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') - -
- -
- - 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 + +
+ Logo + 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