├── src
└── mcstructure
│ ├── py.typed
│ └── __init__.py
├── logo.png
├── docs
├── api.md
├── changelog.md
├── installation.md
├── contributing.md
├── index.md
├── Makefile
├── make.bat
├── conf.py
└── quickstart.md
├── samples
├── barrel.mcstructure
├── cmdblock.mcstructure
├── dirt_house.mcstructure
├── scarecrow.mcstructure
├── large_nether.mcstructure
├── waterlogged.mcstructure
├── caged_villager.mcstructure
└── armor_stand_steve_head.mcstructure
├── examples
├── out
│ ├── area.mcstructure
│ ├── diagonal.mcstructure
│ ├── simple.mcstructure
│ ├── custom_entity.mcstructure
│ ├── large_nether.mcstructure
│ └── waterlogged.mcstructure
├── copystruct.py
├── simple.py
├── waterlogged.py
├── diagonal.py
├── read_and_display.py
├── area.py
└── custom_entity.py
├── .github
├── ISSUE_TEMPLATE
│ ├── custom.md
│ ├── feature_request.md
│ └── bug_report.md
└── workflows
│ └── black.yaml
├── .readthedocs.yaml
├── tests
├── test_block.py
└── test_structure.py
├── LICENSE.txt
├── pyproject.toml
├── scripts
└── packer.py
├── README_CN.md
├── README_DE.md
├── README.md
├── .gitignore
└── poetry.lock
/src/mcstructure/py.typed:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phoenixr-codes/mcstructure/HEAD/logo.png
--------------------------------------------------------------------------------
/docs/api.md:
--------------------------------------------------------------------------------
1 | # API Refernce
2 |
3 | ```{eval-rst}
4 | .. automodule:: mcstructure
5 | ```
6 |
--------------------------------------------------------------------------------
/docs/changelog.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | The changelog will be documented as soon as the stable version is released.
4 |
--------------------------------------------------------------------------------
/samples/barrel.mcstructure:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phoenixr-codes/mcstructure/HEAD/samples/barrel.mcstructure
--------------------------------------------------------------------------------
/samples/cmdblock.mcstructure:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phoenixr-codes/mcstructure/HEAD/samples/cmdblock.mcstructure
--------------------------------------------------------------------------------
/examples/out/area.mcstructure:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phoenixr-codes/mcstructure/HEAD/examples/out/area.mcstructure
--------------------------------------------------------------------------------
/samples/dirt_house.mcstructure:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phoenixr-codes/mcstructure/HEAD/samples/dirt_house.mcstructure
--------------------------------------------------------------------------------
/samples/scarecrow.mcstructure:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phoenixr-codes/mcstructure/HEAD/samples/scarecrow.mcstructure
--------------------------------------------------------------------------------
/examples/out/diagonal.mcstructure:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phoenixr-codes/mcstructure/HEAD/examples/out/diagonal.mcstructure
--------------------------------------------------------------------------------
/examples/out/simple.mcstructure:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phoenixr-codes/mcstructure/HEAD/examples/out/simple.mcstructure
--------------------------------------------------------------------------------
/samples/large_nether.mcstructure:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phoenixr-codes/mcstructure/HEAD/samples/large_nether.mcstructure
--------------------------------------------------------------------------------
/samples/waterlogged.mcstructure:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phoenixr-codes/mcstructure/HEAD/samples/waterlogged.mcstructure
--------------------------------------------------------------------------------
/samples/caged_villager.mcstructure:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phoenixr-codes/mcstructure/HEAD/samples/caged_villager.mcstructure
--------------------------------------------------------------------------------
/examples/out/custom_entity.mcstructure:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phoenixr-codes/mcstructure/HEAD/examples/out/custom_entity.mcstructure
--------------------------------------------------------------------------------
/examples/out/large_nether.mcstructure:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phoenixr-codes/mcstructure/HEAD/examples/out/large_nether.mcstructure
--------------------------------------------------------------------------------
/examples/out/waterlogged.mcstructure:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phoenixr-codes/mcstructure/HEAD/examples/out/waterlogged.mcstructure
--------------------------------------------------------------------------------
/samples/armor_stand_steve_head.mcstructure:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phoenixr-codes/mcstructure/HEAD/samples/armor_stand_steve_head.mcstructure
--------------------------------------------------------------------------------
/docs/installation.md:
--------------------------------------------------------------------------------
1 | # Installation
2 |
3 | *mcstructure* can be installed/updated with *pip*:
4 |
5 | ```bash
6 | pip install -U mcstructure
7 | ```
8 |
9 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/custom.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Custom issue template
3 | about: Describe this issue template's purpose here.
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.github/workflows/black.yaml:
--------------------------------------------------------------------------------
1 | name: Lint
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | lint:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v3
10 | - uses: psf/black@stable
11 |
--------------------------------------------------------------------------------
/docs/contributing.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Contributions are welcomed. Feel free to
4 | [submit an issue](https://github.com/phoenixr-codes/mcstructure/issues/new/choose)
5 | or help with [already existing issues](https://github.com/phoenixr-codes/mcstructure/issues).
6 |
--------------------------------------------------------------------------------
/.readthedocs.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | version: 2
3 |
4 | build:
5 | os: ubuntu-20.04
6 | tools:
7 | python: "3.13"
8 |
9 | python:
10 | install:
11 | - method: pip
12 | path: .
13 | extra_requirements:
14 | - docs
15 |
16 | sphinx:
17 | configuration: docs/conf.py
18 |
--------------------------------------------------------------------------------
/examples/copystruct.py:
--------------------------------------------------------------------------------
1 | from mcstructure import Structure
2 | from pathlib import Path
3 |
4 | here = Path(__file__).parent
5 |
6 | with here.joinpath("../samples/large_nether.mcstructure").open("rb") as f:
7 | struct = Structure.load(f)
8 |
9 | with here.joinpath("out/large_nether.mcstructure").open("wb") as f:
10 | struct.dump(f)
11 |
--------------------------------------------------------------------------------
/examples/simple.py:
--------------------------------------------------------------------------------
1 | from mcstructure import Block, Structure
2 | from pathlib import Path
3 |
4 | here = Path(__file__).parent
5 |
6 | struct = Structure(
7 | (2, 2, 2), # Size of the Structure 声明结构大小,注意这是大小,其坐标从0开始
8 | Block("minecraft:air"), # pre-fill blocks 预填充方块
9 | )
10 |
11 | # fill blocks 填充方块
12 | struct.set_block((1, 1, 1), Block("minecraft:iron_block"))
13 |
14 | # write into file 写入文件
15 | with here.joinpath("out/simple.mcstructure").open("wb") as f:
16 | struct.dump(f)
17 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | # mcstructure
2 |
3 | ```{include} ../README.md
4 | :start-after:
5 | :end-before:
6 | ```
7 |
8 | ```{toctree}
9 | ---
10 | caption: Introduction
11 | maxdepth: 2
12 | ---
13 | installation
14 | quickstart
15 | ```
16 |
17 | ```{toctree}
18 | ---
19 | caption: Content
20 | maxdepth: 2
21 | ---
22 | api
23 | ```
24 |
25 | ```{toctree}
26 | ---
27 | caption: Development
28 | maxdepth: 2
29 | ---
30 | contributing
31 | changelog
32 | ```
33 |
34 |
--------------------------------------------------------------------------------
/examples/waterlogged.py:
--------------------------------------------------------------------------------
1 | from mcstructure import Block, Structure
2 | import nbtx
3 | from pathlib import Path
4 |
5 | here = Path(__file__).parent
6 |
7 | struct = Structure((2, 2, 2), Block("minecraft:air"))
8 |
9 | struct.set_block(
10 | (0, 0, 0),
11 | Block(
12 | "minecraft:birch_stairs",
13 | upside_down_bit=False,
14 | weirdo_direction=2,
15 | waterlogged=True
16 | )
17 | )
18 |
19 | with here.joinpath("out/waterlogged.mcstructure").open("wb") as f:
20 | struct.dump(f)
21 |
--------------------------------------------------------------------------------
/examples/diagonal.py:
--------------------------------------------------------------------------------
1 | from mcstructure import Block, Structure
2 | from pathlib import Path
3 |
4 | here = Path(__file__).parent
5 |
6 | BLOCK = Block("minecraft:grass")
7 |
8 | struct = Structure((10, 10, 10), Block("minecraft:air"))
9 | (
10 | struct.set_block((0, 0, 0), BLOCK)
11 | .set_block((1, 1, 1), BLOCK)
12 | .set_block((2, 2, 2), BLOCK)
13 | .set_block((3, 3, 3), BLOCK)
14 | .set_block((4, 4, 4), BLOCK)
15 | .set_block((5, 5, 5), BLOCK)
16 | )
17 |
18 | with here.joinpath("out/diagonal.mcstructure").open("wb") as f:
19 | struct.dump(f)
20 |
--------------------------------------------------------------------------------
/examples/read_and_display.py:
--------------------------------------------------------------------------------
1 | from mcstructure import Structure
2 | from pathlib import Path
3 |
4 | here = Path(__file__).parent
5 |
6 | with here.joinpath("../samples/dirt_house.mcstructure").open("rb") as f:
7 | struct = Structure.load(f)
8 | print("Dirt House")
9 | print(struct)
10 |
11 | with here.joinpath("../samples/waterlogged.mcstructure").open("rb") as f:
12 | struct = Structure.load(f)
13 | print("Waterlogged Stairs")
14 | print(struct.palette)
15 |
16 | with here.joinpath("../samples/cmdblock.mcstructure").open("rb") as f:
17 | struct = Structure.load(f)
18 | print("Command Block")
19 | print(struct.palette)
20 |
--------------------------------------------------------------------------------
/examples/area.py:
--------------------------------------------------------------------------------
1 | from mcstructure import Block, Structure
2 | from pathlib import Path
3 |
4 | here = Path(__file__).parent
5 |
6 | struct = Structure(
7 | (6, 6, 6), # Size of the Structure 声明结构大小,注意这是大小,其坐标从0开始
8 | Block("minecraft:air"), # pre-fill blocks 预填充方块
9 | )
10 |
11 | # fill blocks 填充方块
12 | struct.set_blocks((1, 1, 1), (4, 1, 4), Block("minecraft:iron_block"))
13 |
14 | # display stuffs in it 显示一些东西
15 | print(struct.get_structure())
16 | print(struct._get_str_array(with_namespace=False, with_states=True))
17 |
18 | # write into file 写入文件
19 | with here.joinpath("out/area.mcstructure").open("wb") as f:
20 | struct.dump(f)
21 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/tests/test_block.py:
--------------------------------------------------------------------------------
1 | from mcstructure import Block
2 |
3 |
4 | def test_stringify() -> None:
5 | b = Block("minecraft:wool", color="red")
6 | assert b.stringify() == 'minecraft:wool ["color"="red"]'
7 | assert b.stringify(with_namespace=False) == 'wool ["color"="red"]'
8 | assert b.stringify(with_states=False) == "minecraft:wool"
9 | assert b.stringify(with_namespace=False, with_states=False) == "wool"
10 |
11 | b = Block("minecraft:dispenser", triggered_bit=True)
12 | assert (
13 | b.stringify(with_namespace=False, with_states=True)
14 | == 'dispenser ["triggered_bit"=true]'
15 | )
16 |
17 | b = Block("minecraft:jigsaw", rotation=12)
18 | assert (
19 | b.stringify(with_namespace=False, with_states=True) == 'jigsaw ["rotation"=12]'
20 | )
21 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=_build
12 |
13 | %SPHINXBUILD% >NUL 2>NUL
14 | if errorlevel 9009 (
15 | echo.
16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
17 | echo.installed, then set the SPHINXBUILD environment variable to point
18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
19 | echo.may add the Sphinx directory to PATH.
20 | echo.
21 | echo.If you don't have Sphinx installed, grab it from
22 | echo.https://www.sphinx-doc.org/
23 | exit /b 1
24 | )
25 |
26 | if "%1" == "" goto help
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Jonas da Silva
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["setuptools", "setuptools-scm"]
3 | build-backend = "setuptools.build_meta"
4 |
5 | [project]
6 | name = "mcstructure"
7 | version = "0.0.1b6"
8 | description = "Read and write Minecraft .mcstructure files."
9 | dependencies = [
10 | "numpy==2.3.0",
11 | "nbtx==0.4.1",
12 | ]
13 | requires-python = ">=3.13"
14 | readme = "README.md"
15 | license = {text = "MIT"}
16 | classifiers = [
17 | "Development Status :: 4 - Beta",
18 | "Intended Audience :: Developers",
19 | "Intended Audience :: Education",
20 | "License :: OSI Approved :: MIT License",
21 | "Natural Language :: English",
22 | "Programming Language :: Python :: 3",
23 | "Topic :: Games/Entertainment",
24 | "Typing :: Typed",
25 | ]
26 | keywords = [
27 | "mcstructure",
28 | "Minecraft",
29 | ]
30 |
31 | [project.optional-dependencies]
32 | dev = [
33 | "pytest>=8",
34 | "mypy==1.16.1",
35 | "black==25.1.0",
36 | ]
37 | docs = [
38 | "furo",
39 | "myst-parser>=2",
40 | "Sphinx>=7",
41 | "sphinx-copybutton>=0",
42 | ]
43 |
44 | [tool.mypy]
45 | strict = true
46 |
47 | [project.urls]
48 | "Documentation" = "https://mcstructure.readthedocs.io/en/latest/"
49 | "Source Code" = "https://github.com/phoenixr-codes/mcstructure/"
50 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | #:==========================================
2 | # Sphinx Documentation Builder Configuration
3 | #:==========================================
4 |
5 |
6 | #####################
7 | # Project Information
8 |
9 | project = "mcstructure"
10 | copyright = "2023, Jonas da Silva"
11 | author = "Jonas da Silva"
12 | release = "0.0.1b5"
13 |
14 |
15 | ###############
16 | # Configuration
17 |
18 | extensions = [
19 | "sphinx.ext.autodoc",
20 | "sphinx.ext.intersphinx",
21 | "sphinx.ext.napoleon",
22 | "myst_parser",
23 | "sphinx_copybutton",
24 | ]
25 |
26 | ###########################
27 | # Intersphinx Configuration
28 |
29 | intersphinx_mapping = {"python": ("https://docs.python.org/3", None)}
30 |
31 | #######################
32 | # Autodoc Configuration
33 |
34 | autodoc_default_options = dict.fromkeys(
35 | """
36 | members
37 | inherited-members
38 | undoc-members
39 | """.split(),
40 | True,
41 | )
42 | autodoc_member_order = "bysource"
43 | autodoc_typehints = "both"
44 | autoclass_content = "both"
45 |
46 |
47 | ############
48 | # Find Files
49 |
50 | templates_path = ["_templates"]
51 | exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
52 |
53 |
54 | ###########################
55 | # HTML Output Configuration
56 |
57 | html_theme = "furo"
58 | html_logo = "../logo.png"
59 | html_favicon = "../logo.png"
60 | html_static_path = ["_static"]
61 |
--------------------------------------------------------------------------------
/docs/quickstart.md:
--------------------------------------------------------------------------------
1 | # Quickstart
2 |
3 | ## Loading/Initializing a Structure
4 |
5 | You can load a pre-existing structure by using the {py:meth}`mcstructure.Structure.load` method.
6 |
7 | ```python
8 | from mcstructure import Structure
9 |
10 | with open("house.mcstructure", "rb") as f:
11 | struct = Structure.load(f)
12 | ```
13 |
14 | Alternatively, create a new empty structure:
15 |
16 | ```python
17 | from mcstructure import Block, Structure
18 |
19 | struct = Structure(
20 | (12, 20, 5), # size of the structure
21 | Block("minecraft:wool", color="red") # fill the structure with red wool
22 | )
23 | ```
24 |
25 |
26 | ## Inspecting a Structure
27 |
28 | ```python
29 | struct.size # The size of the structure
30 | struct.get_block(1, 1, 1) # Get the block at (1, 1, 1)
31 | struct.get_structure() # Get the numpy array representing the structure
32 | ```
33 |
34 |
35 | ## Viewing a Structure
36 |
37 | You can simply print the structure object:
38 |
39 | ```python
40 | print(struct)
41 | ```
42 |
43 |
44 | ## Modifying a Structure
45 |
46 | Simple modifications such as placing blocks:
47 |
48 | ```python
49 | from mcstructure import Block
50 |
51 | struct.set_block((1, 1, 1), Block("minecraft:wool", color="red")) # Places a red wool block at (1, 1, 1)
52 | struct.set_blocks((1, 1, 1), (5, 5, 5), Block("minecraft:wool", color="red")) # Places red wool blocks from (1, 1, 1) to (5, 5, 5)
53 | ```
54 |
55 | Advanced modifications can be achieved with [numpy](https://numpy.org/doc/stable/index.html).
56 | A structure object consists of an array of integers representing IDs. Each ID is associated
57 | with a {py:class}`mcstructure.Block` in a list.
58 |
59 | ```python
60 | import numpy as np
61 |
62 | np.rot90(struct.structure)
63 | struct.structure = np.transpose(struct.structure)
64 | ```
65 |
66 |
67 | ## Saving a Structure
68 |
69 | ```python
70 | with open("mansion.mcstructure", "wb") as f:
71 | struct.dump(f)
72 | ```
73 |
--------------------------------------------------------------------------------
/tests/test_structure.py:
--------------------------------------------------------------------------------
1 | from mcstructure import has_suitable_size, STRUCTURE_MAX_SIZE, Structure, Block
2 | import pytest
3 |
4 |
5 | def test_oversized() -> None:
6 | assert has_suitable_size(STRUCTURE_MAX_SIZE)
7 | assert not has_suitable_size((65, 0, 0))
8 |
9 |
10 | def test_resize_larger() -> None:
11 | dirt = Block("minecraft:dirt")
12 | air = Block("minecraft:air")
13 | struct = Structure((2, 2, 2), fill=dirt)
14 | struct.resize((4, 4, 4), air)
15 | assert struct.get_block((3, 3, 3)) == air
16 | assert struct.get_block((0, 0, 0)) == dirt
17 | assert struct.get_block((1, 1, 1)) == dirt
18 | assert struct.get_block((2, 2, 2)) == air
19 |
20 |
21 | def test_resize_smaller() -> None:
22 | dirt = Block("minecraft:dirt")
23 | struct = Structure((4, 4, 4), fill=dirt)
24 | struct.resize((2, 2, 2))
25 | with pytest.raises(IndexError):
26 | assert struct.get_block((3, 3, 3)) is None
27 | with pytest.raises(IndexError):
28 | assert struct.get_block((2, 2, 2)) is None
29 | assert struct.get_block((1, 1, 1)) == dirt
30 | assert struct.get_block((0, 0, 0)) == dirt
31 |
32 |
33 | def test_combine() -> None:
34 | dirt = Block("minecraft:dirt")
35 | air = Block("minecraft:air")
36 | void = Block("minecraft:structure_void")
37 | struct_a = Structure((1, 2, 2), fill=air)
38 | struct_b = Structure((1, 2, 2), fill=dirt)
39 | struct_c = struct_a.combine(struct_b, (0, 1, 1))
40 |
41 | # Check the combined structure
42 | assert struct_c.get_block((0, 0, 0)) == air
43 | assert struct_c.get_block((0, 0, 1)) == air
44 | assert struct_c.get_block((0, 0, 2)) == void
45 | assert struct_c.get_block((0, 1, 0)) == air
46 | assert struct_c.get_block((0, 1, 1)) == dirt
47 | assert struct_c.get_block((0, 1, 2)) == dirt
48 | assert struct_c.get_block((0, 2, 0)) == void
49 | assert struct_c.get_block((0, 2, 1)) == dirt
50 | assert struct_c.get_block((0, 2, 2)) == dirt
51 |
--------------------------------------------------------------------------------
/scripts/packer.py:
--------------------------------------------------------------------------------
1 | """
2 | Packs mcstructure files into a usable MCBE add-on.
3 | """
4 |
5 | from datetime import datetime
6 | import json
7 | from pathlib import Path
8 | from uuid import uuid4
9 | from tempfile import TemporaryDirectory
10 | import zipfile
11 |
12 | here = Path(__file__).parent
13 | root = here.parent
14 | logo = root / "logo.png"
15 | structures = root / "examples/out"
16 |
17 |
18 | def main() -> None:
19 | timestamp = datetime.now().strftime("%d.%m %H:%M")
20 | name = f"mcstructure pack - {timestamp}"
21 | manifest = {
22 | "format_version": 2,
23 | "header": {
24 | "name": name,
25 | "description": "github.com/phoenixr-codes/mcstructure",
26 | "uuid": str(uuid4()),
27 | "version": [1, 0, 0],
28 | "min_engine_version": [1, 21, 0],
29 | },
30 | "modules": [{"type": "data", "uuid": str(uuid4()), "version": [1, 0, 0]}],
31 | "metadata": {"product_type": "addon"},
32 | }
33 | with TemporaryDirectory() as temp_dir_str:
34 | temp_dir = Path(temp_dir_str)
35 | with (temp_dir / "manifest.json").open("w") as f:
36 | json.dump(manifest, f)
37 | with (temp_dir / "pack_icon.png").open("wb") as f:
38 | f.write(logo.read_bytes())
39 | structures_dir = temp_dir / "structures"
40 | structures_dir.mkdir()
41 | for structure_path in structures.glob("*.mcstructure"):
42 | destination = structures_dir / structure_path.name
43 | destination.write_bytes(structure_path.read_bytes())
44 | print(f"adding {structure_path}")
45 | destination = (root / name.replace(".", "_")).with_suffix(".mcpack")
46 | with zipfile.ZipFile(destination, "w") as archive:
47 | for source_path in temp_dir.glob("**/*"):
48 | print(f"archiving {source_path}")
49 | archive.write(source_path, arcname=source_path.relative_to(temp_dir))
50 | print(f"bundled add-on at {destination}")
51 |
52 |
53 | if __name__ == "__main__":
54 | main()
55 |
--------------------------------------------------------------------------------
/README_CN.md:
--------------------------------------------------------------------------------
1 |
2 |
7 |
mcstructure
8 |
9 | 《我的世界》.mcstructure 文件的读写操作库
10 |
11 |
12 |
13 |
14 | 🌍 此介绍文件亦可见于以下语种:
15 |
16 | * [🇬🇧 英文](./README.md)
17 | * [🇩🇪 德文](./README_DE.md) *(未及时更新)*
18 |
19 |
21 |
22 |
23 | [](https://github.com/psf/black)
24 | [](https://mcstructure.readthedocs.io/en/latest/?badge=latest)
25 | [](https://pypi.org/project/mcstructure)
26 |
27 | _在整个项目中(且更官方地是在“大一统更新”("Better Together Update")之后,名词《我的世界》("Minecraft")所指代的均为基岩版("Bedrock Edition")。_
28 |
29 | _此库中的所有特性也是仅仅针对基岩版的。_
30 |
31 | > [!WARNING]
32 | > **请注意**
33 | > 此项目目前仍属于 **BETA** 版本,因此部分特性可能并未启用或在未经示警的情况下频繁更改。
34 |
35 |
36 |
37 | 此库可以让您以代码实现对 *《我的世界》* 结构文件的创建与编辑。
38 | 您能够凭此而将您自己的结构存储为 `.mcstructure` 文件,因而可以使之用于行为包中,或者发展出更厉害的用途。
39 |
40 | 当然,通过此库您也可以通过此库来读取(read)这些在游戏中通过*结构方块*保存的结构文件,从而获取(identify)其中存储之方块与实体之类。
41 |
42 |
43 |
44 | 下载安装
45 | ------------
46 |
47 | ```console
48 | pip install mcstructure
49 | ```
50 |
51 |
52 | 基本用法
53 | -----------
54 |
55 | 1. 写入结构文件
56 |
57 | ```python
58 | # 导入库
59 | from mcstructure import Block, Structure
60 |
61 | # 实例化对象 Structure
62 | struct = Structure(
63 | (7, 7, 7), # 声明结构大小
64 | Block("minecraft:wool", color = "red") # 预填充方块
65 | )
66 |
67 | # 设定方块
68 | (struct
69 | .set_block((1, 1, 1), Block("minecraft:grass"))
70 | .set_block((2, 2, 2), Block("minecraft:grass"))
71 | .set_block((3, 3, 3), Block("minecraft:grass"))
72 | .set_block((4, 4, 4), Block("minecraft:grass"))
73 | .set_block((5, 5, 5), Block("minecraft:grass"))
74 | .set_block((6, 6, 6), Block("minecraft:grass"))
75 | )
76 |
77 | # 写入文件
78 | with open("house.mcstructure", "wb") as f:
79 | struct.dump(f)
80 |
81 | ```
82 |
83 | 2. 读取结构文件
84 |
85 | ```python
86 | with open("house.mcstructure", "rb") as f:
87 | struct = Structure.load(f)
88 |
89 | ```
90 |
91 | 妙用链接
92 | ------------
93 |
94 | * 📖 [此项目之文档](https://mcstructure.readthedocs.io/en/latest/)
95 | * 📁 [此项目之源码](https://github.com/phoenixr-codes/mcstructure)
96 | * 🐍 [PyPI](https://pypi.org/project/mcstructure/)
97 |
98 | ### 其他资源
99 |
100 | * 👋 [结构方块的简介](https://learn.microsoft.com/en-us/minecraft/creator/documents/introductiontostructureblocks)
101 | * 📖 [基岩版维基](https://wiki.bedrock.dev/nbt/mcstructure.html#file-format)
102 | _译注:文件结构文档已经被我翻译了,详见[我的译本](https://gitee.com/TriM-Organization/mcstructure/blob/main/docs/mcstructure%E6%96%87%E4%BB%B6%E7%BB%93%E6%9E%84.md)_
103 | --------------------------------------------
104 |
105 | NOT AN OFFICIAL MINECRAFT PRODUCT.
106 | NOT APPROVED BY OR ASSOCIATED WITH MOJANG.
107 |
108 | 此项目并非一个官方 《我的世界》(*Minecraft*)项目
109 |
110 | 此项目不隶属或关联于 Mojang Studios
111 |
--------------------------------------------------------------------------------
/README_DE.md:
--------------------------------------------------------------------------------
1 |
2 |
7 |
mcstructure
8 |
9 | Lesen und Schreiben von Minecraft .mcstructure-Dateien.
10 |
11 |
12 |
13 | 🌍 Diese README-Datei ist auch in den folgenden
14 | Sprachen verfügbar:
15 |
16 | * [🇨🇳 Chinesisch](./README_CN.md)
17 | * [🇬🇧 Englisch](./README.md)
18 |
19 |
20 |
21 | [](https://github.com/psf/black)
22 | [](https://mcstructure.readthedocs.io/en/latest/?badge=latest)
23 | [](https://pypi.org/project/mcstructure)
24 |
25 | _Im gesamten Projekt (und offiziell seit dem
26 | "Better Together Update") ist mit "Minecraft"
27 | die Version gemeint, welche auch als "Bedrock
28 | Edition" bekannt ist._
29 |
30 | _Features dieser Bibliothek sind nur in der
31 | oben genannten Edition von Minecraft nützlich._
32 |
33 | > [!WARNING]
34 | > Dieses Projekt ist momentan in der BETA Version.
35 | > Die meisten Features sind somit instabil.
36 |
37 | Diese Bibliothek ermöglicht es innerhalb eines
38 | Programmes Minecraft Strukturen zu editieren.
39 | Diese können dann als ``.mcstructure``-Datei
40 | gespeichert werden und beispielsweise in einem
41 | Verhaltenspaket genutzt werden.
42 |
43 | Es ist auch möglich, Blöcke und Entitäten zu
44 | identifizieren, welche mit einem Konstruktionsblock
45 | innerhalb des Spiels gespeichert wurden.
46 |
47 |
48 | Installation
49 | ------------
50 |
51 | ```console
52 | pip install mcstructure
53 | ```
54 |
55 |
56 | Demonstration
57 | -------------
58 |
59 | ```python
60 | from mcstructure import Block, Structure
61 |
62 | struct = Structure(
63 | (7, 7, 7),
64 | Block("minecraft:wool", color = "red")
65 | )
66 |
67 | (struct
68 | .set_block((1, 1, 1), Block("minecraft:grass"))
69 | .set_block((2, 2, 2), Block("minecraft:grass"))
70 | .set_block((3, 3, 3), Block("minecraft:grass"))
71 | .set_block((4, 4, 4), Block("minecraft:grass"))
72 | .set_block((5, 5, 5), Block("minecraft:grass"))
73 | .set_block((6, 6, 6), Block("minecraft:grass"))
74 | )
75 |
76 | with open("house.mcstructure", "wb") as f:
77 | struct.dump(f)
78 | ```
79 |
80 | ```python
81 | with open("house.mcstructure", "rb") as f:
82 | struct = Structure.load(f)
83 | ```
84 |
85 |
86 | Nützliche Links
87 | ---------------
88 |
89 | * [📖 Dokumentation](https://mcstructure.readthedocs.io/en/latest/)
90 | * [📁 Quellcode](https://github.com/phoenixr-codes/mcstructure)
91 | * [🐍 PyPI](https://pypi.org/project/mcstructure/)
92 |
93 | ### Externe Resourcen
94 |
95 | * [👋 Einführung zu Konstruktionsblöcken](https://learn.microsoft.com/en-us/minecraft/creator/documents/introductiontostructureblocks)
96 | * [📖 Bedrock Wiki](https://wiki.bedrock.dev/nbt/mcstructure.html#file-format)
97 |
98 |
99 | --------------------------------------------
100 |
101 | NOT AN OFFICIAL MINECRAFT PRODUCT.
102 | NOT APPROVED BY OR ASSOCIATED WITH MOJANG.
103 |
104 | KEIN OFFIZIELLES MINECRAFT PRODUKT.
105 | NICHT VON MOJANG GENEHMIGT ODER MIT MOJANG
106 | ASSOZIIERT.
107 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
7 |
mcstructure
8 |
9 | Read and write Minecraft .mcstructure files.
10 |
11 |
12 |
13 | 🌍 This README is also available in the following
14 | languages:
15 |
16 | * 🇨🇳 [Chinese](./README_CN.md)
17 | * 🇩🇪 [German](./README_DE.md)
18 |
19 |
20 |
22 |
23 |
24 | [](https://github.com/psf/black)
25 | [](https://mcstructure.readthedocs.io/en/latest/?badge=latest)
26 | [](https://pypi.org/project/mcstructure)
27 |
28 | _In the entire project ([and officially since
29 | the "Better Together Update"](https://www.minecraft.net/de-de/article/all-news-e3)) the term
30 | "Minecraft" refers to the edition of Minecraft
31 | that is also known as the "Bedrock Edition"._
32 |
33 | _Features that this library provides are only
34 | useful for the above named edition of Minecraft._
35 |
36 | > [!WARNING]
37 | > This project is currently in the **BETA** version. Some
38 | > features may not work as expected and might change without backwards compability or deprecation warnings.
39 |
40 |
41 |
42 | This library lets you programmatically create
43 | and edit Minecraft structures. You are able to
44 | save these as ``.mcstructure`` files and for
45 | example use them in behavior packs.
46 |
47 | You may as well read them to identify blocks and
48 | and entities that were saved with a Structure
49 | Block in-game.
50 |
51 |
52 |
53 | Installation
54 | ------------
55 |
56 | ```console
57 | pip install mcstructure
58 | ```
59 |
60 |
61 | Basic Usage
62 | -----------
63 |
64 | ```python
65 | from mcstructure import Block, Structure
66 |
67 | struct = Structure(
68 | (7, 7, 7),
69 | Block("minecraft:wool", color = "red")
70 | )
71 |
72 | (struct
73 | .set_block((1, 1, 1), Block("minecraft:grass"))
74 | .set_block((2, 2, 2), Block("minecraft:grass"))
75 | .set_block((3, 3, 3), Block("minecraft:grass"))
76 | .set_block((4, 4, 4), Block("minecraft:grass"))
77 | .set_block((5, 5, 5), Block("minecraft:grass"))
78 | .set_block((6, 6, 6), Block("minecraft:grass"))
79 | )
80 |
81 | with open("house.mcstructure", "wb") as f:
82 | struct.dump(f)
83 | ```
84 |
85 | ```python
86 | with open("house.mcstructure", "rb") as f:
87 | struct = Structure.load(f)
88 | ```
89 |
90 |
91 | References
92 | ----------
93 |
94 | * 📖 [Documentation](https://mcstructure.readthedocs.io/en/latest/)
95 | * 📁 [Source Code](https://github.com/phoenixr-codes/mcstructure)
96 | * 🐍 [PyPI](https://pypi.org/project/mcstructure/)
97 |
98 | ### External Resources
99 |
100 | * 👋 [Introduction to Structure Blocks](https://learn.microsoft.com/en-us/minecraft/creator/documents/introductiontostructureblocks)
101 | * 📖 [Bedrock Wiki](https://wiki.bedrock.dev/nbt/mcstructure.html#file-format)
102 |
103 |
104 | --------------------------------------------
105 |
106 | NOT AN OFFICIAL MINECRAFT PRODUCT.
107 | NOT APPROVED BY OR ASSOCIATED WITH MOJANG.
108 |
--------------------------------------------------------------------------------
/examples/custom_entity.py:
--------------------------------------------------------------------------------
1 | from mcstructure import Block, Structure
2 | import nbtx
3 | from pathlib import Path
4 |
5 | here = Path(__file__).parent
6 |
7 | struct = Structure((2, 2, 2), Block("minecraft:air"))
8 |
9 | struct.add_entity(
10 | nbtx.TagCompound(
11 | "",
12 | [
13 | nbtx.TagList(
14 | "Armor",
15 | child_id=nbtx.TagCompound.id(),
16 | value=[
17 | # head slot
18 | nbtx.TagCompound(
19 | "",
20 | [
21 | nbtx.TagCompound("Block", [
22 | nbtx.TagString("name", "minecraft:player_head"),
23 | nbtx.TagCompound("states", [
24 | nbtx.TagInt("facing_direction", 0),
25 | ]),
26 | nbtx.TagInt("version", 18168865),
27 | ]),
28 | nbtx.TagByte("Count", 1),
29 | nbtx.TagShort("Damage", 0),
30 | nbtx.TagString("Name", "minecraft:player_head"),
31 | nbtx.TagByte("WasPickedUp", 0),
32 | ]
33 | ),
34 |
35 | # chest slot
36 | nbtx.TagCompound(
37 | "",
38 | [
39 | nbtx.TagByte("Count", 0),
40 | nbtx.TagShort("Damage", 0),
41 | nbtx.TagString("Name", ""),
42 | nbtx.TagByte("WasPickedUp", 0),
43 | ]
44 | ),
45 |
46 | # legs slot
47 | nbtx.TagCompound(
48 | "",
49 | [
50 | nbtx.TagByte("Count", 0),
51 | nbtx.TagShort("Damage", 0),
52 | nbtx.TagString("Name", ""),
53 | nbtx.TagByte("WasPickedUp", 0),
54 | ]
55 | ),
56 |
57 | # feet slot
58 | nbtx.TagCompound(
59 | "",
60 | [
61 | nbtx.TagByte("Count", 0),
62 | nbtx.TagShort("Damage", 0),
63 | nbtx.TagString("Name", ""),
64 | nbtx.TagByte("WasPickedUp", 0),
65 | ]
66 | ),
67 | ]
68 | ),
69 | nbtx.TagList(
70 | "Attributes",
71 | child_id=nbtx.TagCompound.id(),
72 | value=[]
73 | ),
74 | nbtx.TagList(
75 | "Pos",
76 | child_id=nbtx.TagFloat.id(),
77 | value=[
78 | nbtx.TagFloat("", 0),
79 | nbtx.TagFloat("", 0),
80 | nbtx.TagFloat("", 0),
81 | ]
82 | ),
83 | nbtx.TagList(
84 | "Rotation",
85 | child_id=nbtx.TagFloat.id(),
86 | value=[
87 | nbtx.TagFloat("", -90.),
88 | nbtx.TagFloat("", 0.),
89 | ]
90 | ),
91 | nbtx.TagList(
92 | "definitions",
93 | child_id=nbtx.TagString.id(),
94 | value=[
95 | nbtx.TagString("", "+minecraft:armor_stand"),
96 | ]
97 | ),
98 | nbtx.TagString("identifier", "minecraft:armor_stand"),
99 | ]
100 | )
101 | )
102 |
103 | with here.joinpath("out/custom_entity.mcstructure").open("wb") as f:
104 | struct.dump(f)
105 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # artifacts
2 | *.mcpack
3 | *.mcaddon
4 |
5 | # editors & IDEs
6 | .vscode
7 |
8 | # Byte-compiled / optimized / DLL files
9 | __pycache__/
10 | *.py[cod]
11 | *$py.class
12 |
13 | # C extensions
14 | *.so
15 |
16 | # Distribution / packaging
17 | .Python
18 | build/
19 | develop-eggs/
20 | dist/
21 | downloads/
22 | eggs/
23 | .eggs/
24 | lib/
25 | lib64/
26 | parts/
27 | sdist/
28 | var/
29 | wheels/
30 | share/python-wheels/
31 | *.egg-info/
32 | .installed.cfg
33 | *.egg
34 | MANIFEST
35 |
36 | # PyInstaller
37 | # Usually these files are written by a python script from a template
38 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
39 | *.manifest
40 | *.spec
41 |
42 | # Installer logs
43 | pip-log.txt
44 | pip-delete-this-directory.txt
45 |
46 | # Unit test / coverage reports
47 | htmlcov/
48 | .tox/
49 | .nox/
50 | .coverage
51 | .coverage.*
52 | .cache
53 | nosetests.xml
54 | coverage.xml
55 | *.cover
56 | *.py,cover
57 | .hypothesis/
58 | .pytest_cache/
59 | cover/
60 |
61 | # Translations
62 | *.mo
63 | *.pot
64 |
65 | # Django stuff:
66 | *.log
67 | local_settings.py
68 | db.sqlite3
69 | db.sqlite3-journal
70 |
71 | # Flask stuff:
72 | instance/
73 | .webassets-cache
74 |
75 | # Scrapy stuff:
76 | .scrapy
77 |
78 | # Sphinx documentation
79 | docs/_build/
80 |
81 | # PyBuilder
82 | .pybuilder/
83 | target/
84 |
85 | # Jupyter Notebook
86 | .ipynb_checkpoints
87 |
88 | # IPython
89 | profile_default/
90 | ipython_config.py
91 |
92 | # pyenv
93 | # For a library or package, you might want to ignore these files since the code is
94 | # intended to run in multiple environments; otherwise, check them in:
95 | # .python-version
96 |
97 | # pipenv
98 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
99 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
100 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
101 | # install all needed dependencies.
102 | #Pipfile.lock
103 |
104 | # poetry
105 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
106 | # This is especially recommended for binary packages to ensure reproducibility, and is more
107 | # commonly ignored for libraries.
108 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
109 | #poetry.lock
110 |
111 | # pdm
112 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113 | #pdm.lock
114 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
115 | # in version control.
116 | # https://pdm.fming.dev/#use-with-ide
117 | .pdm.toml
118 |
119 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
120 | __pypackages__/
121 |
122 | # Celery stuff
123 | celerybeat-schedule
124 | celerybeat.pid
125 |
126 | # SageMath parsed files
127 | *.sage.py
128 |
129 | # Environments
130 | .env
131 | .venv
132 | env/
133 | venv/
134 | ENV/
135 | env.bak/
136 | venv.bak/
137 |
138 | # Spyder project settings
139 | .spyderproject
140 | .spyproject
141 |
142 | # Rope project settings
143 | .ropeproject
144 |
145 | # mkdocs documentation
146 | /site
147 |
148 | # mypy
149 | .mypy_cache/
150 | .dmypy.json
151 | dmypy.json
152 |
153 | # Pyre type checker
154 | .pyre/
155 |
156 | # pytype static type analyzer
157 | .pytype/
158 |
159 | # Cython debug symbols
160 | cython_debug/
161 |
162 | # PyCharm
163 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
164 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
165 | # and can be added to the global gitignore or merged into this file. For a more nuclear
166 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
167 | #.idea/
168 |
--------------------------------------------------------------------------------
/src/mcstructure/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Read and write Minecraft ``.mcstructure`` files.
3 | """
4 |
5 | from __future__ import annotations
6 |
7 | from collections.abc import Sequence
8 | from dataclasses import dataclass, field
9 | from functools import partial
10 | from itertools import repeat
11 | from typing import Any, BinaryIO, Tuple, Self, cast
12 |
13 | import numpy as np
14 | from numpy.typing import NDArray
15 | import nbtx
16 |
17 |
18 | Coordinate = Tuple[int, int, int]
19 | BlockStateValue = str | bool | int
20 |
21 |
22 | COMPABILITY_VERSION: int = 17959425
23 | """
24 | The compability version for a block. The four bytes making up this
25 | integer determine the game version number. For example, ``17879555`` is
26 | ``01 10 D2 03`` in hex meaning ``1.16.210.03``.
27 | """
28 |
29 | STRUCTURE_MAX_SIZE: tuple[int, int, int] = (64, 384, 64)
30 | """
31 | The maximum size a structure can have. This does not apply for
32 | structures created externally and thus is not affect structures
33 | created with this library.
34 | """
35 |
36 |
37 | def _get_deep(obj: Any, *keys: Any, default: Any = None) -> Any:
38 | for key in keys:
39 | try:
40 | obj = obj[key]
41 | except (KeyError, ValueError):
42 | return default
43 | return obj
44 |
45 |
46 | def is_valid_structure_name(name: str, *, with_prefix: bool = False) -> bool:
47 | """
48 | Validates the structure name.
49 |
50 | .. seealso: https://minecraft.fandom.com/wiki/Structure_Block
51 |
52 | Parameters
53 | ----------
54 | name
55 | The name of the structure.
56 |
57 | with_prefix
58 | Whether to take the prefix (e.g. ``mystructure:``)
59 | into account.
60 | """
61 | if with_prefix:
62 | name = name.replace(":", "", 1)
63 |
64 | return all((char.isalnum() and char in "-_") for char in name)
65 |
66 |
67 | def has_suitable_size(size: tuple[int, int, int]) -> bool:
68 | """
69 | Returns ``False`` if ``size`` is greater than the size of
70 | structures that can be created within Minecraft.
71 |
72 | .. seealso:: :const:`STRUCTURE_MAX_SIZE`
73 | """
74 | return all(map(lambda n: n[0] <= n[1], zip(size, STRUCTURE_MAX_SIZE)))
75 |
76 |
77 | @dataclass(init=False, slots=True)
78 | class Block:
79 | """
80 | Attributes
81 | ----------
82 | name
83 | The name of the block.
84 |
85 | states
86 | The states of the block.
87 |
88 | Examples
89 | --------
90 | .. code-block::
91 |
92 | Block("minecraft:beehive", honey_level=4)
93 | Block("minecraft:grass")
94 |
95 | """
96 |
97 | identifier: str
98 | states: dict[str, BlockStateValue]
99 | waterlogged: bool = field(kw_only=True, default=False)
100 | block_entity_data: Sequence[nbtx.Tag[Any, Any]] | None = field(kw_only=True, default=None)
101 | tick_queue_data: nbtx.Tag[Any, Any] | None = field(kw_only=True, default=None)
102 |
103 | def __init__(
104 | self,
105 | identifier: str,
106 | *,
107 | waterlogged: bool = False,
108 | block_entity_data: Sequence[nbtx.Tag[Any, Any]] | None = None,
109 | tick_queue_data: nbtx.Tag[Any, Any] | None = None, # TODO: this can be turned into a Python type and then converted into NBT
110 | **states: BlockStateValue
111 | ):
112 | """
113 | Parameters
114 | ----------
115 | identifier
116 | The identifier of the block (e.g. "minecraft:wool").
117 |
118 | states
119 | The block states such as ``color`` or ``stone_type``.
120 | This varies by every block.
121 |
122 | .. seealso:: https://learn.microsoft.com/en-us/minecraft/creator/reference/content/blockreference/examples/blockstateslist
123 |
124 | waterlogged
125 | Whether this block is waterlogged.
126 |
127 | block_entity_data
128 | Block entity data like the content of a container.
129 |
130 | tick_queue_data
131 |
132 | """
133 | self.identifier = identifier
134 | self.states = states
135 | self.waterlogged = waterlogged
136 | self.block_entity_data = block_entity_data
137 | self.tick_queue_data = tick_queue_data
138 |
139 | def __str__(self) -> str:
140 | return self.stringify()
141 |
142 | def stringify(
143 | self,
144 | *,
145 | with_namespace: bool = True,
146 | with_states: bool = True,
147 | ) -> str:
148 | """Returns a human-readable representation of the block.
149 |
150 | This format matches the one used for commands like `setblock`.
151 |
152 | Parameters
153 | ----------
154 | with_namespace
155 | Whether to include the block's namespace.
156 |
157 | with_states
158 | Whether to include the block's states.
159 | """
160 | result = ""
161 | if with_namespace and (ns := self.namespace) is not None:
162 | result += ns + ":"
163 | result += self.name
164 | if with_states:
165 | result += " ["
166 | for key, value in self.states.items():
167 | result += f'"{key}"='
168 | if isinstance(value, str):
169 | result += f'"{value}"'
170 | elif isinstance(value, bool):
171 | result += str(value).lower()
172 | elif isinstance(value, int):
173 | result += str(value)
174 | else:
175 | raise ValueError("block state value must be str, bool or int")
176 | result += "]"
177 | return result
178 |
179 | @property
180 | def namespace_and_name(self) -> tuple[str | None, str]:
181 | """The namespace and the name of the block.
182 |
183 | Examples
184 | --------
185 | .. code-block:: python
186 |
187 | >>> from mcstructure import Block
188 | >>>
189 | >>> block = Block("minecraft:wool", color="red")
190 | >>> block.namespace_and_name
191 | ("minecraft", "wool")
192 | >>>
193 | >>> block = Block("foobar")
194 | >>> block.namespace_and_name
195 | (None, "foobar")
196 |
197 | """
198 | if ":" in self.identifier:
199 | ns, name = self.identifier.split(":", 1)
200 | return ns, name
201 |
202 | return (None, self.identifier)
203 |
204 | @property
205 | def name(self) -> str:
206 | """The name of the block.
207 |
208 | Examples
209 | --------
210 | .. code-block:: python
211 |
212 | >>> from mcstructure import Block
213 | >>>
214 | >>> block = Block("minecraft:wool", color="red")
215 | >>> block.name
216 | "wool"
217 | >>>
218 | >>> block = Block("foobar")
219 | >>> block.name
220 | "foobar"
221 |
222 | """
223 | return self.namespace_and_name[1]
224 |
225 | @property
226 | def namespace(self) -> str | None:
227 | """The namespace of the block.
228 |
229 | Examples
230 | --------
231 | .. code-block:: python
232 |
233 | >>> from mcstructure import Block
234 | >>>
235 | >>> block = Block("minecraft:wool", color="red")
236 | >>> block.namespace
237 | "minecraft"
238 | >>>
239 | >>> block = Block("foobar")
240 | >>> (block.namespace,)
241 | (None,)
242 |
243 | """
244 | return self.namespace_and_name[0]
245 |
246 | _WATER = Block("minecraft:water", liquid_depth=0)
247 |
248 | class Structure:
249 | """Class representing a Minecraft structure that consists of blocks and entities.
250 |
251 | Attributes
252 | ----------
253 | structure
254 | The numpy array representing the blocks in the structure. Each entry is an ID
255 | associated with a block present in :meth:`palette`.
256 |
257 | entities
258 | A list of entities the structure contains.
259 |
260 | _size
261 | Size of the structure stored internally.
262 |
263 | _palette
264 | Internal list of blocks that are used within the structure. The position of
265 | the block in the list represents its ID. Modification of this list should be
266 | done with caution and if you do so consider modifying :attr:`structure`
267 | appropriately. Instead use methods like :meth:`set_block`.
268 | """
269 |
270 | def __init__(
271 | self,
272 | size: tuple[int, int, int],
273 | fill: Block | None = Block("minecraft:air"),
274 | ) -> None:
275 | """
276 | Parameters
277 | ----------
278 | size
279 | The size of the structure.
280 |
281 | fill
282 | Fill the structure with this block at
283 | creation of a new structure object.
284 |
285 | If this is set to ``None`` the structure
286 | is filled with "Structure Void" blocks.
287 |
288 | ``'minecraft:air'`` is used as default.
289 | """
290 | self.structure: NDArray[np.intc]
291 | self.entities: list[nbtx.Tag[Any, Any]] = []
292 |
293 | self._size = size
294 | self._palette: list[Block] = []
295 |
296 | if fill is None:
297 | self.structure = np.full(size, -1, dtype=np.intc)
298 |
299 | else:
300 | self.structure = np.zeros(size, dtype=np.intc)
301 | self._palette.append(fill)
302 |
303 | @classmethod
304 | def load(cls, file: BinaryIO) -> Self:
305 | """
306 | Loads a structure from a file.
307 |
308 | Examples
309 | --------
310 | .. code-block:: python
311 |
312 | from mcstructure import Structure
313 |
314 | with open("house.mcstructure", "rb") as f:
315 | struct = Structure.load(f)
316 |
317 | Parameters
318 | ----------
319 | file
320 | File object to read.
321 | """
322 | nbt_root = nbtx.load(file, endianness="little")
323 | assert isinstance(nbt_root, nbtx.TagCompound)
324 | nbt_body_data = nbt_root
325 | nbt_body = nbt_root.as_python()
326 |
327 | size: tuple[int, int, int] = tuple(nbt_body["size"])
328 |
329 | struct = cls(size, None)
330 |
331 | struct.structure = np.array(
332 | [x for x in nbt_body["structure"]["block_indices"][0]],
333 | dtype=np.intc,
334 | ).reshape(size)
335 |
336 | struct.entities = nbt_body["structure"]["entities"]
337 |
338 | waterlogged_mask: list[bool] = [value != -1 for value in nbt_body["structure"]["block_indices"][1]]
339 |
340 | nbt_structure = nbt_body_data["structure"]
341 | assert isinstance(nbt_structure, nbtx.TagCompound)
342 | nbt_palette = nbt_structure["palette"]
343 | assert isinstance(nbt_palette, nbtx.TagCompound)
344 | nbt_default_palette = nbt_palette["default"]
345 | assert isinstance(nbt_default_palette, nbtx.TagCompound)
346 | block_position_data = nbt_default_palette["block_position_data"]
347 |
348 | for (index, block) in enumerate(nbt_body["structure"]["palette"]["default"]["block_palette"]):
349 | maybe_block_entity_data = _get_deep(block_position_data, str(index), "block_entity_data")
350 | if maybe_block_entity_data is None:
351 | block_entity_data = None
352 | else:
353 | block_entity_data = maybe_block_entity_data.value
354 |
355 | struct._palette.append(
356 | Block(
357 | block["name"],
358 | **(block["states"]),
359 | waterlogged=waterlogged_mask[index],
360 | block_entity_data=block_entity_data,
361 | tick_queue_data=_get_deep(block_position_data, str(index), "tick_queue_data"),
362 | )
363 | )
364 |
365 | return struct
366 |
367 | @property
368 | def size(self) -> tuple[int, int, int]:
369 | """The size of the structure."""
370 | return self._size
371 |
372 | @property
373 | def palette(self) -> list[Block]:
374 | """A copy of the palette."""
375 | palette = self._palette.copy()
376 | return palette
377 |
378 | def __repr__(self) -> str:
379 | return repr(self._get_str_array())
380 |
381 | def __str__(self) -> str:
382 | return str(self._get_str_array())
383 |
384 | def _get_str_array(
385 | self, *, with_namespace: bool = False, with_states: bool = False
386 | ) -> NDArray[Any]:
387 | """
388 | Returns a numpy array where each entry is a
389 | readable string of the corresponding block.
390 |
391 | Parameters
392 | ----------
393 | with_namespace
394 | Adds the namespace to the string if present.
395 |
396 | with_states
397 | Adds the block states to the string if present.
398 | """
399 | arr = self.get_structure().copy()
400 | vec = np.vectorize(
401 | partial(
402 | Block.stringify, with_namespace=with_namespace, with_states=with_states
403 | )
404 | )
405 | return cast(NDArray[Any], vec(arr))
406 |
407 | def _add_block_to_palette(self, block: Block | None) -> int:
408 | """
409 | Adds a block to the palette.
410 |
411 | Parameters
412 | ----------
413 | block
414 | The block to add. If this is set to ``None``
415 | "Structure Void" will be used.
416 |
417 | Returns
418 | -------
419 | The position of the block in the palette. This is
420 | ``-1`` when ``None`` is used as ``block``.
421 | """
422 | if block is None:
423 | return -1
424 |
425 | if (index := self._block_index(block, ignore_waterlogged=True, ignore_block_entity_data=True, ignore_tick_queue_data=True)) is not None:
426 | return index
427 |
428 | self._palette.append(block)
429 | return len(self._palette) - 1
430 |
431 | def _block_index(self, block: Block, *, ignore_states: bool = False, ignore_waterlogged: bool = False, ignore_block_entity_data: bool = False, ignore_tick_queue_data: bool = False) -> int | None:
432 | for (index, palette_block) in enumerate(self._palette):
433 | if block.namespace_and_name != palette_block.namespace_and_name:
434 | continue
435 | if not ignore_states and block.states != palette_block.states:
436 | continue
437 | if not ignore_waterlogged and block.waterlogged != palette_block.waterlogged:
438 | continue
439 | if not ignore_block_entity_data and block.block_entity_data != palette_block.block_entity_data:
440 | continue
441 | if not ignore_tick_queue_data and block.tick_queue_data != palette_block.tick_queue_data:
442 | continue
443 | return index
444 | return None
445 |
446 | def _water_index(self) -> int:
447 | """
448 | Returns the index of water with liquid depth 0.
449 |
450 | If water is not present in the palette, then water will be added to the
451 | palette.
452 | """
453 | for (index, block) in enumerate(self._palette):
454 | if block == _WATER:
455 | return index
456 | return self._add_block_to_palette(_WATER)
457 |
458 | def get_structure(self) -> NDArray[Any]:
459 | """
460 | Returns the structure as a numpy array filled
461 | with the corresponding block objects.
462 | """
463 | arr = np.full(
464 | self.structure.shape, Block("minecraft:structure_void"), dtype=object
465 | )
466 | for key, block in enumerate(self._palette):
467 | arr[self.structure == key] = block
468 | return arr
469 |
470 | def as_nbt(self) -> nbtx.TagCompound[Any, Any]:
471 | """
472 | Serialize the structure as a NBT data.
473 |
474 | Examples
475 | --------
476 | .. code-block:: python
477 |
478 | from mcstructure import Structure
479 |
480 | struct = Structure((5, 5, 5), None)
481 | nbt = struct.as_nbt()
482 | print(nbt.pretty())
483 | """
484 | return nbtx.TagCompound[Any, Any](
485 | name="",
486 | value=[
487 | nbtx.TagInt(name="format_version", value=1),
488 | nbtx.TagList(
489 | name="size",
490 | child_id=nbtx.TagInt.id(),
491 | value=[
492 | nbtx.TagInt("", self._size[0]),
493 | nbtx.TagInt("", self._size[1]),
494 | nbtx.TagInt("", self._size[2]),
495 | ],
496 | ),
497 | nbtx.TagCompound(
498 | name="structure",
499 | value=[
500 | nbtx.TagList(
501 | name="block_indices",
502 | child_id=nbtx.TagList.id(),
503 | value=[
504 | nbtx.TagList(
505 | name="",
506 | child_id=nbtx.TagInt.id(),
507 | value=[
508 | nbtx.TagInt("", i.item())
509 | for i in self.structure.flatten()
510 | ],
511 | ),
512 | nbtx.TagList(
513 | name="",
514 | child_id=nbtx.TagInt.id(),
515 | value=[
516 | nbtx.TagInt(
517 | "",
518 | self._water_index() if self._palette[i.item()].waterlogged else -1
519 | )
520 | for i in self.structure.flatten()
521 | ],
522 | ),
523 | ],
524 | ),
525 | nbtx.TagList(
526 | name="entities",
527 | child_id=nbtx.TagCompound.id(),
528 | value=self.entities,
529 | ),
530 | nbtx.TagCompound(
531 | name="palette",
532 | value=[
533 | nbtx.TagCompound(
534 | name="default",
535 | value=[
536 | nbtx.TagList(
537 | name="block_palette",
538 | child_id=nbtx.TagCompound.id(),
539 | value=[
540 | nbtx.TagCompound(
541 | name="",
542 | value=[
543 | nbtx.TagString(
544 | name="name",
545 | value=block.identifier,
546 | ),
547 | nbtx.TagCompound(
548 | name="states",
549 | value=[
550 | (
551 | nbtx.TagInt(
552 | state_name,
553 | state_value,
554 | )
555 | if isinstance(
556 | state_value, int
557 | )
558 | else (
559 | nbtx.TagString(
560 | state_name,
561 | state_value,
562 | )
563 | if isinstance(
564 | state_value,
565 | str,
566 | )
567 | else nbtx.TagByte(
568 | state_name,
569 | state_value,
570 | )
571 | )
572 | )
573 | for state_name, state_value in block.states.items()
574 | ],
575 | ),
576 | nbtx.TagInt(
577 | name="version",
578 | value=COMPABILITY_VERSION,
579 | ),
580 | ],
581 | )
582 | for block in self._palette
583 | ],
584 | ),
585 | nbtx.TagCompound(
586 | name="block_position_data", value=[
587 | nbtx.TagCompound(
588 | name=str(index),
589 | value=[
590 | *([nbtx.TagCompound(
591 | name="block_entity_data",
592 | value=block.block_entity_data
593 | )] if block.block_entity_data is not None else []),
594 | *([nbtx.TagList(
595 | name="tick_queue_data",
596 | child_id=nbtx.TagCompound.id(),
597 | value=[] # TODO
598 | )] if block.tick_queue_data is not None else [])
599 | ]
600 | )
601 | for (index, block) in enumerate(self._palette)
602 | if block.block_entity_data is not None or block.tick_queue_data is not None
603 | ]
604 | ),
605 | ],
606 | )
607 | ],
608 | ),
609 | ],
610 | ),
611 | nbtx.TagList(
612 | name="structure_world_origin",
613 | value=[
614 | nbtx.TagInt(name="", value=0),
615 | nbtx.TagInt(name="", value=0),
616 | nbtx.TagInt(name="", value=0),
617 | ],
618 | child_id=nbtx.TagInt.id(),
619 | ),
620 | ],
621 | )
622 |
623 | def dump(self, file: BinaryIO) -> None:
624 | """
625 | Serialize the structure as a NBT file.
626 |
627 | Examples
628 | --------
629 | .. code-block:: python
630 |
631 | from mcstructure import Structure
632 |
633 | struct = Structure((5, 5, 5), None)
634 | with open("house.mcstructure", "wb") as f:
635 | struct.dump(f)
636 |
637 | Parameters
638 | ----------
639 | file
640 | File object to write to.
641 | """
642 | nbt = self.as_nbt()
643 | nbtx.dump(nbt, file, endianness="little")
644 |
645 | def get_block(self, coordinate: Coordinate) -> Block | None:
646 | """
647 | Returns the block in a specific position.
648 |
649 | Parameters
650 | ----------
651 | coordinate
652 | The coordinte of the block.
653 | """
654 | x, y, z = coordinate
655 | return (
656 | self._palette[self.structure[x, y, z]]
657 | if self.structure[x, y, z] >= 0
658 | else Block("minecraft:structure_void")
659 | )
660 |
661 | def add_entity(self, nbt_data: nbtx.Tag[Any, Any]) -> Self:
662 | """
663 | Adds an entity to the structure.
664 |
665 | Parameters
666 | ----------
667 | nbt_data
668 | The NBT data of the entity to add.
669 | The best approach would be to export a structure from the game,
670 | display the NBT data and use that as a reference.
671 | """
672 | self.entities.append(nbt_data)
673 | return self
674 |
675 | def set_block(
676 | self,
677 | coordinate: Coordinate,
678 | block: Block | None,
679 | ) -> Self:
680 | """
681 | Places a block in the structure.
682 |
683 | Parameters
684 | ----------
685 | coordinate
686 | Relative coordinates of the block's position.
687 |
688 | block
689 | The block to place. If this is set to ``None``
690 | "Structure Void" blocks will be used.
691 | """
692 | x, y, z = coordinate
693 |
694 | ident = self._add_block_to_palette(block)
695 |
696 | self.structure[x, y, z] = ident
697 | return self
698 |
699 | def set_blocks(
700 | self,
701 | from_coordinate: Coordinate,
702 | to_coordinate: Coordinate,
703 | block: Block,
704 | ) -> Self:
705 | """
706 | Fills an area in the structure with blocks.
707 |
708 | Notes
709 | -----
710 | Both start and end points are included.
711 |
712 | Parameters
713 | ----------
714 | from_coordinate
715 | Relative coordinates of the start edge.
716 |
717 | to_coordinate
718 | Relative coordinates of the end edge.
719 |
720 | block
721 | The block to place. If this is set to ``None``
722 | "Structure Void" blocks will be used to fill.
723 | """
724 | fx, fy, fz = from_coordinate
725 | tx, ty, tz = to_coordinate
726 |
727 | ident = self._add_block_to_palette(block)
728 | self.structure[fx : tx + 1, fy : ty + 1, fz : tz + 1] = np.array(
729 | [
730 | [
731 | [ident for k in range(abs(fz - tz) + 1)]
732 | for j in range(abs(fy - ty) + 1)
733 | ]
734 | for i in range(abs(fx - tx) + 1)
735 | ],
736 | dtype=np.intc,
737 | ).reshape([abs(i) + 1 for i in (fx - tx, fy - ty, fz - tz)])
738 | return self
739 |
740 | def resize(
741 | self, size: tuple[int, int, int], fill: Block | None = Block("minecraft:air")
742 | ) -> Self:
743 | """
744 | Resizes the structure.
745 |
746 | This function erases blocks that are out of bounds and fill newly
747 | created space with ``fill`` (default is air).
748 |
749 | Parameters
750 | ----------
751 | size
752 | The new size of the structure.
753 |
754 | fill
755 | The block to fill newly created space with. If this is set to
756 | ``None`` (default) then "Structure Void" blocks will be used.
757 | """
758 | ident = self._add_block_to_palette(fill)
759 | self._size = size
760 |
761 | if self.structure.shape == size:
762 | # No need to resize
763 | return self
764 |
765 | # Create new structure filled with the fill block identifier
766 | if fill is not None:
767 | new_structure = np.full(size, ident, dtype=np.intc)
768 | else:
769 | new_structure = np.full(size, -1, dtype=np.intc) # Fill Structure void
770 |
771 | # Calculate the overlap region (what we can copy from old to new)
772 | old_size = self.structure.shape
773 | copy_size = tuple(min(old_size[i], size[i]) for i in range(3))
774 |
775 | # Copy the existing Blocks that fits into the new size
776 | if all(s > 0 for s in copy_size):
777 | new_structure[: copy_size[0], : copy_size[1], : copy_size[2]] = (
778 | self.structure[: copy_size[0], : copy_size[1], : copy_size[2]]
779 | )
780 |
781 | self.structure = new_structure
782 | return self
783 |
784 | def combine(self, other: Structure, position: Coordinate = (0, 0, 0)) -> Structure:
785 | """
786 | Combines another structure into this structure.
787 |
788 | Parameters
789 | ----------
790 | other
791 | The other structure to combine with.
792 |
793 | position
794 | The position to place the other structure at.
795 |
796 | note: This position is relative to the
797 | current structure's origin. ( no negative coordinates allowed )
798 |
799 | Returns
800 | -------
801 | Structure
802 | The combined structure.
803 | """
804 |
805 | ox, oy, oz = position
806 |
807 | if ox < 0 or oy < 0 or oz < 0:
808 | raise ValueError("Negative coordinates are not allowed.")
809 |
810 | # Calculate the new size needed to accommodate both structures
811 | end_pos = (ox + other._size[0], oy + other._size[1], oz + other._size[2])
812 | new_size = (
813 | max(self._size[0], end_pos[0]),
814 | max(self._size[1], end_pos[1]),
815 | max(self._size[2], end_pos[2]),
816 | )
817 |
818 | combined = Structure(new_size, None)
819 |
820 | # Copy the current structure's palette
821 | combined._palette = self._palette.copy()
822 |
823 | # Copy the current structure
824 | combined.structure[: self._size[0], : self._size[1], : self._size[2]] = (
825 | self.structure
826 | )
827 |
828 | # Create mapping from other's palette indices to combined palette indices
829 | other_to_combined_mapping = {
830 | other_idx: combined._add_block_to_palette(block)
831 | for other_idx, block in enumerate(other._palette)
832 | }
833 |
834 | # Remap the entire other structure using vectorized operations
835 | remapped_structure = other.structure.copy()
836 |
837 | # For non-structure-void blocks, apply the palette mapping
838 | for other_idx, combined_idx in other_to_combined_mapping.items():
839 | block_mask = other.structure == other_idx
840 | remapped_structure[block_mask] = combined_idx
841 |
842 | # Overlay the remapped structure onto the combined structure
843 | combined.structure[ox:, oy:, oz:] = remapped_structure[:, :, :]
844 |
845 | return combined
846 |
--------------------------------------------------------------------------------
/poetry.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand.
2 |
3 | [[package]]
4 | name = "alabaster"
5 | version = "1.0.0"
6 | description = "A light, configurable Sphinx theme"
7 | optional = true
8 | python-versions = ">=3.10"
9 | groups = ["main"]
10 | markers = "extra == \"docs\""
11 | files = [
12 | {file = "alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b"},
13 | {file = "alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e"},
14 | ]
15 |
16 | [[package]]
17 | name = "babel"
18 | version = "2.17.0"
19 | description = "Internationalization utilities"
20 | optional = true
21 | python-versions = ">=3.8"
22 | groups = ["main"]
23 | markers = "extra == \"docs\""
24 | files = [
25 | {file = "babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2"},
26 | {file = "babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d"},
27 | ]
28 |
29 | [package.extras]
30 | dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata ; sys_platform == \"win32\""]
31 |
32 | [[package]]
33 | name = "beautifulsoup4"
34 | version = "4.13.4"
35 | description = "Screen-scraping library"
36 | optional = true
37 | python-versions = ">=3.7.0"
38 | groups = ["main"]
39 | markers = "extra == \"docs\""
40 | files = [
41 | {file = "beautifulsoup4-4.13.4-py3-none-any.whl", hash = "sha256:9bbbb14bfde9d79f38b8cd5f8c7c85f4b8f2523190ebed90e950a8dea4cb1c4b"},
42 | {file = "beautifulsoup4-4.13.4.tar.gz", hash = "sha256:dbb3c4e1ceae6aefebdaf2423247260cd062430a410e38c66f2baa50a8437195"},
43 | ]
44 |
45 | [package.dependencies]
46 | soupsieve = ">1.2"
47 | typing-extensions = ">=4.0.0"
48 |
49 | [package.extras]
50 | cchardet = ["cchardet"]
51 | chardet = ["chardet"]
52 | charset-normalizer = ["charset-normalizer"]
53 | html5lib = ["html5lib"]
54 | lxml = ["lxml"]
55 |
56 | [[package]]
57 | name = "black"
58 | version = "25.1.0"
59 | description = "The uncompromising code formatter."
60 | optional = true
61 | python-versions = ">=3.9"
62 | groups = ["main"]
63 | markers = "extra == \"dev\""
64 | files = [
65 | {file = "black-25.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:759e7ec1e050a15f89b770cefbf91ebee8917aac5c20483bc2d80a6c3a04df32"},
66 | {file = "black-25.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e519ecf93120f34243e6b0054db49c00a35f84f195d5bce7e9f5cfc578fc2da"},
67 | {file = "black-25.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:055e59b198df7ac0b7efca5ad7ff2516bca343276c466be72eb04a3bcc1f82d7"},
68 | {file = "black-25.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:db8ea9917d6f8fc62abd90d944920d95e73c83a5ee3383493e35d271aca872e9"},
69 | {file = "black-25.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a39337598244de4bae26475f77dda852ea00a93bd4c728e09eacd827ec929df0"},
70 | {file = "black-25.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:96c1c7cd856bba8e20094e36e0f948718dc688dba4a9d78c3adde52b9e6c2299"},
71 | {file = "black-25.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bce2e264d59c91e52d8000d507eb20a9aca4a778731a08cfff7e5ac4a4bb7096"},
72 | {file = "black-25.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:172b1dbff09f86ce6f4eb8edf9dede08b1fce58ba194c87d7a4f1a5aa2f5b3c2"},
73 | {file = "black-25.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4b60580e829091e6f9238c848ea6750efed72140b91b048770b64e74fe04908b"},
74 | {file = "black-25.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e2978f6df243b155ef5fa7e558a43037c3079093ed5d10fd84c43900f2d8ecc"},
75 | {file = "black-25.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b48735872ec535027d979e8dcb20bf4f70b5ac75a8ea99f127c106a7d7aba9f"},
76 | {file = "black-25.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea0213189960bda9cf99be5b8c8ce66bb054af5e9e861249cd23471bd7b0b3ba"},
77 | {file = "black-25.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f0b18a02996a836cc9c9c78e5babec10930862827b1b724ddfe98ccf2f2fe4f"},
78 | {file = "black-25.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:afebb7098bfbc70037a053b91ae8437c3857482d3a690fefc03e9ff7aa9a5fd3"},
79 | {file = "black-25.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:030b9759066a4ee5e5aca28c3c77f9c64789cdd4de8ac1df642c40b708be6171"},
80 | {file = "black-25.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18"},
81 | {file = "black-25.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a1ee0a0c330f7b5130ce0caed9936a904793576ef4d2b98c40835d6a65afa6a0"},
82 | {file = "black-25.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3df5f1bf91d36002b0a75389ca8663510cf0531cca8aa5c1ef695b46d98655f"},
83 | {file = "black-25.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9e6827d563a2c820772b32ce8a42828dc6790f095f441beef18f96aa6f8294e"},
84 | {file = "black-25.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:bacabb307dca5ebaf9c118d2d2f6903da0d62c9faa82bd21a33eecc319559355"},
85 | {file = "black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717"},
86 | {file = "black-25.1.0.tar.gz", hash = "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666"},
87 | ]
88 |
89 | [package.dependencies]
90 | click = ">=8.0.0"
91 | mypy-extensions = ">=0.4.3"
92 | packaging = ">=22.0"
93 | pathspec = ">=0.9.0"
94 | platformdirs = ">=2"
95 |
96 | [package.extras]
97 | colorama = ["colorama (>=0.4.3)"]
98 | d = ["aiohttp (>=3.10)"]
99 | jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
100 | uvloop = ["uvloop (>=0.15.2)"]
101 |
102 | [[package]]
103 | name = "certifi"
104 | version = "2025.6.15"
105 | description = "Python package for providing Mozilla's CA Bundle."
106 | optional = true
107 | python-versions = ">=3.7"
108 | groups = ["main"]
109 | markers = "extra == \"docs\""
110 | files = [
111 | {file = "certifi-2025.6.15-py3-none-any.whl", hash = "sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057"},
112 | {file = "certifi-2025.6.15.tar.gz", hash = "sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b"},
113 | ]
114 |
115 | [[package]]
116 | name = "charset-normalizer"
117 | version = "3.4.2"
118 | description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
119 | optional = true
120 | python-versions = ">=3.7"
121 | groups = ["main"]
122 | markers = "extra == \"docs\""
123 | files = [
124 | {file = "charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941"},
125 | {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd"},
126 | {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6"},
127 | {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d"},
128 | {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86"},
129 | {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c"},
130 | {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0"},
131 | {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef"},
132 | {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6"},
133 | {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366"},
134 | {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db"},
135 | {file = "charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a"},
136 | {file = "charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509"},
137 | {file = "charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2"},
138 | {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645"},
139 | {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd"},
140 | {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8"},
141 | {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f"},
142 | {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7"},
143 | {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9"},
144 | {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544"},
145 | {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82"},
146 | {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0"},
147 | {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5"},
148 | {file = "charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a"},
149 | {file = "charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28"},
150 | {file = "charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7"},
151 | {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3"},
152 | {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a"},
153 | {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214"},
154 | {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a"},
155 | {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd"},
156 | {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981"},
157 | {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c"},
158 | {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b"},
159 | {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d"},
160 | {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f"},
161 | {file = "charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c"},
162 | {file = "charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e"},
163 | {file = "charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0"},
164 | {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf"},
165 | {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e"},
166 | {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1"},
167 | {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c"},
168 | {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691"},
169 | {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0"},
170 | {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b"},
171 | {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff"},
172 | {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b"},
173 | {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148"},
174 | {file = "charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7"},
175 | {file = "charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980"},
176 | {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cad5f45b3146325bb38d6855642f6fd609c3f7cad4dbaf75549bf3b904d3184"},
177 | {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2680962a4848b3c4f155dc2ee64505a9c57186d0d56b43123b17ca3de18f0fa"},
178 | {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:36b31da18b8890a76ec181c3cf44326bf2c48e36d393ca1b72b3f484113ea344"},
179 | {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4074c5a429281bf056ddd4c5d3b740ebca4d43ffffe2ef4bf4d2d05114299da"},
180 | {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9e36a97bee9b86ef9a1cf7bb96747eb7a15c2f22bdb5b516434b00f2a599f02"},
181 | {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:1b1bde144d98e446b056ef98e59c256e9294f6b74d7af6846bf5ffdafd687a7d"},
182 | {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:915f3849a011c1f593ab99092f3cecfcb4d65d8feb4a64cf1bf2d22074dc0ec4"},
183 | {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:fb707f3e15060adf5b7ada797624a6c6e0138e2a26baa089df64c68ee98e040f"},
184 | {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:25a23ea5c7edc53e0f29bae2c44fcb5a1aa10591aae107f2a2b2583a9c5cbc64"},
185 | {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:770cab594ecf99ae64c236bc9ee3439c3f46be49796e265ce0cc8bc17b10294f"},
186 | {file = "charset_normalizer-3.4.2-cp37-cp37m-win32.whl", hash = "sha256:6a0289e4589e8bdfef02a80478f1dfcb14f0ab696b5a00e1f4b8a14a307a3c58"},
187 | {file = "charset_normalizer-3.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6fc1f5b51fa4cecaa18f2bd7a003f3dd039dd615cd69a2afd6d3b19aed6775f2"},
188 | {file = "charset_normalizer-3.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb"},
189 | {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a"},
190 | {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45"},
191 | {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5"},
192 | {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1"},
193 | {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027"},
194 | {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b"},
195 | {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455"},
196 | {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01"},
197 | {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58"},
198 | {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681"},
199 | {file = "charset_normalizer-3.4.2-cp38-cp38-win32.whl", hash = "sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7"},
200 | {file = "charset_normalizer-3.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a"},
201 | {file = "charset_normalizer-3.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4"},
202 | {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7"},
203 | {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836"},
204 | {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597"},
205 | {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7"},
206 | {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f"},
207 | {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba"},
208 | {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12"},
209 | {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518"},
210 | {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5"},
211 | {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3"},
212 | {file = "charset_normalizer-3.4.2-cp39-cp39-win32.whl", hash = "sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471"},
213 | {file = "charset_normalizer-3.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e"},
214 | {file = "charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0"},
215 | {file = "charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63"},
216 | ]
217 |
218 | [[package]]
219 | name = "click"
220 | version = "8.2.1"
221 | description = "Composable command line interface toolkit"
222 | optional = true
223 | python-versions = ">=3.10"
224 | groups = ["main"]
225 | markers = "extra == \"dev\""
226 | files = [
227 | {file = "click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b"},
228 | {file = "click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202"},
229 | ]
230 |
231 | [package.dependencies]
232 | colorama = {version = "*", markers = "platform_system == \"Windows\""}
233 |
234 | [[package]]
235 | name = "colorama"
236 | version = "0.4.6"
237 | description = "Cross-platform colored terminal text."
238 | optional = true
239 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
240 | groups = ["main"]
241 | markers = "sys_platform == \"win32\" and (extra == \"dev\" or extra == \"docs\") or extra == \"dev\" and platform_system == \"Windows\""
242 | files = [
243 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
244 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
245 | ]
246 |
247 | [[package]]
248 | name = "docutils"
249 | version = "0.21.2"
250 | description = "Docutils -- Python Documentation Utilities"
251 | optional = true
252 | python-versions = ">=3.9"
253 | groups = ["main"]
254 | markers = "extra == \"docs\""
255 | files = [
256 | {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"},
257 | {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"},
258 | ]
259 |
260 | [[package]]
261 | name = "furo"
262 | version = "2024.8.6"
263 | description = "A clean customisable Sphinx documentation theme."
264 | optional = true
265 | python-versions = ">=3.8"
266 | groups = ["main"]
267 | markers = "extra == \"docs\""
268 | files = [
269 | {file = "furo-2024.8.6-py3-none-any.whl", hash = "sha256:6cd97c58b47813d3619e63e9081169880fbe331f0ca883c871ff1f3f11814f5c"},
270 | {file = "furo-2024.8.6.tar.gz", hash = "sha256:b63e4cee8abfc3136d3bc03a3d45a76a850bada4d6374d24c1716b0e01394a01"},
271 | ]
272 |
273 | [package.dependencies]
274 | beautifulsoup4 = "*"
275 | pygments = ">=2.7"
276 | sphinx = ">=6.0,<9.0"
277 | sphinx-basic-ng = ">=1.0.0.beta2"
278 |
279 | [[package]]
280 | name = "idna"
281 | version = "3.10"
282 | description = "Internationalized Domain Names in Applications (IDNA)"
283 | optional = true
284 | python-versions = ">=3.6"
285 | groups = ["main"]
286 | markers = "extra == \"docs\""
287 | files = [
288 | {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"},
289 | {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"},
290 | ]
291 |
292 | [package.extras]
293 | all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"]
294 |
295 | [[package]]
296 | name = "imagesize"
297 | version = "1.4.1"
298 | description = "Getting image size from png/jpeg/jpeg2000/gif file"
299 | optional = true
300 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
301 | groups = ["main"]
302 | markers = "extra == \"docs\""
303 | files = [
304 | {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"},
305 | {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"},
306 | ]
307 |
308 | [[package]]
309 | name = "iniconfig"
310 | version = "2.1.0"
311 | description = "brain-dead simple config-ini parsing"
312 | optional = true
313 | python-versions = ">=3.8"
314 | groups = ["main"]
315 | markers = "extra == \"dev\""
316 | files = [
317 | {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"},
318 | {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"},
319 | ]
320 |
321 | [[package]]
322 | name = "jinja2"
323 | version = "3.1.6"
324 | description = "A very fast and expressive template engine."
325 | optional = true
326 | python-versions = ">=3.7"
327 | groups = ["main"]
328 | markers = "extra == \"docs\""
329 | files = [
330 | {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"},
331 | {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"},
332 | ]
333 |
334 | [package.dependencies]
335 | MarkupSafe = ">=2.0"
336 |
337 | [package.extras]
338 | i18n = ["Babel (>=2.7)"]
339 |
340 | [[package]]
341 | name = "markdown-it-py"
342 | version = "3.0.0"
343 | description = "Python port of markdown-it. Markdown parsing, done right!"
344 | optional = true
345 | python-versions = ">=3.8"
346 | groups = ["main"]
347 | markers = "extra == \"docs\""
348 | files = [
349 | {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
350 | {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
351 | ]
352 |
353 | [package.dependencies]
354 | mdurl = ">=0.1,<1.0"
355 |
356 | [package.extras]
357 | benchmarking = ["psutil", "pytest", "pytest-benchmark"]
358 | code-style = ["pre-commit (>=3.0,<4.0)"]
359 | compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"]
360 | linkify = ["linkify-it-py (>=1,<3)"]
361 | plugins = ["mdit-py-plugins"]
362 | profiling = ["gprof2dot"]
363 | rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
364 | testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
365 |
366 | [[package]]
367 | name = "markupsafe"
368 | version = "3.0.2"
369 | description = "Safely add untrusted strings to HTML/XML markup."
370 | optional = true
371 | python-versions = ">=3.9"
372 | groups = ["main"]
373 | markers = "extra == \"docs\""
374 | files = [
375 | {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"},
376 | {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"},
377 | {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"},
378 | {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"},
379 | {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"},
380 | {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"},
381 | {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"},
382 | {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"},
383 | {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"},
384 | {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"},
385 | {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"},
386 | {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"},
387 | {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"},
388 | {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"},
389 | {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"},
390 | {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"},
391 | {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"},
392 | {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"},
393 | {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"},
394 | {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"},
395 | {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"},
396 | {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"},
397 | {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"},
398 | {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"},
399 | {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"},
400 | {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"},
401 | {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"},
402 | {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"},
403 | {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"},
404 | {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"},
405 | {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"},
406 | {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"},
407 | {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"},
408 | {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"},
409 | {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"},
410 | {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"},
411 | {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"},
412 | {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"},
413 | {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"},
414 | {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"},
415 | {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"},
416 | {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"},
417 | {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"},
418 | {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"},
419 | {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"},
420 | {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"},
421 | {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"},
422 | {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"},
423 | {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"},
424 | {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"},
425 | {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"},
426 | {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"},
427 | {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"},
428 | {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"},
429 | {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"},
430 | {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"},
431 | {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"},
432 | {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"},
433 | {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"},
434 | {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"},
435 | {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"},
436 | ]
437 |
438 | [[package]]
439 | name = "mdit-py-plugins"
440 | version = "0.4.2"
441 | description = "Collection of plugins for markdown-it-py"
442 | optional = true
443 | python-versions = ">=3.8"
444 | groups = ["main"]
445 | markers = "extra == \"docs\""
446 | files = [
447 | {file = "mdit_py_plugins-0.4.2-py3-none-any.whl", hash = "sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636"},
448 | {file = "mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5"},
449 | ]
450 |
451 | [package.dependencies]
452 | markdown-it-py = ">=1.0.0,<4.0.0"
453 |
454 | [package.extras]
455 | code-style = ["pre-commit"]
456 | rtd = ["myst-parser", "sphinx-book-theme"]
457 | testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
458 |
459 | [[package]]
460 | name = "mdurl"
461 | version = "0.1.2"
462 | description = "Markdown URL utilities"
463 | optional = true
464 | python-versions = ">=3.7"
465 | groups = ["main"]
466 | markers = "extra == \"docs\""
467 | files = [
468 | {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
469 | {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
470 | ]
471 |
472 | [[package]]
473 | name = "mypy"
474 | version = "1.16.1"
475 | description = "Optional static typing for Python"
476 | optional = true
477 | python-versions = ">=3.9"
478 | groups = ["main"]
479 | markers = "extra == \"dev\""
480 | files = [
481 | {file = "mypy-1.16.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b4f0fed1022a63c6fec38f28b7fc77fca47fd490445c69d0a66266c59dd0b88a"},
482 | {file = "mypy-1.16.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:86042bbf9f5a05ea000d3203cf87aa9d0ccf9a01f73f71c58979eb9249f46d72"},
483 | {file = "mypy-1.16.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ea7469ee5902c95542bea7ee545f7006508c65c8c54b06dc2c92676ce526f3ea"},
484 | {file = "mypy-1.16.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:352025753ef6a83cb9e7f2427319bb7875d1fdda8439d1e23de12ab164179574"},
485 | {file = "mypy-1.16.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ff9fa5b16e4c1364eb89a4d16bcda9987f05d39604e1e6c35378a2987c1aac2d"},
486 | {file = "mypy-1.16.1-cp310-cp310-win_amd64.whl", hash = "sha256:1256688e284632382f8f3b9e2123df7d279f603c561f099758e66dd6ed4e8bd6"},
487 | {file = "mypy-1.16.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:472e4e4c100062488ec643f6162dd0d5208e33e2f34544e1fc931372e806c0cc"},
488 | {file = "mypy-1.16.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ea16e2a7d2714277e349e24d19a782a663a34ed60864006e8585db08f8ad1782"},
489 | {file = "mypy-1.16.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08e850ea22adc4d8a4014651575567b0318ede51e8e9fe7a68f25391af699507"},
490 | {file = "mypy-1.16.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22d76a63a42619bfb90122889b903519149879ddbf2ba4251834727944c8baca"},
491 | {file = "mypy-1.16.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2c7ce0662b6b9dc8f4ed86eb7a5d505ee3298c04b40ec13b30e572c0e5ae17c4"},
492 | {file = "mypy-1.16.1-cp311-cp311-win_amd64.whl", hash = "sha256:211287e98e05352a2e1d4e8759c5490925a7c784ddc84207f4714822f8cf99b6"},
493 | {file = "mypy-1.16.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:af4792433f09575d9eeca5c63d7d90ca4aeceda9d8355e136f80f8967639183d"},
494 | {file = "mypy-1.16.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:66df38405fd8466ce3517eda1f6640611a0b8e70895e2a9462d1d4323c5eb4b9"},
495 | {file = "mypy-1.16.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44e7acddb3c48bd2713994d098729494117803616e116032af192871aed80b79"},
496 | {file = "mypy-1.16.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0ab5eca37b50188163fa7c1b73c685ac66c4e9bdee4a85c9adac0e91d8895e15"},
497 | {file = "mypy-1.16.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb6229b2c9086247e21a83c309754b9058b438704ad2f6807f0d8227f6ebdd"},
498 | {file = "mypy-1.16.1-cp312-cp312-win_amd64.whl", hash = "sha256:1f0435cf920e287ff68af3d10a118a73f212deb2ce087619eb4e648116d1fe9b"},
499 | {file = "mypy-1.16.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ddc91eb318c8751c69ddb200a5937f1232ee8efb4e64e9f4bc475a33719de438"},
500 | {file = "mypy-1.16.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:87ff2c13d58bdc4bbe7dc0dedfe622c0f04e2cb2a492269f3b418df2de05c536"},
501 | {file = "mypy-1.16.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a7cfb0fe29fe5a9841b7c8ee6dffb52382c45acdf68f032145b75620acfbd6f"},
502 | {file = "mypy-1.16.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:051e1677689c9d9578b9c7f4d206d763f9bbd95723cd1416fad50db49d52f359"},
503 | {file = "mypy-1.16.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d5d2309511cc56c021b4b4e462907c2b12f669b2dbeb68300110ec27723971be"},
504 | {file = "mypy-1.16.1-cp313-cp313-win_amd64.whl", hash = "sha256:4f58ac32771341e38a853c5d0ec0dfe27e18e27da9cdb8bbc882d2249c71a3ee"},
505 | {file = "mypy-1.16.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7fc688329af6a287567f45cc1cefb9db662defeb14625213a5b7da6e692e2069"},
506 | {file = "mypy-1.16.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e198ab3f55924c03ead626ff424cad1732d0d391478dfbf7bb97b34602395da"},
507 | {file = "mypy-1.16.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:09aa4f91ada245f0a45dbc47e548fd94e0dd5a8433e0114917dc3b526912a30c"},
508 | {file = "mypy-1.16.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13c7cd5b1cb2909aa318a90fd1b7e31f17c50b242953e7dd58345b2a814f6383"},
509 | {file = "mypy-1.16.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:58e07fb958bc5d752a280da0e890c538f1515b79a65757bbdc54252ba82e0b40"},
510 | {file = "mypy-1.16.1-cp39-cp39-win_amd64.whl", hash = "sha256:f895078594d918f93337a505f8add9bd654d1a24962b4c6ed9390e12531eb31b"},
511 | {file = "mypy-1.16.1-py3-none-any.whl", hash = "sha256:5fc2ac4027d0ef28d6ba69a0343737a23c4d1b83672bf38d1fe237bdc0643b37"},
512 | {file = "mypy-1.16.1.tar.gz", hash = "sha256:6bd00a0a2094841c5e47e7374bb42b83d64c527a502e3334e1173a0c24437bab"},
513 | ]
514 |
515 | [package.dependencies]
516 | mypy_extensions = ">=1.0.0"
517 | pathspec = ">=0.9.0"
518 | typing_extensions = ">=4.6.0"
519 |
520 | [package.extras]
521 | dmypy = ["psutil (>=4.0)"]
522 | faster-cache = ["orjson"]
523 | install-types = ["pip"]
524 | mypyc = ["setuptools (>=50)"]
525 | reports = ["lxml"]
526 |
527 | [[package]]
528 | name = "mypy-extensions"
529 | version = "1.1.0"
530 | description = "Type system extensions for programs checked with the mypy type checker."
531 | optional = true
532 | python-versions = ">=3.8"
533 | groups = ["main"]
534 | markers = "extra == \"dev\""
535 | files = [
536 | {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"},
537 | {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"},
538 | ]
539 |
540 | [[package]]
541 | name = "myst-parser"
542 | version = "4.0.1"
543 | description = "An extended [CommonMark](https://spec.commonmark.org/) compliant parser,"
544 | optional = true
545 | python-versions = ">=3.10"
546 | groups = ["main"]
547 | markers = "extra == \"docs\""
548 | files = [
549 | {file = "myst_parser-4.0.1-py3-none-any.whl", hash = "sha256:9134e88959ec3b5780aedf8a99680ea242869d012e8821db3126d427edc9c95d"},
550 | {file = "myst_parser-4.0.1.tar.gz", hash = "sha256:5cfea715e4f3574138aecbf7d54132296bfd72bb614d31168f48c477a830a7c4"},
551 | ]
552 |
553 | [package.dependencies]
554 | docutils = ">=0.19,<0.22"
555 | jinja2 = "*"
556 | markdown-it-py = ">=3.0,<4.0"
557 | mdit-py-plugins = ">=0.4.1,<1.0"
558 | pyyaml = "*"
559 | sphinx = ">=7,<9"
560 |
561 | [package.extras]
562 | code-style = ["pre-commit (>=4.0,<5.0)"]
563 | linkify = ["linkify-it-py (>=2.0,<3.0)"]
564 | rtd = ["ipython", "sphinx (>=7)", "sphinx-autodoc2 (>=0.5.0,<0.6.0)", "sphinx-book-theme (>=1.1,<2.0)", "sphinx-copybutton", "sphinx-design", "sphinx-pyscript", "sphinx-tippy (>=0.4.3)", "sphinx-togglebutton", "sphinxext-opengraph (>=0.9.0,<0.10.0)", "sphinxext-rediraffe (>=0.2.7,<0.3.0)"]
565 | testing = ["beautifulsoup4", "coverage[toml]", "defusedxml", "pygments (<2.19)", "pytest (>=8,<9)", "pytest-cov", "pytest-param-files (>=0.6.0,<0.7.0)", "pytest-regressions", "sphinx-pytest"]
566 | testing-docutils = ["pygments", "pytest (>=8,<9)", "pytest-param-files (>=0.6.0,<0.7.0)"]
567 |
568 | [[package]]
569 | name = "nbtx"
570 | version = "0.4.1"
571 | description = "Minecraft NBT parser"
572 | optional = false
573 | python-versions = ">=3.13"
574 | groups = ["main"]
575 | files = [
576 | {file = "nbtx-0.4.1-py3-none-any.whl", hash = "sha256:cea2abc9126ab5788cef5898fbb4e83396429dcb4437b4ba9417c8a7c07be755"},
577 | {file = "nbtx-0.4.1.tar.gz", hash = "sha256:4cff89779883ef639a71ca31c39b56bca4f238b4f1bebcd9527c871eda22955b"},
578 | ]
579 |
580 | [package.extras]
581 | dev = ["codespell (==2.4.1)", "coverage (==7.10.6)", "docstr-coverage (==2.3.2)", "isort (==6.0.1)", "mypy (==1.17.1)", "nox (==2025.5.1)", "pytest (==8.4.1)", "ruff (==0.12.12)"]
582 | docs = ["pdoc (==15.0.4)"]
583 |
584 | [[package]]
585 | name = "numpy"
586 | version = "2.3.0"
587 | description = "Fundamental package for array computing in Python"
588 | optional = false
589 | python-versions = ">=3.11"
590 | groups = ["main"]
591 | files = [
592 | {file = "numpy-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c3c9fdde0fa18afa1099d6257eb82890ea4f3102847e692193b54e00312a9ae9"},
593 | {file = "numpy-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:46d16f72c2192da7b83984aa5455baee640e33a9f1e61e656f29adf55e406c2b"},
594 | {file = "numpy-2.3.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a0be278be9307c4ab06b788f2a077f05e180aea817b3e41cebbd5aaf7bd85ed3"},
595 | {file = "numpy-2.3.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:99224862d1412d2562248d4710126355d3a8db7672170a39d6909ac47687a8a4"},
596 | {file = "numpy-2.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:2393a914db64b0ead0ab80c962e42d09d5f385802006a6c87835acb1f58adb96"},
597 | {file = "numpy-2.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:7729c8008d55e80784bd113787ce876ca117185c579c0d626f59b87d433ea779"},
598 | {file = "numpy-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:06d4fb37a8d383b769281714897420c5cc3545c79dc427df57fc9b852ee0bf58"},
599 | {file = "numpy-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c39ec392b5db5088259c68250e342612db82dc80ce044cf16496cf14cf6bc6f8"},
600 | {file = "numpy-2.3.0-cp311-cp311-win32.whl", hash = "sha256:ee9d3ee70d62827bc91f3ea5eee33153212c41f639918550ac0475e3588da59f"},
601 | {file = "numpy-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:43c55b6a860b0eb44d42341438b03513cf3879cb3617afb749ad49307e164edd"},
602 | {file = "numpy-2.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:2e6a1409eee0cb0316cb64640a49a49ca44deb1a537e6b1121dc7c458a1299a8"},
603 | {file = "numpy-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:389b85335838155a9076e9ad7f8fdba0827496ec2d2dc32ce69ce7898bde03ba"},
604 | {file = "numpy-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9498f60cd6bb8238d8eaf468a3d5bb031d34cd12556af53510f05fcf581c1b7e"},
605 | {file = "numpy-2.3.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:622a65d40d8eb427d8e722fd410ac3ad4958002f109230bc714fa551044ebae2"},
606 | {file = "numpy-2.3.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:b9446d9d8505aadadb686d51d838f2b6688c9e85636a0c3abaeb55ed54756459"},
607 | {file = "numpy-2.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:50080245365d75137a2bf46151e975de63146ae6d79f7e6bd5c0e85c9931d06a"},
608 | {file = "numpy-2.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:c24bb4113c66936eeaa0dc1e47c74770453d34f46ee07ae4efd853a2ed1ad10a"},
609 | {file = "numpy-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4d8d294287fdf685281e671886c6dcdf0291a7c19db3e5cb4178d07ccf6ecc67"},
610 | {file = "numpy-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6295f81f093b7f5769d1728a6bd8bf7466de2adfa771ede944ce6711382b89dc"},
611 | {file = "numpy-2.3.0-cp312-cp312-win32.whl", hash = "sha256:e6648078bdd974ef5d15cecc31b0c410e2e24178a6e10bf511e0557eed0f2570"},
612 | {file = "numpy-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:0898c67a58cdaaf29994bc0e2c65230fd4de0ac40afaf1584ed0b02cd74c6fdd"},
613 | {file = "numpy-2.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:bd8df082b6c4695753ad6193018c05aac465d634834dca47a3ae06d4bb22d9ea"},
614 | {file = "numpy-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5754ab5595bfa2c2387d241296e0381c21f44a4b90a776c3c1d39eede13a746a"},
615 | {file = "numpy-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d11fa02f77752d8099573d64e5fe33de3229b6632036ec08f7080f46b6649959"},
616 | {file = "numpy-2.3.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:aba48d17e87688a765ab1cd557882052f238e2f36545dfa8e29e6a91aef77afe"},
617 | {file = "numpy-2.3.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:4dc58865623023b63b10d52f18abaac3729346a7a46a778381e0e3af4b7f3beb"},
618 | {file = "numpy-2.3.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:df470d376f54e052c76517393fa443758fefcdd634645bc9c1f84eafc67087f0"},
619 | {file = "numpy-2.3.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:87717eb24d4a8a64683b7a4e91ace04e2f5c7c77872f823f02a94feee186168f"},
620 | {file = "numpy-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d8fa264d56882b59dcb5ea4d6ab6f31d0c58a57b41aec605848b6eb2ef4a43e8"},
621 | {file = "numpy-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e651756066a0eaf900916497e20e02fe1ae544187cb0fe88de981671ee7f6270"},
622 | {file = "numpy-2.3.0-cp313-cp313-win32.whl", hash = "sha256:e43c3cce3b6ae5f94696669ff2a6eafd9a6b9332008bafa4117af70f4b88be6f"},
623 | {file = "numpy-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:81ae0bf2564cf475f94be4a27ef7bcf8af0c3e28da46770fc904da9abd5279b5"},
624 | {file = "numpy-2.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:c8738baa52505fa6e82778580b23f945e3578412554d937093eac9205e845e6e"},
625 | {file = "numpy-2.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:39b27d8b38942a647f048b675f134dd5a567f95bfff481f9109ec308515c51d8"},
626 | {file = "numpy-2.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0eba4a1ea88f9a6f30f56fdafdeb8da3774349eacddab9581a21234b8535d3d3"},
627 | {file = "numpy-2.3.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:b0f1f11d0a1da54927436505a5a7670b154eac27f5672afc389661013dfe3d4f"},
628 | {file = "numpy-2.3.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:690d0a5b60a47e1f9dcec7b77750a4854c0d690e9058b7bef3106e3ae9117808"},
629 | {file = "numpy-2.3.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:8b51ead2b258284458e570942137155978583e407babc22e3d0ed7af33ce06f8"},
630 | {file = "numpy-2.3.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:aaf81c7b82c73bd9b45e79cfb9476cb9c29e937494bfe9092c26aece812818ad"},
631 | {file = "numpy-2.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f420033a20b4f6a2a11f585f93c843ac40686a7c3fa514060a97d9de93e5e72b"},
632 | {file = "numpy-2.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d344ca32ab482bcf8735d8f95091ad081f97120546f3d250240868430ce52555"},
633 | {file = "numpy-2.3.0-cp313-cp313t-win32.whl", hash = "sha256:48a2e8eaf76364c32a1feaa60d6925eaf32ed7a040183b807e02674305beef61"},
634 | {file = "numpy-2.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ba17f93a94e503551f154de210e4d50c5e3ee20f7e7a1b5f6ce3f22d419b93bb"},
635 | {file = "numpy-2.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:f14e016d9409680959691c109be98c436c6249eaf7f118b424679793607b5944"},
636 | {file = "numpy-2.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:80b46117c7359de8167cc00a2c7d823bdd505e8c7727ae0871025a86d668283b"},
637 | {file = "numpy-2.3.0-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:5814a0f43e70c061f47abd5857d120179609ddc32a613138cbb6c4e9e2dbdda5"},
638 | {file = "numpy-2.3.0-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:ef6c1e88fd6b81ac6d215ed71dc8cd027e54d4bf1d2682d362449097156267a2"},
639 | {file = "numpy-2.3.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:33a5a12a45bb82d9997e2c0b12adae97507ad7c347546190a18ff14c28bbca12"},
640 | {file = "numpy-2.3.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:54dfc8681c1906d239e95ab1508d0a533c4a9505e52ee2d71a5472b04437ef97"},
641 | {file = "numpy-2.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:e017a8a251ff4d18d71f139e28bdc7c31edba7a507f72b1414ed902cbe48c74d"},
642 | {file = "numpy-2.3.0.tar.gz", hash = "sha256:581f87f9e9e9db2cba2141400e160e9dd644ee248788d6f90636eeb8fd9260a6"},
643 | ]
644 |
645 | [[package]]
646 | name = "packaging"
647 | version = "25.0"
648 | description = "Core utilities for Python packages"
649 | optional = true
650 | python-versions = ">=3.8"
651 | groups = ["main"]
652 | markers = "extra == \"dev\" or extra == \"docs\""
653 | files = [
654 | {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"},
655 | {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"},
656 | ]
657 |
658 | [[package]]
659 | name = "pathspec"
660 | version = "0.12.1"
661 | description = "Utility library for gitignore style pattern matching of file paths."
662 | optional = true
663 | python-versions = ">=3.8"
664 | groups = ["main"]
665 | markers = "extra == \"dev\""
666 | files = [
667 | {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
668 | {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
669 | ]
670 |
671 | [[package]]
672 | name = "platformdirs"
673 | version = "4.3.8"
674 | description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
675 | optional = true
676 | python-versions = ">=3.9"
677 | groups = ["main"]
678 | markers = "extra == \"dev\""
679 | files = [
680 | {file = "platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4"},
681 | {file = "platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc"},
682 | ]
683 |
684 | [package.extras]
685 | docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"]
686 | test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)"]
687 | type = ["mypy (>=1.14.1)"]
688 |
689 | [[package]]
690 | name = "pluggy"
691 | version = "1.6.0"
692 | description = "plugin and hook calling mechanisms for python"
693 | optional = true
694 | python-versions = ">=3.9"
695 | groups = ["main"]
696 | markers = "extra == \"dev\""
697 | files = [
698 | {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"},
699 | {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"},
700 | ]
701 |
702 | [package.extras]
703 | dev = ["pre-commit", "tox"]
704 | testing = ["coverage", "pytest", "pytest-benchmark"]
705 |
706 | [[package]]
707 | name = "pygments"
708 | version = "2.19.2"
709 | description = "Pygments is a syntax highlighting package written in Python."
710 | optional = true
711 | python-versions = ">=3.8"
712 | groups = ["main"]
713 | markers = "extra == \"dev\" or extra == \"docs\""
714 | files = [
715 | {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"},
716 | {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"},
717 | ]
718 |
719 | [package.extras]
720 | windows-terminal = ["colorama (>=0.4.6)"]
721 |
722 | [[package]]
723 | name = "pytest"
724 | version = "8.4.1"
725 | description = "pytest: simple powerful testing with Python"
726 | optional = true
727 | python-versions = ">=3.9"
728 | groups = ["main"]
729 | markers = "extra == \"dev\""
730 | files = [
731 | {file = "pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7"},
732 | {file = "pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c"},
733 | ]
734 |
735 | [package.dependencies]
736 | colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""}
737 | iniconfig = ">=1"
738 | packaging = ">=20"
739 | pluggy = ">=1.5,<2"
740 | pygments = ">=2.7.2"
741 |
742 | [package.extras]
743 | dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"]
744 |
745 | [[package]]
746 | name = "pyyaml"
747 | version = "6.0.2"
748 | description = "YAML parser and emitter for Python"
749 | optional = true
750 | python-versions = ">=3.8"
751 | groups = ["main"]
752 | markers = "extra == \"docs\""
753 | files = [
754 | {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"},
755 | {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"},
756 | {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"},
757 | {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"},
758 | {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"},
759 | {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"},
760 | {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"},
761 | {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"},
762 | {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"},
763 | {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"},
764 | {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"},
765 | {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"},
766 | {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"},
767 | {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"},
768 | {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"},
769 | {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"},
770 | {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"},
771 | {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"},
772 | {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"},
773 | {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"},
774 | {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"},
775 | {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"},
776 | {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"},
777 | {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"},
778 | {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"},
779 | {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"},
780 | {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"},
781 | {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"},
782 | {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"},
783 | {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"},
784 | {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"},
785 | {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"},
786 | {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"},
787 | {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"},
788 | {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"},
789 | {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"},
790 | {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"},
791 | {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"},
792 | {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"},
793 | {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"},
794 | {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"},
795 | {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"},
796 | {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"},
797 | {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"},
798 | {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"},
799 | {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"},
800 | {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"},
801 | {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"},
802 | {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"},
803 | {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"},
804 | {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"},
805 | {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"},
806 | {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"},
807 | ]
808 |
809 | [[package]]
810 | name = "requests"
811 | version = "2.32.4"
812 | description = "Python HTTP for Humans."
813 | optional = true
814 | python-versions = ">=3.8"
815 | groups = ["main"]
816 | markers = "extra == \"docs\""
817 | files = [
818 | {file = "requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c"},
819 | {file = "requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422"},
820 | ]
821 |
822 | [package.dependencies]
823 | certifi = ">=2017.4.17"
824 | charset_normalizer = ">=2,<4"
825 | idna = ">=2.5,<4"
826 | urllib3 = ">=1.21.1,<3"
827 |
828 | [package.extras]
829 | socks = ["PySocks (>=1.5.6,!=1.5.7)"]
830 | use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
831 |
832 | [[package]]
833 | name = "roman-numerals-py"
834 | version = "3.1.0"
835 | description = "Manipulate well-formed Roman numerals"
836 | optional = true
837 | python-versions = ">=3.9"
838 | groups = ["main"]
839 | markers = "extra == \"docs\""
840 | files = [
841 | {file = "roman_numerals_py-3.1.0-py3-none-any.whl", hash = "sha256:9da2ad2fb670bcf24e81070ceb3be72f6c11c440d73bd579fbeca1e9f330954c"},
842 | {file = "roman_numerals_py-3.1.0.tar.gz", hash = "sha256:be4bf804f083a4ce001b5eb7e3c0862479d10f94c936f6c4e5f250aa5ff5bd2d"},
843 | ]
844 |
845 | [package.extras]
846 | lint = ["mypy (==1.15.0)", "pyright (==1.1.394)", "ruff (==0.9.7)"]
847 | test = ["pytest (>=8)"]
848 |
849 | [[package]]
850 | name = "snowballstemmer"
851 | version = "3.0.1"
852 | description = "This package provides 32 stemmers for 30 languages generated from Snowball algorithms."
853 | optional = true
854 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*"
855 | groups = ["main"]
856 | markers = "extra == \"docs\""
857 | files = [
858 | {file = "snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064"},
859 | {file = "snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895"},
860 | ]
861 |
862 | [[package]]
863 | name = "soupsieve"
864 | version = "2.7"
865 | description = "A modern CSS selector implementation for Beautiful Soup."
866 | optional = true
867 | python-versions = ">=3.8"
868 | groups = ["main"]
869 | markers = "extra == \"docs\""
870 | files = [
871 | {file = "soupsieve-2.7-py3-none-any.whl", hash = "sha256:6e60cc5c1ffaf1cebcc12e8188320b72071e922c2e897f737cadce79ad5d30c4"},
872 | {file = "soupsieve-2.7.tar.gz", hash = "sha256:ad282f9b6926286d2ead4750552c8a6142bc4c783fd66b0293547c8fe6ae126a"},
873 | ]
874 |
875 | [[package]]
876 | name = "sphinx"
877 | version = "8.2.3"
878 | description = "Python documentation generator"
879 | optional = true
880 | python-versions = ">=3.11"
881 | groups = ["main"]
882 | markers = "extra == \"docs\""
883 | files = [
884 | {file = "sphinx-8.2.3-py3-none-any.whl", hash = "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3"},
885 | {file = "sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348"},
886 | ]
887 |
888 | [package.dependencies]
889 | alabaster = ">=0.7.14"
890 | babel = ">=2.13"
891 | colorama = {version = ">=0.4.6", markers = "sys_platform == \"win32\""}
892 | docutils = ">=0.20,<0.22"
893 | imagesize = ">=1.3"
894 | Jinja2 = ">=3.1"
895 | packaging = ">=23.0"
896 | Pygments = ">=2.17"
897 | requests = ">=2.30.0"
898 | roman-numerals-py = ">=1.0.0"
899 | snowballstemmer = ">=2.2"
900 | sphinxcontrib-applehelp = ">=1.0.7"
901 | sphinxcontrib-devhelp = ">=1.0.6"
902 | sphinxcontrib-htmlhelp = ">=2.0.6"
903 | sphinxcontrib-jsmath = ">=1.0.1"
904 | sphinxcontrib-qthelp = ">=1.0.6"
905 | sphinxcontrib-serializinghtml = ">=1.1.9"
906 |
907 | [package.extras]
908 | docs = ["sphinxcontrib-websupport"]
909 | lint = ["betterproto (==2.0.0b6)", "mypy (==1.15.0)", "pypi-attestations (==0.0.21)", "pyright (==1.1.395)", "pytest (>=8.0)", "ruff (==0.9.9)", "sphinx-lint (>=0.9)", "types-Pillow (==10.2.0.20240822)", "types-Pygments (==2.19.0.20250219)", "types-colorama (==0.4.15.20240311)", "types-defusedxml (==0.7.0.20240218)", "types-docutils (==0.21.0.20241128)", "types-requests (==2.32.0.20241016)", "types-urllib3 (==1.26.25.14)"]
910 | test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=8.0)", "pytest-xdist[psutil] (>=3.4)", "setuptools (>=70.0)", "typing_extensions (>=4.9)"]
911 |
912 | [[package]]
913 | name = "sphinx-basic-ng"
914 | version = "1.0.0b2"
915 | description = "A modern skeleton for Sphinx themes."
916 | optional = true
917 | python-versions = ">=3.7"
918 | groups = ["main"]
919 | markers = "extra == \"docs\""
920 | files = [
921 | {file = "sphinx_basic_ng-1.0.0b2-py3-none-any.whl", hash = "sha256:eb09aedbabfb650607e9b4b68c9d240b90b1e1be221d6ad71d61c52e29f7932b"},
922 | {file = "sphinx_basic_ng-1.0.0b2.tar.gz", hash = "sha256:9ec55a47c90c8c002b5960c57492ec3021f5193cb26cebc2dc4ea226848651c9"},
923 | ]
924 |
925 | [package.dependencies]
926 | sphinx = ">=4.0"
927 |
928 | [package.extras]
929 | docs = ["furo", "ipython", "myst-parser", "sphinx-copybutton", "sphinx-inline-tabs"]
930 |
931 | [[package]]
932 | name = "sphinx-copybutton"
933 | version = "0.5.2"
934 | description = "Add a copy button to each of your code cells."
935 | optional = true
936 | python-versions = ">=3.7"
937 | groups = ["main"]
938 | markers = "extra == \"docs\""
939 | files = [
940 | {file = "sphinx-copybutton-0.5.2.tar.gz", hash = "sha256:4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd"},
941 | {file = "sphinx_copybutton-0.5.2-py3-none-any.whl", hash = "sha256:fb543fd386d917746c9a2c50360c7905b605726b9355cd26e9974857afeae06e"},
942 | ]
943 |
944 | [package.dependencies]
945 | sphinx = ">=1.8"
946 |
947 | [package.extras]
948 | code-style = ["pre-commit (==2.12.1)"]
949 | rtd = ["ipython", "myst-nb", "sphinx", "sphinx-book-theme", "sphinx-examples"]
950 |
951 | [[package]]
952 | name = "sphinxcontrib-applehelp"
953 | version = "2.0.0"
954 | description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books"
955 | optional = true
956 | python-versions = ">=3.9"
957 | groups = ["main"]
958 | markers = "extra == \"docs\""
959 | files = [
960 | {file = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"},
961 | {file = "sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1"},
962 | ]
963 |
964 | [package.extras]
965 | lint = ["mypy", "ruff (==0.5.5)", "types-docutils"]
966 | standalone = ["Sphinx (>=5)"]
967 | test = ["pytest"]
968 |
969 | [[package]]
970 | name = "sphinxcontrib-devhelp"
971 | version = "2.0.0"
972 | description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents"
973 | optional = true
974 | python-versions = ">=3.9"
975 | groups = ["main"]
976 | markers = "extra == \"docs\""
977 | files = [
978 | {file = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"},
979 | {file = "sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad"},
980 | ]
981 |
982 | [package.extras]
983 | lint = ["mypy", "ruff (==0.5.5)", "types-docutils"]
984 | standalone = ["Sphinx (>=5)"]
985 | test = ["pytest"]
986 |
987 | [[package]]
988 | name = "sphinxcontrib-htmlhelp"
989 | version = "2.1.0"
990 | description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files"
991 | optional = true
992 | python-versions = ">=3.9"
993 | groups = ["main"]
994 | markers = "extra == \"docs\""
995 | files = [
996 | {file = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"},
997 | {file = "sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9"},
998 | ]
999 |
1000 | [package.extras]
1001 | lint = ["mypy", "ruff (==0.5.5)", "types-docutils"]
1002 | standalone = ["Sphinx (>=5)"]
1003 | test = ["html5lib", "pytest"]
1004 |
1005 | [[package]]
1006 | name = "sphinxcontrib-jsmath"
1007 | version = "1.0.1"
1008 | description = "A sphinx extension which renders display math in HTML via JavaScript"
1009 | optional = true
1010 | python-versions = ">=3.5"
1011 | groups = ["main"]
1012 | markers = "extra == \"docs\""
1013 | files = [
1014 | {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"},
1015 | {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"},
1016 | ]
1017 |
1018 | [package.extras]
1019 | test = ["flake8", "mypy", "pytest"]
1020 |
1021 | [[package]]
1022 | name = "sphinxcontrib-qthelp"
1023 | version = "2.0.0"
1024 | description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents"
1025 | optional = true
1026 | python-versions = ">=3.9"
1027 | groups = ["main"]
1028 | markers = "extra == \"docs\""
1029 | files = [
1030 | {file = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"},
1031 | {file = "sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab"},
1032 | ]
1033 |
1034 | [package.extras]
1035 | lint = ["mypy", "ruff (==0.5.5)", "types-docutils"]
1036 | standalone = ["Sphinx (>=5)"]
1037 | test = ["defusedxml (>=0.7.1)", "pytest"]
1038 |
1039 | [[package]]
1040 | name = "sphinxcontrib-serializinghtml"
1041 | version = "2.0.0"
1042 | description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)"
1043 | optional = true
1044 | python-versions = ">=3.9"
1045 | groups = ["main"]
1046 | markers = "extra == \"docs\""
1047 | files = [
1048 | {file = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"},
1049 | {file = "sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d"},
1050 | ]
1051 |
1052 | [package.extras]
1053 | lint = ["mypy", "ruff (==0.5.5)", "types-docutils"]
1054 | standalone = ["Sphinx (>=5)"]
1055 | test = ["pytest"]
1056 |
1057 | [[package]]
1058 | name = "typing-extensions"
1059 | version = "4.14.1"
1060 | description = "Backported and Experimental Type Hints for Python 3.9+"
1061 | optional = true
1062 | python-versions = ">=3.9"
1063 | groups = ["main"]
1064 | markers = "extra == \"dev\" or extra == \"docs\""
1065 | files = [
1066 | {file = "typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76"},
1067 | {file = "typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36"},
1068 | ]
1069 |
1070 | [[package]]
1071 | name = "urllib3"
1072 | version = "2.5.0"
1073 | description = "HTTP library with thread-safe connection pooling, file post, and more."
1074 | optional = true
1075 | python-versions = ">=3.9"
1076 | groups = ["main"]
1077 | markers = "extra == \"docs\""
1078 | files = [
1079 | {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"},
1080 | {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"},
1081 | ]
1082 |
1083 | [package.extras]
1084 | brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""]
1085 | h2 = ["h2 (>=4,<5)"]
1086 | socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
1087 | zstd = ["zstandard (>=0.18.0)"]
1088 |
1089 | [extras]
1090 | dev = ["black", "mypy", "pytest"]
1091 | docs = ["Sphinx", "furo", "myst-parser", "sphinx-copybutton"]
1092 |
1093 | [metadata]
1094 | lock-version = "2.1"
1095 | python-versions = ">=3.13"
1096 | content-hash = "cc4318c524b06119a71b66467cc3bdae263897318d8bbd48a37cfc3b524f06eb"
1097 |
--------------------------------------------------------------------------------