diff --git a/.github/workflows/mkdocs.yml b/.github/workflows/mkdocs.yml
new file mode 100644
index 00000000..4425b36b
--- /dev/null
+++ b/.github/workflows/mkdocs.yml
@@ -0,0 +1,82 @@
+---
+name: MkDocs
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+permissions:
+ contents: write
+ pull-requests: write
+
+jobs:
+ deploy-docs:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Generate token
+ id: app-token
+ uses: actions/create-github-app-token@v1
+ with:
+ app-id: ${{ secrets.APP_ID }}
+ private-key: ${{ secrets.PRIVATE_KEY }}
+
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ token: "${{ steps.app-token.outputs.token }}"
+
+ # Make the github application be the committer
+ # (see: https://stackoverflow.com/a/74071223 on how to obtain the committer email)
+ - name: Setup git config
+ run: |
+ git config --global user.name "py-mine-ci-bot"
+ git config --global user.email "121461646+py-mine-ci-bot[bot]@users.noreply.github.com"
+
+ - name: Setup poetry
+ id: poetry_setup
+ uses: ItsDrike/setup-poetry@v1
+ with:
+ python-version: 3.12
+ install-args: "--only main,docs"
+
+ - name: Generate docs directory hash
+ run: |
+ docs_dir_hash="$(find "./docs" -type f -exec sha256sum {} + | sort | sha256sum | awk '{print $1}')"
+ echo "docs_dir_hash=$docs_hash" >> $GITHUB_ENV
+
+ - name: Restore MkDocs cache
+ uses: actions/cache@v4
+ with:
+ path: .cache
+ key:
+ "mkdocs-material-${{ steps.poetry_setup.outputs.python-version }}-\
+ ${{ hashFiles('./poetry.lock') }}-${{ hashFiles('./mkdocs.yml') }}-\
+ ${{ env.docs_dir_hash }}"
+ restore-keys: "mkdocs-material-${{ steps.poetry_setup.outputs.python-version }}-"
+
+ - name: Build the documentation
+ run: poetry run mkdocs build
+
+ - name: Deploy preview
+ if: ${{ github.event_name == 'pull_request' }}
+ uses: rossjrw/pr-preview-action@v1
+ with:
+ source-dir: ./site
+ preview-branch: gh-pages
+ umbrella-dir: pr-preview
+ token: ${{ steps.app-token.outputs.token }}
+
+ - name: Deploy production
+ if: ${{ github.event_name == 'push' }}
+ uses: JamesIves/github-pages-deploy-action@v4
+ with:
+ branch: gh-pages
+ folder: ./site
+ clean-exclude: pr-preview/
+ token: ${{ steps.app-token.outputs.token }}
diff --git a/.gitignore b/.gitignore
index 62b5097e..d5a2037f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,8 +20,8 @@ htmlcov/
.coverage*
coverage.xml
-# Sphinx documentation
-docs/_build/
+# Mkdocs documentation
+site/
# Pyenv local version information
.python-version
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
deleted file mode 100644
index 8b4835c6..00000000
--- a/.readthedocs.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-version: 2
-
-build:
- os: ubuntu-22.04
- tools:
- python: "3.12"
- jobs:
- post_create_environment:
- - python -m pip install poetry
- post_install:
- - VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH poetry install --only main,docs,docs-ci
- - poetry run poetry-dynamic-versioning
-
-sphinx:
- builder: dirhtml
- configuration: "docs/conf.py"
- fail_on_warning: true
diff --git a/docs/_static/extra.css b/docs/_static/extra.css
deleted file mode 100644
index f0373b0c..00000000
--- a/docs/_static/extra.css
+++ /dev/null
@@ -1,119 +0,0 @@
-html {
- word-wrap: anywhere;
-}
-
-body {
- --toc-item-spacing-horizontal: 0.5rem;
- --admonition-font-size: 0.8em;
-
- --attribute-table-title: var(--color-content-foreground);
- --attribute-table-entry-border: var(--color-foreground-border);
- --attribute-table-entry-text: var(--color-api-name);
- --attribute-table-entry-hover-border: var(--color-content-foreground);
- --attribute-table-entry-hover-background: var(--color-api-background-hover);
- --attribute-table-entry-hover-text: var(--color-content-foreground);
- --attribute-table-badge: var(--color-api-keyword);
-}
-
-.icon {
- user-select: none;
-}
-
-.viewcode-back {
- position: absolute;
- right: 1em;
- background-color: var(--color-code-background);
- width: auto;
-}
-
-.toc-drawer {
- width: initial;
- max-width: 20em;
- right: -20em;
-}
-
-.toc-tree ul ul ul ul {
- border-left: 1px solid var(--color-background-border);
-}
-
-@media (max-width: 82em) {
- body {
- font-size: 0.7em;
- }
-
- .toc-tree {
- padding-left: 0;
- }
-
- .sidebar-brand-text {
- font-size: 1rem;
- }
-
- .sidebar-tree .reference {
- padding: 0.5em 1em;
- }
-}
-
-/* attribute tables */
-.py-attribute-table {
- display: flex;
- flex-wrap: wrap;
- flex-direction: row;
- margin: 0 2em;
- padding-top: 16px;
-}
-
-.py-attribute-table-column {
- flex: 1 1 auto;
-}
-
-.py-attribute-table-column:not(:first-child) {
- margin-top: 1em;
-}
-
-.py-attribute-table-column > span {
- color: var(--attribute-table-title);
-}
-
-main .py-attribute-table-column > ul {
- list-style: none;
- margin: 4px 0px;
- padding-left: 0;
- font-size: 0.95em;
-}
-
-.py-attribute-table-entry {
- margin: 0;
- padding: 2px 0;
- padding-left: 0.2em;
- border-left: 2px solid var(--attribute-table-entry-border);
- display: flex;
- line-height: 1.2em;
-}
-
-.py-attribute-table-entry > a {
- padding-left: 0.5em;
- color: var(--attribute-table-entry-text);
- flex-grow: 1;
-}
-
-.py-attribute-table-entry > a:hover {
- color: var(--attribute-table-entry-hover-text);
- text-decoration: none;
-}
-
-.py-attribute-table-entry:hover {
- background-color: var(--attribute-table-entry-hover-background);
- border-left: 2px solid var(--attribute-table-entry-hover-border);
- text-decoration: none;
-}
-
-.py-attribute-table-badge {
- flex-basis: 3em;
- text-align: right;
- font-size: 0.9em;
- color: var(--attribute-table-badge);
- -moz-user-select: none;
- -webkit-user-select: none;
- user-select: none;
-}
diff --git a/docs/_static/extra.js b/docs/_static/extra.js
deleted file mode 100644
index 12fd8a08..00000000
--- a/docs/_static/extra.js
+++ /dev/null
@@ -1,13 +0,0 @@
-document.addEventListener("DOMContentLoaded", () => {
- const tables = document.querySelectorAll(
- ".py-attribute-table[data-move-to-id]"
- );
- tables.forEach((table) => {
- let element = document.getElementById(
- table.getAttribute("data-move-to-id")
- );
- let parent = element.parentNode;
- // insert ourselves after the element
- parent.insertBefore(table, element.nextSibling);
- });
-});
diff --git a/docs/api/basic.rst b/docs/api/basic.rst
deleted file mode 100644
index c68e0204..00000000
--- a/docs/api/basic.rst
+++ /dev/null
@@ -1,5 +0,0 @@
-Basic Usage
-===========
-
-..
- TODO: Write this
diff --git a/docs/api/internal.rst b/docs/api/internal.rst
deleted file mode 100644
index 7a8e0745..00000000
--- a/docs/api/internal.rst
+++ /dev/null
@@ -1,14 +0,0 @@
-Internal API
-============
-
-Everything listed on this page is considered internal, and is only present to provide linkable references, and
-as an easy quick reference for contributors. These components **are not a part of the public API** and **they
-should not be used externally**, as we do not guarantee their backwards compatibility, which means breaking changes
-may be introduced between patch versions without any warnings.
-
-.. automodule:: mcproto.utils.abc
- :exclude-members: define
-
-.. autofunction:: tests.helpers.gen_serializable_test
-..
- TODO: Write this
diff --git a/docs/api/packets.rst b/docs/api/packets.rst
deleted file mode 100644
index 5c2d1a55..00000000
--- a/docs/api/packets.rst
+++ /dev/null
@@ -1,45 +0,0 @@
-Packets documentation
-=====================
-
-Base classes and interaction functions
---------------------------------------
-
-.. automodule:: mcproto.packets
- :members:
- :undoc-members:
- :show-inheritance:
-
-
-Handshaking gamestate
----------------------
-
-.. automodule:: mcproto.packets.handshaking.handshake
- :members:
- :undoc-members:
- :show-inheritance:
-
-Status gamestate
-----------------
-
-.. automodule:: mcproto.packets.status.ping
- :members:
- :undoc-members:
- :show-inheritance:
-
-.. automodule:: mcproto.packets.status.status
- :members:
- :undoc-members:
- :show-inheritance:
-
-Login gamestate
----------------
-
-.. automodule:: mcproto.packets.login.login
- :members:
- :undoc-members:
- :show-inheritance:
-
-Play gamestate
---------------
-
-Not yet implemented
diff --git a/docs/api/protocol.rst b/docs/api/protocol.rst
deleted file mode 100644
index 92fea8d9..00000000
--- a/docs/api/protocol.rst
+++ /dev/null
@@ -1,24 +0,0 @@
-Protocol documentation
-======================
-
-This is the documentation for methods minecraft protocol interactions, connection and buffer.
-
-
-.. attributetable:: mcproto.protocol.base_io.BaseAsyncReader
-
-.. attributetable:: mcproto.protocol.base_io.BaseSyncReader
-
-.. automodule:: mcproto.protocol.base_io
- :members:
- :undoc-members:
- :show-inheritance:
-
-.. autoclass:: mcproto.buffer.Buffer
- :members:
- :undoc-members:
- :show-inheritance:
-
-.. automodule:: mcproto.connection
- :members:
- :undoc-members:
- :show-inheritance:
diff --git a/docs/api/types/index.rst b/docs/api/types/index.rst
deleted file mode 100644
index f17972a8..00000000
--- a/docs/api/types/index.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-.. api/types documentation master file
-
-=======================
-API Types Documentation
-=======================
-
-Welcome to the API Types documentation! This documentation provides information about the various types used in the API.
-
-.. toctree::
- :maxdepth: 2
-
- nbt.rst
diff --git a/docs/api/types/nbt.rst b/docs/api/types/nbt.rst
deleted file mode 100644
index e2a4398b..00000000
--- a/docs/api/types/nbt.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-NBT Format
-==========
-
-.. automodule:: mcproto.types.nbt
- :members:
- :show-inheritance:
diff --git a/docs/assets/py-mine_logo.png b/docs/assets/py-mine_logo.png
new file mode 100644
index 00000000..5e2af94e
Binary files /dev/null and b/docs/assets/py-mine_logo.png differ
diff --git a/docs/conf.py b/docs/conf.py
deleted file mode 100644
index 297169d3..00000000
--- a/docs/conf.py
+++ /dev/null
@@ -1,223 +0,0 @@
-"""Configuration file for the Sphinx documentation builder.
-
-For the full list of built-in configuration values, see the documentation:
-https://www.sphinx-doc.org/en/master/usage/configuration.html
-
-# -- Project information -----------------------------------------------------
-# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
-"""
-
-from __future__ import annotations
-
-import datetime
-import sys
-from pathlib import Path
-
-from packaging.version import parse as parse_version
-from typing_extensions import override
-
-if sys.version_info >= (3, 11):
- from tomllib import load as toml_parse
-else:
- from tomli import load as toml_parse
-
-
-# -- Basic project information -----------------------------------------------
-
-with Path("../pyproject.toml").open("rb") as f:
- pkg_meta: dict[str, str] = toml_parse(f)["tool"]["poetry"]
-
-project = str(pkg_meta["name"])
-copyright = f"{datetime.datetime.now(tz=datetime.timezone.utc).date().year}, ItsDrike" # noqa: A001
-author = "ItsDrike"
-
-parsed_version = parse_version(pkg_meta["version"])
-release = str(parsed_version)
-
-# -- General configuration ---------------------------------------------------
-# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
-
-# Add docs/extensions into python path, allowing custom internal sphinx extensions
-# these will now be essentially considered as regualar packages
-sys.path.append(str(Path(__file__).parent.joinpath("extensions").absolute()))
-
-extensions = [
- # official extensions
- "sphinx.ext.autodoc", # Automatic documentation generation
- "sphinx.ext.autosectionlabel", # Allows referring to sections by their title
- "sphinx.ext.extlinks", # Shorten common link patterns
- "sphinx.ext.intersphinx", # Used to reference for third party projects:
- "sphinx.ext.todo", # Adds todo directive
- "sphinx.ext.viewcode", # Links to source files for the documented functions
- # external
- "sphinxcontrib.towncrier.ext", # Towncrier changelog
- "m2r2", # Used to include .md files:
- "sphinx_copybutton", # Copyable codeblocks
- # internal
- "attributetable", # adds attributetable directive, for producing list of methods and attributes of class
-]
-
-# The suffix(es) of source filenames.
-source_suffix = [".rst", ".md"]
-
-# The master toctree document.
-master_doc = "index"
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-#
-# This is also used if you do content translation via gettext catalogs.
-# Usually you set "language" from the command line for these cases.
-language = "en"
-
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-exclude_patterns = ["_build"]
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = "sphinx"
-
-# -- Options for HTML output -------------------------------------------------
-# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
-
-html_theme = "furo"
-html_favicon = "https://i.imgur.com/nPCcxts.png"
-
-html_static_path = ["_static"]
-html_css_files = ["extra.css"]
-html_js_files = ["extra.js"]
-
-# -- Extension configuration -------------------------------------------------
-
-# -- sphinx.ext.autodoc ------------------------
-
-# What docstring to insert into main body of autoclass
-# "class" / "init" / "both"
-autoclass_content = "both"
-
-# Sort order of the automatically documented members
-autodoc_member_order = "bysource"
-
-# Default options for all autodoc directives
-autodoc_default_options = {
- "members": True,
- "undoc-members": True,
- "show-inheritance": True,
- "exclude-members": "__dict__,__weakref__",
-}
-
-# -- sphinx.ext.autosectionlabel ---------------
-
-# Automatically generate section labels:
-autosectionlabel_prefix_document = True
-
-# -- sphinx.ext.extlinks -----------------------
-
-# will create new role, allowing for example :issue:`123`
-extlinks = {
- # role: (URL with %s, caption or None)
- "issue": ("https://github.com/py-mine/mcproto/issues/%s", "GH-%s"),
-}
-
-# -- sphinx.ext.intersphinx --------------------
-
-# Third-party projects documentation references:
-intersphinx_mapping = {
- "python": ("https://docs.python.org/3", None),
-}
-
-# -- sphinx.ext.todo ---------------------------
-
-# If true, `todo` and `todoList` produce output, else they produce nothing.
-todo_include_todos = True
-
-# -- sphinxcontrib.towncrier.ext ---------------
-
-towncrier_draft_autoversion_mode = "draft"
-towncrier_draft_include_empty = True
-towncrier_draft_working_directory = Path(__file__).parents[1].resolve()
-
-# -- m2r2 --------------------------------------
-
-# Enable multiple references to the same URL for m2r2
-m2r_anonymous_references = True
-
-# Changelog contains a lot of duplicate labels, since every subheading holds a category
-# and these repeat a lot. Currently, m2r2 doesn't handle this properly, and so these
-# labels end up duplicated. See: https://github.com/CrossNox/m2r2/issues/59
-suppress_warnings = [
- "autosectionlabel.pages/changelog",
- "autosectionlabel.pages/code-of-conduct",
- "autosectionlabel.pages/contributing",
-]
-
-# -- Other options -----------------------------------------------------------
-
-
-def mock_autodoc() -> None:
- """Mock autodoc to not add ``Bases: object`` to the classes, that do not have super classes.
-
- See also https://stackoverflow.com/a/75041544/20952782.
- """
- from sphinx.ext import autodoc
-
- class MockedClassDocumenter(autodoc.ClassDocumenter):
- @override
- def add_line(self, line: str, source: str, *lineno: int) -> None:
- if line == " Bases: :py:class:`object`":
- return
- super().add_line(line, source, *lineno)
-
- autodoc.ClassDocumenter = MockedClassDocumenter
-
-
-def override_towncrier_draft_format() -> None:
- """Monkeypatch sphinxcontrib.towncrier.ext to first convert the draft text from md to rst.
-
- We can use ``m2r2`` for this, as it's an already installed extension with goal
- of including markdown documents into rst documents, so we simply run it's converter
- somewhere within sphinxcontrib.towncrier.ext and include this conversion.
-
- Additionally, the current changelog format always starts the version with "Version {}",
- this doesn't look well with the version set to "Unreleased changes", so this function
- also removes this "Version " prefix.
- """
- import m2r2
- import sphinxcontrib.towncrier.ext
- from docutils import statemachine
- from sphinx.util.nodes import nodes
-
- orig_f = sphinxcontrib.towncrier.ext._nodes_from_document_markup_source
-
- def override_f(
- state: statemachine.State,
- markup_source: str,
- ) -> list[nodes.Node]:
- markup_source = markup_source.replace("## Version Unreleased changes", "## Unreleased changes")
- markup_source = markup_source.rstrip(" \n")
-
- # Alternative to 3.9+ str.removesuffix
- if markup_source.endswith("---"):
- markup_source = markup_source[:-3]
-
- markup_source = markup_source.rstrip(" \n")
- markup_source = m2r2.M2R()(markup_source)
-
- return orig_f(state, markup_source)
-
- sphinxcontrib.towncrier.ext._nodes_from_document_markup_source = override_f
-
-
-mock_autodoc()
-override_towncrier_draft_format()
diff --git a/docs/examples/index.rst b/docs/examples/index.rst
deleted file mode 100644
index 09ef2452..00000000
--- a/docs/examples/index.rst
+++ /dev/null
@@ -1,13 +0,0 @@
-Examples
-========
-
-Here are some examples of using the project in practice.
-
-
-.. toctree::
- :maxdepth: 1
- :caption: Examples
-
- status.rst
-
-Feel free to propose any further examples, we'll be happy to add them to the list!
diff --git a/docs/examples/status.rst b/docs/examples/status.rst
deleted file mode 100644
index e9c37997..00000000
--- a/docs/examples/status.rst
+++ /dev/null
@@ -1,5 +0,0 @@
-Obtaining status data from a server
-===================================
-
-..
- TODO: Write this
diff --git a/docs/extensions/attributetable.py b/docs/extensions/attributetable.py
deleted file mode 100644
index 99740fdf..00000000
--- a/docs/extensions/attributetable.py
+++ /dev/null
@@ -1,295 +0,0 @@
-from __future__ import annotations
-
-import importlib
-import inspect
-import re
-from collections.abc import Sequence
-from typing import NamedTuple
-
-from docutils import nodes
-from sphinx import addnodes
-from sphinx.application import Sphinx
-from sphinx.environment import BuildEnvironment
-from sphinx.locale import _ as translate
-from sphinx.util.docutils import SphinxDirective
-from sphinx.util.typing import OptionSpec
-from sphinx.writers.html5 import HTML5Translator
-from typing_extensions import override
-
-
-class AttributeTable(nodes.General, nodes.Element):
- pass
-
-
-class AttributeTableColumn(nodes.General, nodes.Element):
- pass
-
-
-class AttributeTableTitle(nodes.TextElement):
- pass
-
-
-class AttributeTablePlaceholder(nodes.General, nodes.Element):
- pass
-
-
-class AttributeTableBadge(nodes.TextElement):
- pass
-
-
-class AttributeTableItem(nodes.Part, nodes.Element):
- pass
-
-
-def visit_attributetable_node(self: HTML5Translator, node: AttributeTable) -> None:
- class_ = node["python-class"]
- self.body.append(f'
')
-
-
-def visit_attributetablecolumn_node(self: HTML5Translator, node: AttributeTableColumn) -> None:
- self.body.append(self.starttag(node, "div", CLASS="py-attribute-table-column"))
-
-
-def visit_attributetabletitle_node(self: HTML5Translator, node: AttributeTableTitle) -> None:
- self.body.append(self.starttag(node, "span"))
-
-
-def visit_attributetablebadge_node(self: HTML5Translator, node: AttributeTableBadge) -> None:
- attributes = {
- "class": "py-attribute-table-badge",
- "title": node["badge-type"],
- }
- self.body.append(self.starttag(node, "span", **attributes))
-
-
-def visit_attributetable_item_node(self: HTML5Translator, node: AttributeTableItem) -> None:
- self.body.append(self.starttag(node, "li", CLASS="py-attribute-table-entry"))
-
-
-def depart_attributetable_node(self: HTML5Translator, node: AttributeTable) -> None:
- self.body.append("
")
-
-
-def depart_attributetablecolumn_node(self: HTML5Translator, node: AttributeTableColumn) -> None:
- self.body.append("")
-
-
-def depart_attributetabletitle_node(self: HTML5Translator, node: AttributeTableTitle) -> None:
- self.body.append("")
-
-
-def depart_attributetablebadge_node(self: HTML5Translator, node: AttributeTableBadge) -> None:
- self.body.append("")
-
-
-def depart_attributetable_item_node(self: HTML5Translator, node: AttributeTableItem) -> None:
- self.body.append("")
-
-
-_name_parser_regex = re.compile(r"(?P[\w.]+\.)?(?P\w+)")
-
-
-class PyAttributeTable(SphinxDirective):
- has_content = False
- required_arguments = 1
- optional_arguments = 0
- final_argument_whitespace = False
- option_spec: OptionSpec = {} # type: ignore # noqa: RUF012 # (from original impl)
-
- def parse_name(self, content: str) -> tuple[str, str]:
- match = _name_parser_regex.match(content)
- if match is None:
- raise RuntimeError(f"content {content} somehow doesn't match regex in {self.env.docname}.")
- path, name = match.groups()
- if path:
- modulename = path.rstrip(".")
- else:
- modulename = self.env.temp_data.get("autodoc:module")
- if not modulename:
- modulename = self.env.ref_context.get("py:module")
- if modulename is None:
- raise RuntimeError(f"modulename somehow None for {content} in {self.env.docname}.")
-
- return modulename, name
-
- @override
- def run(self) -> list[AttributeTablePlaceholder]:
- """If you're curious on the HTML this is meant to generate:
-
-
-
-
translate('Attributes')
-
-
-
-
translate('Methods')
-
-
-
-
- However, since this requires the tree to be complete
- and parsed, it'll need to be done at a different stage and then
- replaced.
- """
- content = self.arguments[0].strip()
- node = AttributeTablePlaceholder("")
- modulename, name = self.parse_name(content)
- node["python-doc"] = self.env.docname
- node["python-module"] = modulename
- node["python-class"] = name
- node["python-full-name"] = f"{modulename}.{name}"
- return [node]
-
-
-def build_lookup_table(env: BuildEnvironment) -> dict[str, list[str]]:
- # Given an environment, load up a lookup table of
- # full-class-name: objects
- result = {}
- domain = env.domains["py"]
-
- ignored = {
- "data",
- "exception",
- "module",
- "class",
- }
-
- for fullname, _, objtype, _, _, _ in domain.get_objects():
- if objtype in ignored:
- continue
-
- classname, _, child = fullname.rpartition(".")
- try:
- result[classname].append(child)
- except KeyError:
- result[classname] = [child]
-
- return result
-
-
-class TableElement(NamedTuple):
- fullname: str
- label: str
- badge: AttributeTableBadge | None
-
-
-def process_attributetable(app: Sphinx, doctree: nodes.Node, fromdocname: str) -> None:
- env = app.builder.env
-
- lookup = build_lookup_table(env)
- for node in doctree.traverse(AttributeTablePlaceholder):
- modulename, classname, fullname = node["python-module"], node["python-class"], node["python-full-name"]
- groups = get_class_results(lookup, modulename, classname, fullname)
- table = AttributeTable("")
- for label, subitems in groups.items():
- if not subitems:
- continue
- table.append(class_results_to_node(label, sorted(subitems, key=lambda c: c.label)))
-
- table["python-class"] = fullname
-
- if not table:
- node.replace_self([])
- else:
- node.replace_self([table])
-
-
-def get_class_results(
- lookup: dict[str, list[str]], modulename: str, name: str, fullname: str
-) -> dict[str, list[TableElement]]:
- module = importlib.import_module(modulename)
- cls = getattr(module, name)
-
- groups: dict[str, list[TableElement]] = {
- translate("Attributes"): [],
- translate("Methods"): [],
- }
-
- try:
- members = lookup[fullname]
- except KeyError:
- return groups
-
- for attr in members:
- attrlookup = f"{fullname}.{attr}"
- key = translate("Attributes")
- badge = None
- label = attr
- value = None
-
- for base in cls.__mro__:
- value = base.__dict__.get(attr)
- if value is not None:
- break
-
- if value is not None:
- doc = value.__doc__ or ""
- if inspect.iscoroutinefunction(value) or doc.startswith("|coro|"):
- key = translate("Methods")
- badge = AttributeTableBadge("async", "async")
- badge["badge-type"] = translate("coroutine")
- elif isinstance(value, classmethod):
- key = translate("Methods")
- label = f"{name}.{attr}"
- badge = AttributeTableBadge("cls", "cls")
- badge["badge-type"] = translate("classmethod")
- elif inspect.isfunction(value):
- if doc.startswith(("A decorator", "A shortcut decorator")):
- # finicky but surprisingly consistent
- key = translate("Methods")
- badge = AttributeTableBadge("@", "@")
- badge["badge-type"] = translate("decorator")
- elif inspect.isasyncgenfunction(value):
- key = translate("Methods")
- badge = AttributeTableBadge("async for", "async for")
- badge["badge-type"] = translate("async iterable")
- else:
- key = translate("Methods")
- badge = AttributeTableBadge("def", "def")
- badge["badge-type"] = translate("method")
-
- groups[key].append(TableElement(fullname=attrlookup, label=label, badge=badge))
-
- return groups
-
-
-def class_results_to_node(key: str, elements: Sequence[TableElement]) -> AttributeTableColumn:
- title = AttributeTableTitle(key, key)
- ul = nodes.bullet_list("")
- for element in elements:
- ref = nodes.reference(
- "",
- "",
- internal=True,
- refuri=f"#{element.fullname}",
- anchorname="",
- *[nodes.Text(element.label)], # noqa: B026 # (from original impl)
- )
- para = addnodes.compact_paragraph("", "", ref)
- if element.badge is not None:
- ul.append(AttributeTableItem("", element.badge, para))
- else:
- ul.append(AttributeTableItem("", para))
-
- return AttributeTableColumn("", title, ul)
-
-
-def setup(app: Sphinx) -> dict:
- app.add_directive("attributetable", PyAttributeTable)
- app.add_node(AttributeTable, html=(visit_attributetable_node, depart_attributetable_node))
- app.add_node(AttributeTableColumn, html=(visit_attributetablecolumn_node, depart_attributetablecolumn_node))
- app.add_node(AttributeTableTitle, html=(visit_attributetabletitle_node, depart_attributetabletitle_node))
- app.add_node(AttributeTableBadge, html=(visit_attributetablebadge_node, depart_attributetablebadge_node))
- app.add_node(AttributeTableItem, html=(visit_attributetable_item_node, depart_attributetable_item_node))
- app.add_node(AttributeTablePlaceholder)
- app.connect("doctree-resolved", process_attributetable)
- return {"parallel_read_safe": True}
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 00000000..d6ea06c3
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,82 @@
+---
+hide:
+ - navigation
+---
+
+
+
+# Home
+
+
+
+ MCPROTO
+
+
+## What is Mcproto
+
+Mcproto is a python library that provides various low level interactions with the minecraft protocol. It attempts to be
+a full wrapper around the minecraft protocol, which means it could be used as a basis for minecraft bots written in
+python, or even full python server implementations.
+
+!!! warning
+
+ This library is still heavily Work-In-Progress, which means a lot of things can still change and some features may
+ be missing or incomplete. Using the library for production applications at it's current state isn't recommended.
+
+## Installation
+
+### PyPI (stable) version
+
+Mcproto is available on [PyPI](https://pypi.org/project/mcproto) and can be installed like any other python library with:
+
+=== "pip"
+
+ ```bash
+ pip install mcproto
+ ```
+
+=== "poetry"
+
+ ```bash
+ poetry add mcproto
+ ```
+
+=== "rye"
+
+ ```bash
+ rye add mcproto
+ ```
+
+### Latest (git) version
+
+Alternatively, you may want to install the latest available version, which is what you currently see in the `main` git
+branch. Although this method will actually work for any branch with a pretty straightforward change.
+
+This kind of installation should only be done if you wish to test some new unreleased features and it's likely that you
+will encounter bugs.
+
+That said, since mcproto is still in development, changes can often be made quickly and it can sometimes take a while
+for these changes to carry over to PyPI. So if you really want to try out that latest feature, this is the method
+you'll want.
+
+To install the latest mcproto version directly from the `main` git branch, use:
+
+=== "pip"
+
+ ```bash
+ pip install 'mcproto@git+https://github.com/py-mine/mcproto@main'
+ ```
+
+=== "poetry"
+
+ ```bash
+ poetry add 'git+https://github.com/py-mine/mcproto#main'
+ ```
+
+=== "rye"
+
+ ```bash
+ rye add mcproto --git='https://github.com/py-mine/mcproto' --branch main
+ ```
diff --git a/docs/index.rst b/docs/index.rst
deleted file mode 100644
index 18170ab2..00000000
--- a/docs/index.rst
+++ /dev/null
@@ -1,35 +0,0 @@
-.. mdinclude:: ../README.md
-
-Content
--------
-
-.. toctree::
- :maxdepth: 1
- :caption: Pages
-
- pages/installation.rst
- usage/index.rst
- examples/index.rst
- pages/faq.rst
- pages/changelog.rst
- pages/version_guarantees.rst
- pages/contributing.rst
- pages/code-of-conduct.rst
-
-.. toctree::
- :maxdepth: 1
- :caption: API Documentation
-
- api/basic.rst
- api/packets.rst
- api/protocol.rst
- api/internal.rst
- api/types/index.rst
-
-
-Indices and tables
-------------------
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
diff --git a/docs/pages/changelog.rst b/docs/pages/changelog.rst
deleted file mode 100644
index 68f630ee..00000000
--- a/docs/pages/changelog.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-Changelog
-=========
-
-.. seealso::
- Check out what can and can't change between the library versions. :doc:`version_guarantees`
-
-.. attention::
- Major and minor releases also include the changes specified in prior development releases.
-
-.. towncrier-draft-entries:: Unreleased changes
-
-.. mdinclude:: ../../CHANGELOG.md
diff --git a/docs/pages/code-of-conduct.rst b/docs/pages/code-of-conduct.rst
deleted file mode 100644
index 20161955..00000000
--- a/docs/pages/code-of-conduct.rst
+++ /dev/null
@@ -1,159 +0,0 @@
-Code of Conduct
-===============
-
-This code of conduct outlines our expectations for the people involved with this project. We, as members, contributors
-and leaders are committed to providing a welcoming and inspiring project that anyone can easily join, expecting
-a harassment-free experience, as described in this code of conduct.
-
-This code of conduct is here to ensure we provide a welcoming and inspiring project that anyone can easily join,
-expecting a harassment-free experience, as described in this code of conduct.
-
-The goal of this document is to set the overall tone for our community. It is here to outline some of the things you
-can and can't do if you wish to participate in our community. However it is not here to serve as a rule-book with
-a complete set of things you can't do, social conduct differs from situation to situation, and person to person, but we
-should do our best to try and provide a good experience to everyone, in every situation.
-
-We value many things beyond just technical expertise, including collaboration and supporting others within our
-community. Providing a positive experience for others can have a much more significant impact than simply providing the
-correct answer.
-
-Harassment
-----------
-
-We share a common understanding of what constitutes harassment as it applies to a professional setting. Although this
-list cannot be exhaustive, we explicitly honor diversity in age, gender, culture, ethnicity, language, national origin,
-political beliefs, profession, race, religion, sexual orientation, socioeconomic status, disability and personal
-appearance. We will not tolerate discrimination based on any of the protected characteristics above, including some
-that may not have been explicitly mentioned here. We consider discrimination of any kind to be unacceptable and
-immoral.
-
-Harassment includes, but is not limited to:
-
-* Offensive comments (or "jokes") related to any of the above mentioned attributes.
-* Deliberate "outing"/"doxing" of any aspect of a person's identity, such as physical or electronic address, without
- their explicit consent, except as necessary to protect others from intentional abuse.
-* Unwelcome comments regarding a person's lifestyle choices and practices, including those related to food, health,
- parenting, drugs and employment.
-* Deliberate misgendering. This includes deadnaming or persistently using a pronoun that does not correctly reflect a
- person's gender identity. You must address people by the name they give you when not addressing them by their
- username or handle.
-* Threats of violence, both physical and psychological.
-* Incitement of violence towards any individual, including encouraging a person to engage in self-harm.
-* Publication of non-harassing private communication.
-* Pattern of inappropriate social conduct, such as requesting/assuming inappropriate levels of intimacy with others, or
- excessive teasing after a request to stop.
-* Continued one-on-one communication after requests to cease.
-* Sabotage of someone else's work or intentionally hindering someone else's performance.
-
-Plagiarism
-----------
-
-Plagiarism is the re-use of someone else's work (eg: binary content such as images, textual content such as an article,
-but also source code, or any other copyrightable resources) without the permission or license right from the author.
-Claiming someone else's work as your own is not just immoral and disrespectful to the author, but also illegal in most
-countries. You should always follow the authors wishes, and give credit where credit is due.
-
-If we found that you've **intentionally** attempted to add plagiarized content to our code-base, you will likely end up
-being permanently banned from any future contributions to this project's repository. We will of course also do our best
-to remove, or properly attribute this plagiarized content as quickly as possible.
-
-An unintentional attempt at plagiarism will not be punished as harshly, but nevertheless, it is your responsibility as
-a contributor to check where the code you're submitting comes from, and so repeated submission of such content, even
-after you were warned might still get you banned.
-
-Please note that an online repository that has no license is presumed to only be source-available, NOT open-source.
-Meaning that this work is protected by author's copyright, automatically imposed over it, and without any license
-extending that copyright, you have no rights to use such code. So know that you can't simply take some source-code,
-even though it's published publicly. This code may be available to be seen by anyone, but that does not mean it's also
-available to be used by anyone in other projects.
-
-Another important note to keep in mind is that even if some project has an open-source license, that license may have
-conditions which are incompatible with our codebase (such as requiring all of the code that links to this new part to
-also be licensed under the same license, which our code-base is not currently under). That is why it's necessary to
-understand a license before using code available under it. Simple attribution often isn't everything that the license
-requires.
-
-Generally inappropriate behavior
---------------------------------
-
-Outside of just harassment and plagiarism, there are countless other behaviors which we consider unacceptable, as they
-may be offensive, and discourage people from engaging with our community.
-
-**Examples of generally inappropriate behavior:**
-
-* The use of sexualized language or imagery of any kind
-* The use of inappropriate images, including in an account's avatar
-* The use of inappropriate language, including in an account's nickname
-* Any spamming, flamming, baiting or other attention-stealing behavior
-* Discussing topics that are overly polarizing, sensitive, or incite arguments.
-* Responding with "RTFM", "just google it" or similar response to help requests
-* Other conduct which could be reasonably considered inappropriate
-
-**Examples of generally appropriate behavior:**
-
-* Being kind and courteous to others
-* Collaborating with other community members
-* Gracefully accepting constructive criticism
-* Using welcoming and inclusive language
-* Showing empathy towards other community members
-
-Scope
------
-
-This Code of Conduct applies within all community spaces, including this repository itself, conversations on any
-platforms officially connected to this project (such as in GitHub issues, through official emails or applications like
-discord). It also applies when an individual is officially representing the community in public spaces. Examples of
-representing our community include using an official social media account, or acting as an appointed representative at
-an online or offline event.
-
-All members involved with the project are expected to follow this Code of Conduct, no matter their position in the
-project's hierarchy, this Code of Conduct applies equally to contributors, maintainers, people seeking help/reporting
-bugs, etc.
-
-Enforcement Responsibilities
-----------------------------
-
-Whenever a participant has made a mistake, we expect them to take responsibility for their actions. If someone has been
-harmed or offended, it is our responsibility to listen carefully and respectfully, and to do our best to right the
-wrong.
-
-Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take
-appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening,
-offensive, harmful, or otherwise undesirable.
-
-Community leaders have the right and responsibility to remove, edit or reject comments, commits, code, wiki edits,
-issues and other contributions within the enforcement scope that are not aligned to this Code of Conduct, and will
-communicate reasons for moderation decisions when appropriate.
-
-If you have experienced or witnessed unacceptable behavior constituting a code of conduct violation or have any other
-code of conduct concerns, please let us know and we will do our best to resolve this issue.
-
-Reporting a Code of Conduct violation
--------------------------------------
-
-If you saw someone violating the Code of Conduct in some way, you can report it to any repository maintainer, either by
-email or through a Discord DM. You should avoid using public channels for reporting these, and instead do so in private
-discussion with a maintainer.
-
-Sources
--------
-
-The open-source community has an incredible amount of resources that people have freely provided to others and we all
-depend on these projects in many ways. This code of conduct article is no exception and there were many open source
-projects that has helped bring this code of conduct to existence. For that reason, we'd like to thank all of these
-communities and projects for keeping their content open and available to everyone, but most notably we'd like to thank
-the projects with established codes of conduct and diversity statements that we used as our inspiration. Below is the
-list these projects:
-
-* `Python `_
-* `Contributor Covenant `_
-* `Rust-lang `_
-* `Code Fellows `_
-* `Python Discord `_
-
-License
--------
-
-All content of this page is licensed under a Creative Commons Attributions license.
-
-For more information about this license, see:
diff --git a/docs/pages/contributing.rst b/docs/pages/contributing.rst
deleted file mode 100644
index 1c554637..00000000
--- a/docs/pages/contributing.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-Contributing Guidelines
-=======================
-
-.. mdinclude:: ../../CONTRIBUTING.md
- :start-line: 2
-
-..
- TODO: Rewrite CONTRIBUTING.md here directly, rather than including it
- like this, and just include a link to the docs in CONTRIBUTING.md
diff --git a/docs/pages/faq.rst b/docs/pages/faq.rst
deleted file mode 100644
index cb73d06a..00000000
--- a/docs/pages/faq.rst
+++ /dev/null
@@ -1,21 +0,0 @@
-Frequently Asked Questions
-==========================
-
-.. note::
- This page is still being worked on, if you have any suggestions for a question, feel free to create an issue on
- GitHub, or let us know on the development discord server.
-
-Missing synchronous alternatives for some functions
----------------------------------------------------
-
-While mcproto does provide synchronous functionalities for the general protocol interactions (reading/writing packets
-and lower level structures), any unrelated functionalities (such as HTTP interactions with the Minecraft API) will only
-provide asynchronous versions.
-
-This was done to reduce the burden of maintaining 2 versions of the same code. The only reason protocol intercation
-even have synchronous support is because it's needed in the :class:`~mcproto.buffer.Buffer` class. (See `Issue #128
-`_ for more details on this decision.)
-
-Generally, we recommend that you just stick to using the asynchronous alternatives though, both since some functions
-only support async, and because async will generally provide you with a more scalable codebase, making it much easier
-to handle multiple things concurrently.
diff --git a/docs/pages/installation.rst b/docs/pages/installation.rst
deleted file mode 100644
index 3515936b..00000000
--- a/docs/pages/installation.rst
+++ /dev/null
@@ -1,28 +0,0 @@
-Installation
-============
-
-PyPI (stable) version
----------------------
-
-Mcproto is available on `PyPI `_, and can be installed trivially with:
-
-.. code-block:: bash
-
- python3 -m pip install mcproto
-
-This will install the latest stable (released) version. This is generally what you'll want to do.
-
-Latest (git) version
---------------------
-
-Alternatively, you may want to install the latest available version, which is what you currently see in the ``main``
-git branch. Although this method will actually work for any branch with a pretty straightforward change. This kind of
-installation should only be done when testing new feautes, and it's likely you'll encounter bugs.
-
-That said, since mcproto is still in development, changes can often be made pretty quickly, and it can sometimes take a
-while for these changes to carry over to PyPI. So if you really want to try out that latest feature, this is the method
-you'll want.
-
-.. code-block:: bash
-
- python3 -m pip install 'mcproto@git+https://github.com/py-mine/mcproto@main'
diff --git a/docs/pages/version_guarantees.rst b/docs/pages/version_guarantees.rst
deleted file mode 100644
index d530fa86..00000000
--- a/docs/pages/version_guarantees.rst
+++ /dev/null
@@ -1,38 +0,0 @@
-Version Guarantees
-==================
-
-.. attention::
- Mcproto is currently in the pre-release phase (pre v1.0.0). During this phase, these guarantees will NOT be
- followed! This means that **breaking changes can occur in minor version bumps**, though micro version bumps are
- still strictly for bugfixes, and will not include any features or breaking changes.
-
-This library follows `semantic versioning model `_, which means the major version is updated every
-time there is an incompatible (breaking) change made to the public API. However due to the fairly dynamic nature of
-Python, it can be hard to discern what can be considered a breaking change, and what isn't.
-
-First thing to keep in mind is that breaking changes only apply to **publicly documented functions and classes**. If
-it's not listed in the documentation here, it's an internal feature, that isn't considered a part of the public API,
-and thus is bound to change. This includes documented attributes that start with an underscore.
-
-.. note::
- The examples below are non-exhaustive.
-
-Examples of Breaking Changes
-----------------------------
-
-* Changing the default parameter value of a function to something else.
-* Renaming (or removing) a function without an alias to the old function.
-* Adding or removing parameters of a function.
-* Removing deprecated alias to a renamed function
-
-Examples of Non-Breaking Changes
---------------------------------
-
-* Changing function's name, while providing a deprecated alias.
-* Renaming (or removing) private underscored attributes.
-* Adding an element into `__slots__` of a data class.
-* Changing the behavior of a function to fix a bug.
-* Changes in the typing behavior of the library.
-* Changes in the documentation.
-* Modifying the internal protocol connection handling.
-* Updating the dependencies to a newer version, major or otherwise.
diff --git a/docs/usage/authentication.rst b/docs/usage/authentication.rst
deleted file mode 100644
index 6adb328f..00000000
--- a/docs/usage/authentication.rst
+++ /dev/null
@@ -1,268 +0,0 @@
-Minecraft account authentication
-================================
-
-Mcproto has first party support to handle authentication, allowing you to use your own minecraft account. This is
-needed if you wish to login to "online mode" (non-warez) servers as a client (player).
-
-Microsoft (migrated) accounts
------------------------------
-
-This is how authentication works for already migrated minecraft accounts, using Microsoft accounts for authentication.
-(This will be most accounts. Any newly created minecraft accounts - after 2021 will always be Microsoft linked accounts.)
-
-Creating Azure application
-^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-To authenticate with a microsoft account, you will need to go through the entire OAuth2 flow. Mcproto has functions to
-hide pretty much all of this away, however you will need to create a new Microsoft Azure application, that mcproto will
-use to obtain an access token.
-
-We know this is annoying, but it's a necessary step, as Microsoft only allows these applications to request OAuth2
-authentication, and to avoid potential abuse, we can't really just use our registered application (like with say
-`MultiMC `_), as this token would have to be embedded into our source-code, and
-since this is python, that would mean just including it here in plain text, and because mcproto is a low level library
-that can be used for any kind of interactions, we can't trust that you won't abuse this token.
-
-Instead, everyone using mcproto should register a new application, and get their own MSA token for your application
-that uses mcproto in the back.
-
-To create a new application, follow these steps (this is a simplified guide, for a full guide, feel free to check the
-`Microsoft documentation `):
-
-#. Go to the `Azure portal `_ and log in (create an account if you need to).
-#. Search for and select **Azure Active Directory**.
-#. On the left navbar, under **Manage** section, click on **App registrations**.
-#. Click on **New registration** on top navbar.
-#. Pick a name for the application. Anyone using your app to authenticate will see this name.
-#. Choose **Personal Microsoft accounts only** from the Supported account types.
-#. Leave the **Redirect URI (optional)** empty.
-#. Click on **Register**.
-
-From there, you will need to enable this application to be used for OAuth2 flows. To do that, follow these steps:
-
-#. On the left navbar, under **Manage** section, click on **Authentication**.
-#. Set **Allow public content flows** to **Yes**.
-#. Click **Save**.
-
-After that, you can go back to the app (click **Overview** from the left navbar), and you'll want to copy the
-**Application (client) ID**. This is the ID you will need to pass to mcproto. (You will also need the **Display name**,
-and the **Directory (Tenant) ID** for `Registering the application with Minecraft`_ - first time only)
-
-If you ever need to access this application again, follow these steps (as Microsoft Azure is pretty unintuitive, we
-document this too):
-
-#. Go to the `Azure portal `_ and log in.
-#. Click on **Azure Active Directory** (if you can't find it on the main page, you can use the search).
-#. On the left navbar, under **Manage** section, click on **App registrations**.
-#. Click on **View all applications from personal account** (assuming you registered the app from a personal account).
-#. Click on your app.
-
-Registering the application with Minecraft
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Previously, this step wasn't required, however due to people maliciously creating these applications to steal accounts,
-Mojang have recently started to limit access to the ``https://api.minecraftservices.com``, and only allow explicitly
-white listed Client IDs to use this API.
-
-This API is absolutely crucial step in getting the final minecraft token, and so you will need to register your Client
-ID to be white listed by Mojang. Thankfully, it looks like Mojang is generally pretty lenient and at least for me, they
-didn't cause any unnecessary hassles when I asked for my application to be registered, for development purposes and
-work on mcproto.
-
-That said, you will need to wait a while (about a week, though it could be more), until Mojang reviews your application
-and approves it. There isn't much we can do about this.
-
-To get your Azure application registered, you will need to fill out a simple form, where you accept the EULA, provide
-your E-Mail, Application name, Application Client ID and Tennant ID.
-
-More annoyingly you will additionally also need to provide an **associated website or domain** for your project/brand.
-(This application is generally designed for more user-facing programs, such as full launchers. When registering
-mcproto, I just used the GitHub URL). Lastly, you'll want to describe why you need access to this API in the
-**Justification** section.
-
-Visit the `mojang article `_ describing this process.
-There is also a link to the form to fill out.
-
-
-The code
-^^^^^^^^
-
-Finally, after you've managed to register your application and get it approved by Mojang, you can use it with mcproto,
-go through the Microsoft OAuth2 flow and authorize this application to access your Microsoft account, which mcproto
-will then use to get the minecraft token you'll then need to login to online servers.
-
-.. code-block:: python
-
- import httpx
- from mcproto.auth.microsoft.oauth import full_microsoft_oauth
- from mcproto.auth.microsoft.xbox import xbox_auth
- from mcproto.auth.msa import MSAAccount
-
- MY_MSA_CLIENT_ID = "[REDACTED]" # Paste your own Client ID here
-
- async def authenticate() -> MSAAccount:
- async with httpx.AsyncClient() as client:
- microsoft_token = await full_microsoft_oauth(client, MY_MSA_CLIENT_ID)
- user_hash, xsts_token = xbox_auth(client, microsoft_token)
- return MSAAccount.xbox_auth(cilent, user_hash, xsts_token)
-
-Note that the :meth:`~mcproto.auth.microsoft.oauth.full_microsoft_oauth` will print a message containing the URL you
-should visit in your browser, and a one time code to type in once you reach this URL. That will then prompt you to log
-in to your Microsoft account, and then allow you to authorize the application to use your account.
-
-Caching
-^^^^^^^
-
-You will very likely want to set up caching here, and store at least the ``microsoft_token`` somewhere, so you don't
-have to log in each time your code will run. Here's some example code that caches every step of the way, always
-resorting to the "closest" functional token. Note that this is using `pickle` to store the tokens, you may want to use
-JSON or other format instead, as it would be safer. Also, be aware that these are sensitive and if compromised, someone
-could gain access to your minecraft account (though only for playing, they shouldn't be able to change your password or
-anything like that), so you might want to consider encrypting these cache files before storing:
-
-.. code-block:: python
-
- from __future__ import annotations
-
- import logging
- import pickle
- from pathlib import Path
-
- import httpx
-
- from mcproto.auth.microsoft.oauth import full_microsoft_oauth
- from mcproto.auth.microsoft.xbox import XSTSRequestError, xbox_auth
- from mcproto.auth.msa import MSAAccount, ServicesAPIError
-
- log = logging.getLogger(__name__)
-
- MY_MSA_CLIENT_ID = "[REDACTED]" # Paste your own Client ID here
- CACHE_DIR = Path(".cache/")
-
-
- async def microsoft_login(client: httpx.AsyncClient) -> MSAAccount: # noqa: PLR0912,PLR0915
- """Obtain minecraft account using Microsoft authentication.
-
- This function performs full caching of every step along the way, allowing for recovery
- without manual intervention for as long as at least the root token (from Microsoft OAuth2)
- is valid. Any later tokens will be refreshed and re-cached once invalid.
-
- If all tokens are invalid, or this function was ran for the first time (without any cached
- data), you will be shown a URL and a code. You have to go to this URL with your browser and
- enter the code, completing the OAuth2 flow, obtaining the root token.
- """
- CACHE_DIR.mkdir(parents=True, exist_ok=True)
-
- access_token_cache = CACHE_DIR.joinpath("xbox_access_token.pickle")
- if access_token_cache.exists():
- with access_token_cache.open("rb") as f:
- access_token: str = pickle.load(f) # noqa: S301
-
- try:
- account = await MSAAccount.from_xbox_access_token(client, access_token)
- log.info("Logged in with cached xbox minecraft access token")
- return account
- except httpx.HTTPStatusError as exc:
- log.warning(f"Cached xbox minecraft access token is invalid: {exc!r}")
- else:
- log.warning("No cached access token available, trying Xbox Secure Token Service (XSTS) token")
-
- # Access token either doesn't exist, or isn't valid, try XSTS (Xbox) token
- xbox_token_cache = CACHE_DIR.joinpath("xbox_xsts_token.pickle")
- if xbox_token_cache.exists():
- with xbox_token_cache.open("rb") as f:
- user_hash, xsts_token = pickle.load(f) # noqa: S301
-
- try:
- access_token = await MSAAccount._get_access_token_from_xbox(client, user_hash, xsts_token)
- except ServicesAPIError as exc:
- log.warning(f"Invalid cached Xbox Secure Token Service (XSTS) token: {exc!r}")
- else:
- log.info("Obtained xbox access token from cached Xbox Secure Token Service (XSTS) token")
- log.info("Storing xbox minecraft access token to cache and restarting auth")
- with access_token_cache.open("wb") as f:
- pickle.dump(access_token, f)
- return await microsoft_login(client)
- else:
- log.warning("No cached Xbox Secure Token Service (XSTS) token available, trying Microsoft OAuth2 token")
-
- # XSTS token either doesn't exist, or isn't valid, try Microsoft OAuth2 token
- microsoft_token_cache = CACHE_DIR.joinpath("microsoft_token.pickle")
- if microsoft_token_cache.exists():
- with microsoft_token_cache.open("rb") as f:
- microsoft_token = pickle.load(f) # noqa: S301
-
- try:
- user_hash, xsts_token = await xbox_auth(client, microsoft_token)
- except (httpx.HTTPStatusError, XSTSRequestError) as exc:
- log.warning(f"Invalid cached Microsoft OAuth2 token {exc!r}")
- else:
- log.info("Obtained Xbox Secure Token Service (XSTS) token from cached Microsoft OAuth2 token")
- log.info("Storing Xbox Secure Token Service (XSTS) token to cache and restarting auth")
- with xbox_token_cache.open("wb") as f:
- pickle.dump((user_hash, xsts_token), f)
- return await microsoft_login(client)
- else:
- log.warning("No cached microsoft token")
-
- # Microsoft OAuth2 token either doesn't exist, or isn't valid, request user auth
- log.info("Running Microsoft OAuth2 flow, requesting user authentication")
- microsoft_token = await full_microsoft_oauth(client, MY_MSA_CLIENT_ID)
- log.info("Obtained Microsoft OAuth2 token from user authentication")
- log.info("Storing Microsoft OAuth2 token and restarting auth")
- with microsoft_token_cache.open("wb") as f:
- pickle.dump(microsoft_token["access_token"], f)
- return await microsoft_login(client)
-
-Minecraft (non-migrated) accounts
----------------------------------
-
-If you still haven't migrated your account and linked it to a Microsoft account, follow this guide for authentication.
-(Any newly created Minecraft accounts will be using Microsoft accounts already.) This method of authentication is
-called "yggdrasil".
-
-.. warning::
- Mojang has announced that they will be closing the migration period for these unmigrated accounts in **September
- 19, 2023**. See: ``_
-
- Once that happen, any unmigrated accounts will no longer work, and you won't be able to log in. If you're still
- using an unmigrated account, it's about time to move.
-
- Mcproto will remove support for this old authentication methods once this happens.
-
-This method of authentication doesn't require any special app registrations, however it is significantly less secure,
-as you need to enter your login and password directly.
-
-.. code-block:: python
-
- import httpx
- from mcproto.auth.yggdrasil import YggdrasilAccount
-
- LOGIN = "mail@example.com"
- PASSWORD = "my_password"
-
- async def authenticate() -> YggdrasilAccount:
- async with httpx.AsyncClient() as client:
- return YggdrasilAccount.authenticate(client, login=LOGIN, password=PASSWORD)
-
-
-The Account instance you will obtain here will contain a refresh token, and a shorter lived access token, received from
-Mojang APIs from the credentials you entered. Just like with Microsoft accounts, you may want to cache these tokens to
-avoid needless calls to request new ones and go through authentication again. That said, since doing so doesn't
-necessarily require user interaction, if you make the credentials accessible from your code directly, this is a lot
-less annoying.
-
-If you will decide to use caching, or if you plan on using these credentials in a long running program, you may see the
-access token expire. You can check whether the token is expired with the
-:meth:`~mcproto.auth.yggdrasil.YggdrasilAccount.validate` method, and if it is (call returned ``False``), you can call
-:meth:`~mcproto.auth.yggdrasil.YggdrasilAccount.refresh` to use the refresh token to obtain a new access token. The
-refresh token is much more long lived than the access token, so this should generally be enough for you, although if
-you login from elsewhere, or after a really long time, the refresh token might be invalidated, in that case, you'll
-need to go through the full login again.
-
-Legacy Mojang accounts
-----------------------
-
-If your minecraft account is still using the (really old) Mojang authentication, you can simply follow the non-migrated
-guide, as it will work with these legacy accounts too, the only change you will need to make is to use your username,
-instead of an email.
diff --git a/docs/usage/index.rst b/docs/usage/index.rst
deleted file mode 100644
index 430806d7..00000000
--- a/docs/usage/index.rst
+++ /dev/null
@@ -1,13 +0,0 @@
-Usage guides
-============
-
-Here are some guides and explanations on how to use the various different parts of mcproto.
-
-
-.. toctree::
- :maxdepth: 1
- :caption: Guides
-
- authentication.rst
-
-Feel free to propose any further guides, we'll be happy to add them to the list!
diff --git a/mkdocs.yml b/mkdocs.yml
new file mode 100644
index 00000000..a5608e10
--- /dev/null
+++ b/mkdocs.yml
@@ -0,0 +1,69 @@
+site_name: MCPROTO
+site_url: https://py-mine.github.io/mcproto
+
+repo_url: https://github.com/py-mine/mcproto
+repo_name: py-mine/mcproto
+
+nav:
+ - Home: index.md
+
+theme:
+ name: material
+ logo: assets/py-mine_logo.png
+ palette:
+ - media: "(prefers-color-scheme)"
+ primary: black
+ accent: black
+ toggle:
+ icon: material/brightness-auto
+ name: Switch to light mode
+
+ - media: "(prefers-color-scheme: light)"
+ scheme: default
+ primary: black
+ accent: black
+ toggle:
+ icon: material/brightness-7
+ name: Switch to dark mode
+
+ - media: "(prefers-color-scheme: dark)"
+ scheme: slate
+ primary: black
+ accent: black
+ toggle:
+ icon: material/brightness-4
+ name: Switch to system preference
+ icon:
+ repo: fontawesome/brands/github
+ features:
+ - content.tabs.link
+ - content.code.copy
+ - content.action.edit
+ - search.highlight
+ - search.share
+ - search.suggest
+ - navigation.footer
+ - navigation.indexes
+ - navigation.sections
+ - navigation.tabs
+ - navigation.tabs.sticky
+ - navigation.top
+ - toc.follow
+
+markdown_extensions:
+ - admonition
+ - attr_list
+ - md_in_html
+ - toc:
+ permalink: true
+ - pymdownx.highlight:
+ anchor_linenums: true
+ - pymdownx.inlinehilite
+ - pymdownx.superfences
+ - pymdownx.snippets
+ - pymdownx.details
+ - pymdownx.tabbed:
+ alternate_style: true
+
+plugins:
+ - search
diff --git a/poetry.lock b/poetry.lock
index 4b866b43..bdb93c96 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,16 +1,5 @@
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
-[[package]]
-name = "alabaster"
-version = "0.7.13"
-description = "A configurable sidebar-enabled Sphinx theme"
-optional = false
-python-versions = ">=3.6"
-files = [
- {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"},
- {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"},
-]
-
[[package]]
name = "anyio"
version = "4.3.0"
@@ -100,27 +89,6 @@ files = [
[package.dependencies]
nodejs-wheel-binaries = ">=20.13.1"
-[[package]]
-name = "beautifulsoup4"
-version = "4.12.3"
-description = "Screen-scraping library"
-optional = false
-python-versions = ">=3.6.0"
-files = [
- {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"},
- {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"},
-]
-
-[package.dependencies]
-soupsieve = ">1.2"
-
-[package.extras]
-cchardet = ["cchardet"]
-chardet = ["chardet"]
-charset-normalizer = ["charset-normalizer"]
-html5lib = ["html5lib"]
-lxml = ["lxml"]
-
[[package]]
name = "certifi"
version = "2024.7.4"
@@ -458,17 +426,6 @@ files = [
{file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"},
]
-[[package]]
-name = "docutils"
-version = "0.19"
-description = "Docutils -- Python Documentation Utilities"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "docutils-0.19-py3-none-any.whl", hash = "sha256:5e1de4d849fee02c63b040a4a3fd567f4ab104defd8a5511fbbc24a8a017efbc"},
- {file = "docutils-0.19.tar.gz", hash = "sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6"},
-]
-
[[package]]
name = "dunamai"
version = "1.21.1"
@@ -514,21 +471,21 @@ testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)",
typing = ["typing-extensions (>=4.8)"]
[[package]]
-name = "furo"
-version = "2024.5.6"
-description = "A clean customisable Sphinx documentation theme."
+name = "ghp-import"
+version = "2.1.0"
+description = "Copy your docs directly to the gh-pages branch."
optional = false
-python-versions = ">=3.8"
+python-versions = "*"
files = [
- {file = "furo-2024.5.6-py3-none-any.whl", hash = "sha256:490a00d08c0a37ecc90de03ae9227e8eb5d6f7f750edf9807f398a2bdf2358de"},
- {file = "furo-2024.5.6.tar.gz", hash = "sha256:81f205a6605ebccbb883350432b4831c0196dd3d1bc92f61e1f459045b3d2b0b"},
+ {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"},
+ {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"},
]
[package.dependencies]
-beautifulsoup4 = "*"
-pygments = ">=2.7"
-sphinx = ">=6.0,<8.0"
-sphinx-basic-ng = ">=1.0.0.beta2"
+python-dateutil = ">=2.8.1"
+
+[package.extras]
+dev = ["flake8", "markdown", "twine", "wheel"]
[[package]]
name = "h11"
@@ -610,17 +567,6 @@ files = [
{file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"},
]
-[[package]]
-name = "imagesize"
-version = "1.4.1"
-description = "Getting image size from png/jpeg/jpeg2000/gif file"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-files = [
- {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"},
- {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"},
-]
-
[[package]]
name = "importlib-metadata"
version = "7.1.0"
@@ -687,19 +633,22 @@ MarkupSafe = ">=2.0"
i18n = ["Babel (>=2.7)"]
[[package]]
-name = "m2r2"
-version = "0.3.3.post2"
-description = "Markdown and reStructuredText in a single file."
+name = "markdown"
+version = "3.6"
+description = "Python implementation of John Gruber's Markdown."
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "m2r2-0.3.3.post2-py3-none-any.whl", hash = "sha256:86157721eb6eabcd54d4eea7195890cc58fa6188b8d0abea633383cfbb5e11e3"},
- {file = "m2r2-0.3.3.post2.tar.gz", hash = "sha256:e62bcb0e74b3ce19cda0737a0556b04cf4a43b785072fcef474558f2c1482ca8"},
+ {file = "Markdown-3.6-py3-none-any.whl", hash = "sha256:48f276f4d8cfb8ce6527c8f79e2ee29708508bf4d40aa410fbc3b4ee832c850f"},
+ {file = "Markdown-3.6.tar.gz", hash = "sha256:ed4f41f6daecbeeb96e576ce414c41d2d876daa9a16cb35fa8ed8c2ddfad0224"},
]
[package.dependencies]
-docutils = ">=0.19"
-mistune = "0.8.4"
+importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""}
+
+[package.extras]
+docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"]
+testing = ["coverage", "pyyaml"]
[[package]]
name = "markupsafe"
@@ -771,14 +720,102 @@ files = [
]
[[package]]
-name = "mistune"
-version = "0.8.4"
-description = "The fastest markdown parser in pure Python"
+name = "mergedeep"
+version = "1.3.4"
+description = "A deep merge function for 🐍."
optional = false
-python-versions = "*"
+python-versions = ">=3.6"
+files = [
+ {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"},
+ {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"},
+]
+
+[[package]]
+name = "mkdocs"
+version = "1.6.0"
+description = "Project documentation with Markdown."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "mkdocs-1.6.0-py3-none-any.whl", hash = "sha256:1eb5cb7676b7d89323e62b56235010216319217d4af5ddc543a91beb8d125ea7"},
+ {file = "mkdocs-1.6.0.tar.gz", hash = "sha256:a73f735824ef83a4f3bcb7a231dcab23f5a838f88b7efc54a0eef5fbdbc3c512"},
+]
+
+[package.dependencies]
+click = ">=7.0"
+colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""}
+ghp-import = ">=1.0"
+importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""}
+jinja2 = ">=2.11.1"
+markdown = ">=3.3.6"
+markupsafe = ">=2.0.1"
+mergedeep = ">=1.3.4"
+mkdocs-get-deps = ">=0.2.0"
+packaging = ">=20.5"
+pathspec = ">=0.11.1"
+pyyaml = ">=5.1"
+pyyaml-env-tag = ">=0.1"
+watchdog = ">=2.0"
+
+[package.extras]
+i18n = ["babel (>=2.9.0)"]
+min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.4)", "jinja2 (==2.11.1)", "markdown (==3.3.6)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "mkdocs-get-deps (==0.2.0)", "packaging (==20.5)", "pathspec (==0.11.1)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "watchdog (==2.0)"]
+
+[[package]]
+name = "mkdocs-get-deps"
+version = "0.2.0"
+description = "MkDocs extension that lists all dependencies according to a mkdocs.yml file"
+optional = false
+python-versions = ">=3.8"
files = [
- {file = "mistune-0.8.4-py2.py3-none-any.whl", hash = "sha256:88a1051873018da288eee8538d476dffe1262495144b33ecb586c4ab266bb8d4"},
- {file = "mistune-0.8.4.tar.gz", hash = "sha256:59a3429db53c50b5c6bcc8a07f8848cb00d7dc8bdb431a4ab41920d201d4756e"},
+ {file = "mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134"},
+ {file = "mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c"},
+]
+
+[package.dependencies]
+importlib-metadata = {version = ">=4.3", markers = "python_version < \"3.10\""}
+mergedeep = ">=1.3.4"
+platformdirs = ">=2.2.0"
+pyyaml = ">=5.1"
+
+[[package]]
+name = "mkdocs-material"
+version = "9.5.30"
+description = "Documentation that simply works"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "mkdocs_material-9.5.30-py3-none-any.whl", hash = "sha256:fc070689c5250a180e9b9d79d8491ef9a3a7acb240db0728728d6c31eeb131d4"},
+ {file = "mkdocs_material-9.5.30.tar.gz", hash = "sha256:3fd417dd42d679e3ba08b9e2d72cd8b8af142cc4a3969676ad6b00993dd182ec"},
+]
+
+[package.dependencies]
+babel = ">=2.10,<3.0"
+colorama = ">=0.4,<1.0"
+jinja2 = ">=3.0,<4.0"
+markdown = ">=3.2,<4.0"
+mkdocs = ">=1.6,<2.0"
+mkdocs-material-extensions = ">=1.3,<2.0"
+paginate = ">=0.5,<1.0"
+pygments = ">=2.16,<3.0"
+pymdown-extensions = ">=10.2,<11.0"
+regex = ">=2022.4"
+requests = ">=2.26,<3.0"
+
+[package.extras]
+git = ["mkdocs-git-committers-plugin-2 (>=1.1,<2.0)", "mkdocs-git-revision-date-localized-plugin (>=1.2.4,<2.0)"]
+imaging = ["cairosvg (>=2.6,<3.0)", "pillow (>=10.2,<11.0)"]
+recommended = ["mkdocs-minify-plugin (>=0.7,<1.0)", "mkdocs-redirects (>=1.2,<2.0)", "mkdocs-rss-plugin (>=1.6,<2.0)"]
+
+[[package]]
+name = "mkdocs-material-extensions"
+version = "1.3.1"
+description = "Extension pack for Python Markdown and MkDocs Material."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"},
+ {file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"},
]
[[package]]
@@ -833,6 +870,27 @@ files = [
{file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
]
+[[package]]
+name = "paginate"
+version = "0.5.6"
+description = "Divides large result sets into pages for easier browsing"
+optional = false
+python-versions = "*"
+files = [
+ {file = "paginate-0.5.6.tar.gz", hash = "sha256:5e6007b6a9398177a7e1648d04fdd9f8c9766a1a945bceac82f1929e8c78af2d"},
+]
+
+[[package]]
+name = "pathspec"
+version = "0.12.1"
+description = "Utility library for gitignore style pattern matching of file paths."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
+ {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
+]
+
[[package]]
name = "platformdirs"
version = "4.2.2"
@@ -954,6 +1012,24 @@ files = [
[package.extras]
windows-terminal = ["colorama (>=0.4.6)"]
+[[package]]
+name = "pymdown-extensions"
+version = "10.9"
+description = "Extension pack for Python Markdown."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pymdown_extensions-10.9-py3-none-any.whl", hash = "sha256:d323f7e90d83c86113ee78f3fe62fc9dee5f56b54d912660703ea1816fed5626"},
+ {file = "pymdown_extensions-10.9.tar.gz", hash = "sha256:6ff740bcd99ec4172a938970d42b96128bdc9d4b9bcad72494f29921dc69b753"},
+]
+
+[package.dependencies]
+markdown = ">=3.6"
+pyyaml = "*"
+
+[package.extras]
+extra = ["pygments (>=2.12)"]
+
[[package]]
name = "pytest"
version = "7.4.4"
@@ -1030,6 +1106,20 @@ pytest = ">=6.0,<8.0"
[package.extras]
testing = ["pytest-asyncio (==0.21.*)", "pytest-cov (==4.*)"]
+[[package]]
+name = "python-dateutil"
+version = "2.9.0.post0"
+description = "Extensions to the standard Python datetime module"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+files = [
+ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
+ {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
+]
+
+[package.dependencies]
+six = ">=1.5"
+
[[package]]
name = "pytz"
version = "2024.1"
@@ -1101,6 +1191,108 @@ files = [
{file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
]
+[[package]]
+name = "pyyaml-env-tag"
+version = "0.1"
+description = "A custom YAML tag for referencing environment variables in YAML files. "
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"},
+ {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"},
+]
+
+[package.dependencies]
+pyyaml = "*"
+
+[[package]]
+name = "regex"
+version = "2024.7.24"
+description = "Alternative regular expression module, to replace re."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "regex-2024.7.24-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b0d3f567fafa0633aee87f08b9276c7062da9616931382993c03808bb68ce"},
+ {file = "regex-2024.7.24-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3426de3b91d1bc73249042742f45c2148803c111d1175b283270177fdf669024"},
+ {file = "regex-2024.7.24-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f273674b445bcb6e4409bf8d1be67bc4b58e8b46fd0d560055d515b8830063cd"},
+ {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23acc72f0f4e1a9e6e9843d6328177ae3074b4182167e34119ec7233dfeccf53"},
+ {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65fd3d2e228cae024c411c5ccdffae4c315271eee4a8b839291f84f796b34eca"},
+ {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c414cbda77dbf13c3bc88b073a1a9f375c7b0cb5e115e15d4b73ec3a2fbc6f59"},
+ {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf7a89eef64b5455835f5ed30254ec19bf41f7541cd94f266ab7cbd463f00c41"},
+ {file = "regex-2024.7.24-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19c65b00d42804e3fbea9708f0937d157e53429a39b7c61253ff15670ff62cb5"},
+ {file = "regex-2024.7.24-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7a5486ca56c8869070a966321d5ab416ff0f83f30e0e2da1ab48815c8d165d46"},
+ {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6f51f9556785e5a203713f5efd9c085b4a45aecd2a42573e2b5041881b588d1f"},
+ {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a4997716674d36a82eab3e86f8fa77080a5d8d96a389a61ea1d0e3a94a582cf7"},
+ {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c0abb5e4e8ce71a61d9446040c1e86d4e6d23f9097275c5bd49ed978755ff0fe"},
+ {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:18300a1d78cf1290fa583cd8b7cde26ecb73e9f5916690cf9d42de569c89b1ce"},
+ {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:416c0e4f56308f34cdb18c3f59849479dde5b19febdcd6e6fa4d04b6c31c9faa"},
+ {file = "regex-2024.7.24-cp310-cp310-win32.whl", hash = "sha256:fb168b5924bef397b5ba13aabd8cf5df7d3d93f10218d7b925e360d436863f66"},
+ {file = "regex-2024.7.24-cp310-cp310-win_amd64.whl", hash = "sha256:6b9fc7e9cc983e75e2518496ba1afc524227c163e43d706688a6bb9eca41617e"},
+ {file = "regex-2024.7.24-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:382281306e3adaaa7b8b9ebbb3ffb43358a7bbf585fa93821300a418bb975281"},
+ {file = "regex-2024.7.24-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4fdd1384619f406ad9037fe6b6eaa3de2749e2e12084abc80169e8e075377d3b"},
+ {file = "regex-2024.7.24-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3d974d24edb231446f708c455fd08f94c41c1ff4f04bcf06e5f36df5ef50b95a"},
+ {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2ec4419a3fe6cf8a4795752596dfe0adb4aea40d3683a132bae9c30b81e8d73"},
+ {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb563dd3aea54c797adf513eeec819c4213d7dbfc311874eb4fd28d10f2ff0f2"},
+ {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:45104baae8b9f67569f0f1dca5e1f1ed77a54ae1cd8b0b07aba89272710db61e"},
+ {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:994448ee01864501912abf2bad9203bffc34158e80fe8bfb5b031f4f8e16da51"},
+ {file = "regex-2024.7.24-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fac296f99283ac232d8125be932c5cd7644084a30748fda013028c815ba3364"},
+ {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7e37e809b9303ec3a179085415cb5f418ecf65ec98cdfe34f6a078b46ef823ee"},
+ {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:01b689e887f612610c869421241e075c02f2e3d1ae93a037cb14f88ab6a8934c"},
+ {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f6442f0f0ff81775eaa5b05af8a0ffa1dda36e9cf6ec1e0d3d245e8564b684ce"},
+ {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:871e3ab2838fbcb4e0865a6e01233975df3a15e6fce93b6f99d75cacbd9862d1"},
+ {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c918b7a1e26b4ab40409820ddccc5d49871a82329640f5005f73572d5eaa9b5e"},
+ {file = "regex-2024.7.24-cp311-cp311-win32.whl", hash = "sha256:2dfbb8baf8ba2c2b9aa2807f44ed272f0913eeeba002478c4577b8d29cde215c"},
+ {file = "regex-2024.7.24-cp311-cp311-win_amd64.whl", hash = "sha256:538d30cd96ed7d1416d3956f94d54e426a8daf7c14527f6e0d6d425fcb4cca52"},
+ {file = "regex-2024.7.24-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:fe4ebef608553aff8deb845c7f4f1d0740ff76fa672c011cc0bacb2a00fbde86"},
+ {file = "regex-2024.7.24-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:74007a5b25b7a678459f06559504f1eec2f0f17bca218c9d56f6a0a12bfffdad"},
+ {file = "regex-2024.7.24-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7df9ea48641da022c2a3c9c641650cd09f0cd15e8908bf931ad538f5ca7919c9"},
+ {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a1141a1dcc32904c47f6846b040275c6e5de0bf73f17d7a409035d55b76f289"},
+ {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80c811cfcb5c331237d9bad3bea2c391114588cf4131707e84d9493064d267f9"},
+ {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7214477bf9bd195894cf24005b1e7b496f46833337b5dedb7b2a6e33f66d962c"},
+ {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d55588cba7553f0b6ec33130bc3e114b355570b45785cebdc9daed8c637dd440"},
+ {file = "regex-2024.7.24-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:558a57cfc32adcf19d3f791f62b5ff564922942e389e3cfdb538a23d65a6b610"},
+ {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a512eed9dfd4117110b1881ba9a59b31433caed0c4101b361f768e7bcbaf93c5"},
+ {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:86b17ba823ea76256b1885652e3a141a99a5c4422f4a869189db328321b73799"},
+ {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5eefee9bfe23f6df09ffb6dfb23809f4d74a78acef004aa904dc7c88b9944b05"},
+ {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:731fcd76bbdbf225e2eb85b7c38da9633ad3073822f5ab32379381e8c3c12e94"},
+ {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eaef80eac3b4cfbdd6de53c6e108b4c534c21ae055d1dbea2de6b3b8ff3def38"},
+ {file = "regex-2024.7.24-cp312-cp312-win32.whl", hash = "sha256:185e029368d6f89f36e526764cf12bf8d6f0e3a2a7737da625a76f594bdfcbfc"},
+ {file = "regex-2024.7.24-cp312-cp312-win_amd64.whl", hash = "sha256:2f1baff13cc2521bea83ab2528e7a80cbe0ebb2c6f0bfad15be7da3aed443908"},
+ {file = "regex-2024.7.24-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:66b4c0731a5c81921e938dcf1a88e978264e26e6ac4ec96a4d21ae0354581ae0"},
+ {file = "regex-2024.7.24-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:88ecc3afd7e776967fa16c80f974cb79399ee8dc6c96423321d6f7d4b881c92b"},
+ {file = "regex-2024.7.24-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:64bd50cf16bcc54b274e20235bf8edbb64184a30e1e53873ff8d444e7ac656b2"},
+ {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb462f0e346fcf41a901a126b50f8781e9a474d3927930f3490f38a6e73b6950"},
+ {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a82465ebbc9b1c5c50738536fdfa7cab639a261a99b469c9d4c7dcbb2b3f1e57"},
+ {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:68a8f8c046c6466ac61a36b65bb2395c74451df2ffb8458492ef49900efed293"},
+ {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac8e84fff5d27420f3c1e879ce9929108e873667ec87e0c8eeb413a5311adfe"},
+ {file = "regex-2024.7.24-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba2537ef2163db9e6ccdbeb6f6424282ae4dea43177402152c67ef869cf3978b"},
+ {file = "regex-2024.7.24-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:43affe33137fcd679bdae93fb25924979517e011f9dea99163f80b82eadc7e53"},
+ {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:c9bb87fdf2ab2370f21e4d5636e5317775e5d51ff32ebff2cf389f71b9b13750"},
+ {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:945352286a541406f99b2655c973852da7911b3f4264e010218bbc1cc73168f2"},
+ {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:8bc593dcce679206b60a538c302d03c29b18e3d862609317cb560e18b66d10cf"},
+ {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3f3b6ca8eae6d6c75a6cff525c8530c60e909a71a15e1b731723233331de4169"},
+ {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c51edc3541e11fbe83f0c4d9412ef6c79f664a3745fab261457e84465ec9d5a8"},
+ {file = "regex-2024.7.24-cp38-cp38-win32.whl", hash = "sha256:d0a07763776188b4db4c9c7fb1b8c494049f84659bb387b71c73bbc07f189e96"},
+ {file = "regex-2024.7.24-cp38-cp38-win_amd64.whl", hash = "sha256:8fd5afd101dcf86a270d254364e0e8dddedebe6bd1ab9d5f732f274fa00499a5"},
+ {file = "regex-2024.7.24-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0ffe3f9d430cd37d8fa5632ff6fb36d5b24818c5c986893063b4e5bdb84cdf24"},
+ {file = "regex-2024.7.24-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:25419b70ba00a16abc90ee5fce061228206173231f004437730b67ac77323f0d"},
+ {file = "regex-2024.7.24-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:33e2614a7ce627f0cdf2ad104797d1f68342d967de3695678c0cb84f530709f8"},
+ {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d33a0021893ede5969876052796165bab6006559ab845fd7b515a30abdd990dc"},
+ {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04ce29e2c5fedf296b1a1b0acc1724ba93a36fb14031f3abfb7abda2806c1535"},
+ {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b16582783f44fbca6fcf46f61347340c787d7530d88b4d590a397a47583f31dd"},
+ {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:836d3cc225b3e8a943d0b02633fb2f28a66e281290302a79df0e1eaa984ff7c1"},
+ {file = "regex-2024.7.24-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:438d9f0f4bc64e8dea78274caa5af971ceff0f8771e1a2333620969936ba10be"},
+ {file = "regex-2024.7.24-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:973335b1624859cb0e52f96062a28aa18f3a5fc77a96e4a3d6d76e29811a0e6e"},
+ {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c5e69fd3eb0b409432b537fe3c6f44ac089c458ab6b78dcec14478422879ec5f"},
+ {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fbf8c2f00904eaf63ff37718eb13acf8e178cb940520e47b2f05027f5bb34ce3"},
+ {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ae2757ace61bc4061b69af19e4689fa4416e1a04840f33b441034202b5cd02d4"},
+ {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:44fc61b99035fd9b3b9453f1713234e5a7c92a04f3577252b45feefe1b327759"},
+ {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:84c312cdf839e8b579f504afcd7b65f35d60b6285d892b19adea16355e8343c9"},
+ {file = "regex-2024.7.24-cp39-cp39-win32.whl", hash = "sha256:ca5b2028c2f7af4e13fb9fc29b28d0ce767c38c7facdf64f6c2cd040413055f1"},
+ {file = "regex-2024.7.24-cp39-cp39-win_amd64.whl", hash = "sha256:7c479f5ae937ec9985ecaf42e2e10631551d909f203e31308c12d703922742f9"},
+ {file = "regex-2024.7.24.tar.gz", hash = "sha256:9cfd009eed1a46b27c14039ad5bbc5e71b6367c5b2e6d5f5da0ea91600817506"},
+]
+
[[package]]
name = "requests"
version = "2.32.2"
@@ -1179,6 +1371,17 @@ files = [
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
testing = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
+[[package]]
+name = "six"
+version = "1.16.0"
+description = "Python 2 and 3 compatibility utilities"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
+files = [
+ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
+ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
+]
+
[[package]]
name = "slotscheck"
version = "0.19.0"
@@ -1205,221 +1408,6 @@ files = [
{file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
]
-[[package]]
-name = "snowballstemmer"
-version = "2.2.0"
-description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms."
-optional = false
-python-versions = "*"
-files = [
- {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"},
- {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"},
-]
-
-[[package]]
-name = "soupsieve"
-version = "2.5"
-description = "A modern CSS selector implementation for Beautiful Soup."
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "soupsieve-2.5-py3-none-any.whl", hash = "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"},
- {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"},
-]
-
-[[package]]
-name = "sphinx"
-version = "7.1.2"
-description = "Python documentation generator"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "sphinx-7.1.2-py3-none-any.whl", hash = "sha256:d170a81825b2fcacb6dfd5a0d7f578a053e45d3f2b153fecc948c37344eb4cbe"},
- {file = "sphinx-7.1.2.tar.gz", hash = "sha256:780f4d32f1d7d1126576e0e5ecc19dc32ab76cd24e950228dcf7b1f6d3d9e22f"},
-]
-
-[package.dependencies]
-alabaster = ">=0.7,<0.8"
-babel = ">=2.9"
-colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
-docutils = ">=0.18.1,<0.21"
-imagesize = ">=1.3"
-importlib-metadata = {version = ">=4.8", markers = "python_version < \"3.10\""}
-Jinja2 = ">=3.0"
-packaging = ">=21.0"
-Pygments = ">=2.13"
-requests = ">=2.25.0"
-snowballstemmer = ">=2.0"
-sphinxcontrib-applehelp = "*"
-sphinxcontrib-devhelp = "*"
-sphinxcontrib-htmlhelp = ">=2.0.0"
-sphinxcontrib-jsmath = "*"
-sphinxcontrib-qthelp = "*"
-sphinxcontrib-serializinghtml = ">=1.1.5"
-
-[package.extras]
-docs = ["sphinxcontrib-websupport"]
-lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-simplify", "isort", "mypy (>=0.990)", "ruff", "sphinx-lint", "types-requests"]
-test = ["cython", "filelock", "html5lib", "pytest (>=4.6)"]
-
-[[package]]
-name = "sphinx-autodoc-typehints"
-version = "2.0.1"
-description = "Type hints (PEP 484) support for the Sphinx autodoc extension"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "sphinx_autodoc_typehints-2.0.1-py3-none-any.whl", hash = "sha256:f73ae89b43a799e587e39266672c1075b2ef783aeb382d3ebed77c38a3fc0149"},
- {file = "sphinx_autodoc_typehints-2.0.1.tar.gz", hash = "sha256:60ed1e3b2c970acc0aa6e877be42d48029a9faec7378a17838716cacd8c10b12"},
-]
-
-[package.dependencies]
-sphinx = ">=7.1.2"
-
-[package.extras]
-docs = ["furo (>=2024.1.29)"]
-numpy = ["nptyping (>=2.5)"]
-testing = ["covdefaults (>=2.3)", "coverage (>=7.4.2)", "diff-cover (>=8.0.3)", "pytest (>=8.0.1)", "pytest-cov (>=4.1)", "sphobjinv (>=2.3.1)", "typing-extensions (>=4.9)"]
-
-[[package]]
-name = "sphinx-basic-ng"
-version = "1.0.0b2"
-description = "A modern skeleton for Sphinx themes."
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "sphinx_basic_ng-1.0.0b2-py3-none-any.whl", hash = "sha256:eb09aedbabfb650607e9b4b68c9d240b90b1e1be221d6ad71d61c52e29f7932b"},
- {file = "sphinx_basic_ng-1.0.0b2.tar.gz", hash = "sha256:9ec55a47c90c8c002b5960c57492ec3021f5193cb26cebc2dc4ea226848651c9"},
-]
-
-[package.dependencies]
-sphinx = ">=4.0"
-
-[package.extras]
-docs = ["furo", "ipython", "myst-parser", "sphinx-copybutton", "sphinx-inline-tabs"]
-
-[[package]]
-name = "sphinx-copybutton"
-version = "0.5.2"
-description = "Add a copy button to each of your code cells."
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "sphinx-copybutton-0.5.2.tar.gz", hash = "sha256:4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd"},
- {file = "sphinx_copybutton-0.5.2-py3-none-any.whl", hash = "sha256:fb543fd386d917746c9a2c50360c7905b605726b9355cd26e9974857afeae06e"},
-]
-
-[package.dependencies]
-sphinx = ">=1.8"
-
-[package.extras]
-code-style = ["pre-commit (==2.12.1)"]
-rtd = ["ipython", "myst-nb", "sphinx", "sphinx-book-theme", "sphinx-examples"]
-
-[[package]]
-name = "sphinxcontrib-applehelp"
-version = "1.0.4"
-description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "sphinxcontrib-applehelp-1.0.4.tar.gz", hash = "sha256:828f867945bbe39817c210a1abfd1bc4895c8b73fcaade56d45357a348a07d7e"},
- {file = "sphinxcontrib_applehelp-1.0.4-py3-none-any.whl", hash = "sha256:29d341f67fb0f6f586b23ad80e072c8e6ad0b48417db2bde114a4c9746feb228"},
-]
-
-[package.extras]
-lint = ["docutils-stubs", "flake8", "mypy"]
-test = ["pytest"]
-
-[[package]]
-name = "sphinxcontrib-devhelp"
-version = "1.0.2"
-description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document."
-optional = false
-python-versions = ">=3.5"
-files = [
- {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"},
- {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"},
-]
-
-[package.extras]
-lint = ["docutils-stubs", "flake8", "mypy"]
-test = ["pytest"]
-
-[[package]]
-name = "sphinxcontrib-htmlhelp"
-version = "2.0.1"
-description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "sphinxcontrib-htmlhelp-2.0.1.tar.gz", hash = "sha256:0cbdd302815330058422b98a113195c9249825d681e18f11e8b1f78a2f11efff"},
- {file = "sphinxcontrib_htmlhelp-2.0.1-py3-none-any.whl", hash = "sha256:c38cb46dccf316c79de6e5515e1770414b797162b23cd3d06e67020e1d2a6903"},
-]
-
-[package.extras]
-lint = ["docutils-stubs", "flake8", "mypy"]
-test = ["html5lib", "pytest"]
-
-[[package]]
-name = "sphinxcontrib-jsmath"
-version = "1.0.1"
-description = "A sphinx extension which renders display math in HTML via JavaScript"
-optional = false
-python-versions = ">=3.5"
-files = [
- {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"},
- {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"},
-]
-
-[package.extras]
-test = ["flake8", "mypy", "pytest"]
-
-[[package]]
-name = "sphinxcontrib-qthelp"
-version = "1.0.3"
-description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document."
-optional = false
-python-versions = ">=3.5"
-files = [
- {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"},
- {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"},
-]
-
-[package.extras]
-lint = ["docutils-stubs", "flake8", "mypy"]
-test = ["pytest"]
-
-[[package]]
-name = "sphinxcontrib-serializinghtml"
-version = "1.1.5"
-description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)."
-optional = false
-python-versions = ">=3.5"
-files = [
- {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"},
- {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"},
-]
-
-[package.extras]
-lint = ["docutils-stubs", "flake8", "mypy"]
-test = ["pytest"]
-
-[[package]]
-name = "sphinxcontrib-towncrier"
-version = "0.4.0a0"
-description = "An RST directive for injecting a Towncrier-generated changelog draft containing fragments for the unreleased (next) project version"
-optional = false
-python-versions = ">=3.6"
-files = [
- {file = "sphinxcontrib-towncrier-0.4.0a0.tar.gz", hash = "sha256:d9b1513fc07781432dd3a0b2ca797cfe0e99e9b5bc5e5c8bf112d5d142afb6dc"},
- {file = "sphinxcontrib_towncrier-0.4.0a0-py3-none-any.whl", hash = "sha256:ec734e3d0920e2ce26e99681119f398a9e1fc0aa6c2d7ed1f052f1219dcd4653"},
-]
-
-[package.dependencies]
-sphinx = "*"
-towncrier = ">=19.2"
-
[[package]]
name = "taskipy"
version = "1.13.0"
@@ -1528,6 +1516,50 @@ platformdirs = ">=3.9.1,<5"
docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"]
+[[package]]
+name = "watchdog"
+version = "4.0.1"
+description = "Filesystem events monitoring"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "watchdog-4.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:da2dfdaa8006eb6a71051795856bedd97e5b03e57da96f98e375682c48850645"},
+ {file = "watchdog-4.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e93f451f2dfa433d97765ca2634628b789b49ba8b504fdde5837cdcf25fdb53b"},
+ {file = "watchdog-4.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ef0107bbb6a55f5be727cfc2ef945d5676b97bffb8425650dadbb184be9f9a2b"},
+ {file = "watchdog-4.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:17e32f147d8bf9657e0922c0940bcde863b894cd871dbb694beb6704cfbd2fb5"},
+ {file = "watchdog-4.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:03e70d2df2258fb6cb0e95bbdbe06c16e608af94a3ffbd2b90c3f1e83eb10767"},
+ {file = "watchdog-4.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:123587af84260c991dc5f62a6e7ef3d1c57dfddc99faacee508c71d287248459"},
+ {file = "watchdog-4.0.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:093b23e6906a8b97051191a4a0c73a77ecc958121d42346274c6af6520dec175"},
+ {file = "watchdog-4.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:611be3904f9843f0529c35a3ff3fd617449463cb4b73b1633950b3d97fa4bfb7"},
+ {file = "watchdog-4.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:62c613ad689ddcb11707f030e722fa929f322ef7e4f18f5335d2b73c61a85c28"},
+ {file = "watchdog-4.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d4925e4bf7b9bddd1c3de13c9b8a2cdb89a468f640e66fbfabaf735bd85b3e35"},
+ {file = "watchdog-4.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cad0bbd66cd59fc474b4a4376bc5ac3fc698723510cbb64091c2a793b18654db"},
+ {file = "watchdog-4.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a3c2c317a8fb53e5b3d25790553796105501a235343f5d2bf23bb8649c2c8709"},
+ {file = "watchdog-4.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c9904904b6564d4ee8a1ed820db76185a3c96e05560c776c79a6ce5ab71888ba"},
+ {file = "watchdog-4.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:667f3c579e813fcbad1b784db7a1aaa96524bed53437e119f6a2f5de4db04235"},
+ {file = "watchdog-4.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d10a681c9a1d5a77e75c48a3b8e1a9f2ae2928eda463e8d33660437705659682"},
+ {file = "watchdog-4.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0144c0ea9997b92615af1d94afc0c217e07ce2c14912c7b1a5731776329fcfc7"},
+ {file = "watchdog-4.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:998d2be6976a0ee3a81fb8e2777900c28641fb5bfbd0c84717d89bca0addcdc5"},
+ {file = "watchdog-4.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e7921319fe4430b11278d924ef66d4daa469fafb1da679a2e48c935fa27af193"},
+ {file = "watchdog-4.0.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:f0de0f284248ab40188f23380b03b59126d1479cd59940f2a34f8852db710625"},
+ {file = "watchdog-4.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bca36be5707e81b9e6ce3208d92d95540d4ca244c006b61511753583c81c70dd"},
+ {file = "watchdog-4.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ab998f567ebdf6b1da7dc1e5accfaa7c6992244629c0fdaef062f43249bd8dee"},
+ {file = "watchdog-4.0.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:dddba7ca1c807045323b6af4ff80f5ddc4d654c8bce8317dde1bd96b128ed253"},
+ {file = "watchdog-4.0.1-py3-none-manylinux2014_armv7l.whl", hash = "sha256:4513ec234c68b14d4161440e07f995f231be21a09329051e67a2118a7a612d2d"},
+ {file = "watchdog-4.0.1-py3-none-manylinux2014_i686.whl", hash = "sha256:4107ac5ab936a63952dea2a46a734a23230aa2f6f9db1291bf171dac3ebd53c6"},
+ {file = "watchdog-4.0.1-py3-none-manylinux2014_ppc64.whl", hash = "sha256:6e8c70d2cd745daec2a08734d9f63092b793ad97612470a0ee4cbb8f5f705c57"},
+ {file = "watchdog-4.0.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:f27279d060e2ab24c0aa98363ff906d2386aa6c4dc2f1a374655d4e02a6c5e5e"},
+ {file = "watchdog-4.0.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:f8affdf3c0f0466e69f5b3917cdd042f89c8c63aebdb9f7c078996f607cdb0f5"},
+ {file = "watchdog-4.0.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ac7041b385f04c047fcc2951dc001671dee1b7e0615cde772e84b01fbf68ee84"},
+ {file = "watchdog-4.0.1-py3-none-win32.whl", hash = "sha256:206afc3d964f9a233e6ad34618ec60b9837d0582b500b63687e34011e15bb429"},
+ {file = "watchdog-4.0.1-py3-none-win_amd64.whl", hash = "sha256:7577b3c43e5909623149f76b099ac49a1a01ca4e167d1785c76eb52fa585745a"},
+ {file = "watchdog-4.0.1-py3-none-win_ia64.whl", hash = "sha256:d7b9f5f3299e8dd230880b6c55504a1f69cf1e4316275d1b215ebdd8187ec88d"},
+ {file = "watchdog-4.0.1.tar.gz", hash = "sha256:eebaacf674fa25511e8867028d281e602ee6500045b57f43b08778082f7f8b44"},
+]
+
+[package.extras]
+watchmedo = ["PyYAML (>=3.10)"]
+
[[package]]
name = "zipp"
version = "3.19.1"
@@ -1546,4 +1578,4 @@ test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-it
[metadata]
lock-version = "2.0"
python-versions = ">=3.8.1,<4"
-content-hash = "9acc37e791eb2852402a9b68aea108559fbdc4662056101d978e7665fa4dfe8a"
+content-hash = "25804ccd790a57f938a2cbbd6554bfc9443063819b940f6f337b4aca07c4e686"
diff --git a/pyproject.toml b/pyproject.toml
index 6426451c..c78c7824 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -62,15 +62,8 @@ optional = true
poetry-dynamic-versioning = ">=1.4.0,<1.5"
[tool.poetry.group.docs.dependencies]
-sphinx = ">=6.2.1,<8.0.0"
-tomli = { version = "^2.0.1", python = "<3.11" }
-m2r2 = "^0.3.3.post2"
-packaging = ">=23.1,<25.0"
-sphinx-autodoc-typehints = ">=1.23,<3.0"
-sphinx-copybutton = "^0.5.2"
-furo = ">=2022.12.7"
-sphinxcontrib-towncrier = ">=0.3.2,<0.5.0"
-pytest = "^7.3.1" # Required to import the gen_test_serializable function to list it in the docs
+mkdocs = "^1.6.0"
+mkdocs-material = "^9.5.30"
[tool.poetry.group.docs-ci]
optional = true