diff --git a/CHANGELOG.md b/CHANGELOG.md
index e0bf73d17..c3e3694a5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Fixed double-paste into `Input` https://github.com/Textualize/textual/issues/1657
- Added a workaround for an apparent Windows Terminal paste issue https://github.com/Textualize/textual/issues/1661
- Fixes issue with renderable width calculation https://github.com/Textualize/textual/issues/1685
+- Fixed issue with app not processing Paste event https://github.com/Textualize/textual/issues/1666
## [0.10.1] - 2023-01-20
diff --git a/docs/_templates/python/material/attribute.html b/docs/_templates/python/material/attribute.html
new file mode 100644
index 000000000..b4f6bcaf8
--- /dev/null
+++ b/docs/_templates/python/material/attribute.html
@@ -0,0 +1,67 @@
+{{ log.debug("Rendering " + attribute.path) }}
+
+
+{% with html_id = attribute.path %}
+
+ {% if root %}
+ {% set show_full_path = config.show_root_full_path %}
+ {% set root_members = True %}
+ {% elif root_members %}
+ {% set show_full_path = config.show_root_members_full_path or config.show_object_full_path %}
+ {% set root_members = False %}
+ {% else %}
+ {% set show_full_path = config.show_object_full_path %}
+ {% endif %}
+
+ {% if not root or config.show_root_heading %}
+
+ {% filter heading(heading_level,
+ role="data" if attribute.parent.kind.value == "module" else "attr",
+ id=html_id,
+ class="doc doc-heading",
+ toc_label=attribute.name) %}
+
+ {% if config.separate_signature %}
+
{% if show_full_path %}{{ attribute.path }}{% else %}{{ attribute.name }}{% endif %}
+ {% else %}
+ {% filter highlight(language="python", inline=True) %}
+ {% if show_full_path %}{{ attribute.path }}{% else %}{{ attribute.name }}{% endif %}
+ {% if attribute.annotation %}: {{ attribute.annotation }}{% endif %}
+ {% endfilter %}
+ {% endif %}
+
+ {% with labels = attribute.labels %}
+ {% include "labels.html" with context %}
+ {% endwith %}
+
+ {% endfilter %}
+
+ {% if config.separate_signature %}
+ {% filter highlight(language="python", inline=False) %}
+ {% filter format_code(config.line_length) %}
+ {% if show_full_path %}{{ attribute.path }}{% else %}{{ attribute.name }}{% endif %}
+ {% if attribute.annotation %}: {{ attribute.annotation|safe }}{% endif %}
+ {% endfilter %}
+ {% endfilter %}
+ {% endif %}
+
+ {% else %}
+ {% if config.show_root_toc_entry %}
+ {% filter heading(heading_level,
+ role="data" if attribute.parent.kind.value == "module" else "attr",
+ id=html_id,
+ toc_label=attribute.path if config.show_root_full_path else attribute.name,
+ hidden=True) %}
+ {% endfilter %}
+ {% endif %}
+ {% set heading_level = heading_level - 1 %}
+ {% endif %}
+
+
+ {% with docstring_sections = attribute.docstring.parsed %}
+ {% include "docstring.html" with context %}
+ {% endwith %}
+
+
+{% endwith %}
+
diff --git a/docs/widgets/_template.md b/docs/widgets/_template.md
new file mode 100644
index 000000000..1e8c6f972
--- /dev/null
+++ b/docs/widgets/_template.md
@@ -0,0 +1,64 @@
+# Widget
+
+Widget description.
+
+- [ ] Focusable
+- [ ] Container
+
+
+## Example
+
+Example app showing the widget:
+
+=== "Output"
+
+ ```{.textual path="docs/examples/widgets/checkbox.py"}
+ ```
+
+=== "checkbox.py"
+
+ ```python
+ --8<-- "docs/examples/widgets/checkbox.py"
+ ```
+
+=== "checkbox.css"
+
+ ```sass
+ --8<-- "docs/examples/widgets/checkbox.css"
+ ```
+
+
+## Reactive attributes
+
+
+## Bindings
+
+The WIDGET widget defines directly the following bindings:
+
+::: textual.widgets.WIDGET.BINDINGS
+ options:
+ show_root_heading: false
+ show_root_toc_entry: false
+
+
+## Component classes
+
+The WIDGET widget provides the following component classes:
+
+::: textual.widget.WIDGET.COMPONENT_CLASSES
+ options:
+ show_root_heading: false
+ show_root_toc_entry: false
+
+
+## Additional notes
+
+- Did you know this?
+- Another pro tip.
+
+
+## See also
+
+- [WIDGET](../api/WIDGET.md) code reference.
+- Another related API.
+- Something else useful.
diff --git a/docs/widgets/button.md b/docs/widgets/button.md
index ff7436d3b..d5b07ec96 100644
--- a/docs/widgets/button.md
+++ b/docs/widgets/button.md
@@ -39,15 +39,7 @@ Clicking any of the non-disabled buttons in the example app below will result th
## Messages
-### Pressed
-
-The `Button.Pressed` message is sent when the button is pressed.
-
-- [x] Bubbles
-
-#### Attributes
-
-_No other attributes_
+### ::: textual.widgets.Button.Pressed
## Additional Notes
diff --git a/docs/widgets/checkbox.md b/docs/widgets/checkbox.md
index 6a8acc612..a5a247ef9 100644
--- a/docs/widgets/checkbox.md
+++ b/docs/widgets/checkbox.md
@@ -32,25 +32,31 @@ The example below shows checkboxes in various states.
| ------- | ------ | ------- | ---------------------------------- |
| `value` | `bool` | `False` | The default value of the checkbox. |
+## Bindings
+
+The checkbox widget defines directly the following bindings:
+
+::: textual.widgets.Checkbox.BINDINGS
+ options:
+ show_root_heading: false
+ show_root_toc_entry: false
+
+## Component Classes
+
+The checkbox widget provides the following component classes:
+
+::: textual.widgets.Checkbox.COMPONENT_CLASSES
+ options:
+ show_root_heading: false
+ show_root_toc_entry: false
+
## Messages
-### Pressed
-
-The `Checkbox.Changed` message is sent when the checkbox is toggled.
-
-- [x] Bubbles
-
-#### Attributes
-
-| attribute | type | purpose |
-| --------- | ------ | ------------------------------ |
-| `value` | `bool` | The new value of the checkbox. |
+### ::: textual.widgets.Checkbox.Changed
## Additional Notes
- To remove the spacing around a checkbox, set `border: none;` and `padding: 0;`.
-- The `.checkbox--switch` component class can be used to change the color and background of the switch.
-- When focused, the ++enter++ or ++space++ keys can be used to toggle the checkbox.
## See Also
diff --git a/docs/widgets/data_table.md b/docs/widgets/data_table.md
index a593dc4c2..9dd918d9d 100644
--- a/docs/widgets/data_table.md
+++ b/docs/widgets/data_table.md
@@ -48,6 +48,24 @@ The example below populates a table with CSV data.
### ::: textual.widgets.DataTable.ColumnSelected
+## Bindings
+
+The data table widget defines directly the following bindings:
+
+::: textual.widgets.DataTable.BINDINGS
+ options:
+ show_root_heading: false
+ show_root_toc_entry: false
+
+## Component Classes
+
+The data table widget provides the following component classes:
+
+::: textual.widgets.DataTable.COMPONENT_CLASSES
+ options:
+ show_root_heading: false
+ show_root_toc_entry: false
+
## See Also
* [DataTable][textual.widgets.DataTable] code reference
diff --git a/docs/widgets/directory_tree.md b/docs/widgets/directory_tree.md
index 27e0af9ab..a43ae5beb 100644
--- a/docs/widgets/directory_tree.md
+++ b/docs/widgets/directory_tree.md
@@ -16,17 +16,7 @@ The example below creates a simple tree to navigate the current working director
## Messages
-### FileSelected
-
-The `DirectoryTree.FileSelected` message is sent when the user selects a file in the tree
-
-- [x] Bubbles
-
-#### Attributes
-
-| attribute | type | purpose |
-| --------- | ----- | ----------------- |
-| `path` | `str` | Path of the file. |
+### ::: textual.widgets.DirectoryTree.FileSelected
## Reactive Attributes
@@ -36,6 +26,14 @@ The `DirectoryTree.FileSelected` message is sent when the user selects a file in
| `show_guides` | `bool` | `True` | Show guide lines between levels. |
| `guide_depth` | `int` | `4` | Amount of indentation between parent and child. |
+## Component Classes
+
+The directory tree widget provides the following component classes:
+
+::: textual.widgets.DirectoryTree.COMPONENT_CLASSES
+ options:
+ show_root_heading: false
+ show_root_toc_entry: false
## See Also
diff --git a/docs/widgets/footer.md b/docs/widgets/footer.md
index e45b147db..d500ba66b 100644
--- a/docs/widgets/footer.md
+++ b/docs/widgets/footer.md
@@ -32,6 +32,15 @@ widget. Notice how the `Footer` automatically displays the keybinding.
This widget sends no messages.
+## Component Classes
+
+The footer widget provides the following component classes:
+
+::: textual.widgets.Footer.COMPONENT_CLASSES
+ options:
+ show_root_heading: false
+ show_root_toc_entry: false
+
## Additional Notes
* You can prevent keybindings from appearing in the footer by setting the `show` argument of the `Binding` to `False`.
diff --git a/docs/widgets/input.md b/docs/widgets/input.md
index 586fd1ca5..ee6183cf8 100644
--- a/docs/widgets/input.md
+++ b/docs/widgets/input.md
@@ -32,31 +32,27 @@ The example below shows how you might create a simple form using two `Input` wid
## Messages
-### Changed
+### ::: textual.widgets.Input.Changed
-The `Input.Changed` message is sent when the value in the text input changes.
+### ::: textual.widgets.Input.Submitted
-- [x] Bubbles
+## Bindings
-#### Attributes
+The input widget defines directly the following bindings:
-| attribute | type | purpose |
-| --------- | ----- | -------------------------------- |
-| `value` | `str` | The new value in the text input. |
+::: textual.widgets.Input.BINDINGS
+ options:
+ show_root_heading: false
+ show_root_toc_entry: false
+## Component Classes
-### Submitted
-
-The `Input.Submitted` message is sent when you press ++enter++ with the text field submitted.
-
-- [x] Bubbles
-
-#### Attributes
-
-| attribute | type | purpose |
-| --------- | ----- | -------------------------------- |
-| `value` | `str` | The new value in the text input. |
+The input widget provides the following component classes:
+::: textual.widgets.Input.COMPONENT_CLASSES
+ options:
+ show_root_heading: false
+ show_root_toc_entry: false
## Additional Notes
diff --git a/docs/widgets/list_item.md b/docs/widgets/list_item.md
index 5a9ed4435..698214159 100644
--- a/docs/widgets/list_item.md
+++ b/docs/widgets/list_item.md
@@ -27,13 +27,6 @@ of multiple `ListItem`s. The arrow keys can be used to navigate the list.
|---------------|--------|---------|--------------------------------------|
| `highlighted` | `bool` | `False` | True if this ListItem is highlighted |
-## Messages
-
-### Selected
-
-The `ListItem.Selected` message is sent when the item is selected.
-
- - [x] Bubbles
#### Attributes
diff --git a/docs/widgets/list_view.md b/docs/widgets/list_view.md
index fe7a8c563..8bca015df 100644
--- a/docs/widgets/list_view.md
+++ b/docs/widgets/list_view.md
@@ -35,34 +35,18 @@ The example below shows an app with a simple `ListView`.
## Messages
-### Highlighted
+### ::: textual.widgets.ListView.Highlighted
-The `ListView.Highlighted` message is emitted when the highlight changes.
-This happens when you use the arrow keys on your keyboard and when you
-click on a list item.
+### ::: textual.widgets.ListView.Selected
-- [x] Bubbles
+## Bindings
-#### Attributes
-
-| attribute | type | purpose |
-| --------- | ---------- | ------------------------------ |
-| `item` | `ListItem` | The item that was highlighted. |
-
-### Selected
-
-The `ListView.Selected` message is emitted when a list item is selected.
-You can select a list item by pressing ++enter++ while it is highlighted,
-or by clicking on it.
-
-- [x] Bubbles
-
-#### Attributes
-
-| attribute | type | purpose |
-| --------- | ---------- | --------------------------- |
-| `item` | `ListItem` | The item that was selected. |
+The list view widget defines directly the following bindings:
+::: textual.widgets.ListView.BINDINGS
+ options:
+ show_root_heading: false
+ show_root_toc_entry: false
## See Also
diff --git a/docs/widgets/tree.md b/docs/widgets/tree.md
index 7f0772566..5ae8b14ef 100644
--- a/docs/widgets/tree.md
+++ b/docs/widgets/tree.md
@@ -32,47 +32,33 @@ Tree widgets have a "root" attribute which is an instance of a [TreeNode][textua
| `show_guides` | `bool` | `True` | Show guide lines between levels. |
| `guide_depth` | `int` | `4` | Amount of indentation between parent and child. |
-
-
## Messages
-### NodeSelected
+### ::: textual.widgets.Tree.NodeCollapsed
-The `Tree.NodeSelected` message is sent when the user selects a tree node.
+### ::: textual.widgets.Tree.NodeExpanded
+### ::: textual.widgets.Tree.NodeHighlighted
-#### Attributes
+### ::: textual.widgets.Tree.NodeSelected
-| attribute | type | purpose |
-| --------- | ----------------------------------------- | -------------- |
-| `node` | [TreeNode][textual.widgets.tree.TreeNode] | Selected node. |
+## Bindings
+The tree widget defines directly the following bindings:
-### NodeExpanded
-
-The `Tree.NodeExpanded` message is sent when the user expands a node in the tree.
-
-#### Attributes
-
-| attribute | type | purpose |
-| --------- | ----------------------------------------- | -------------- |
-| `node` | [TreeNode][textual.widgets.tree.TreeNode] | Expanded node. |
-
-
-### NodeCollapsed
-
-
-The `Tree.NodeCollapsed` message is sent when the user expands a node in the tree.
-
-
-#### Attributes
-
-| attribute | type | purpose |
-| --------- | ----------------------------------------- | --------------- |
-| `node` | [TreeNode][textual.widgets.tree.TreeNode] | Collapsed node. |
+::: textual.widgets.Tree.BINDINGS
+ options:
+ show_root_heading: false
+ show_root_toc_entry: false
+## Component Classes
+The tree widget provides the following component classes:
+::: textual.widgets.Tree.COMPONENT_CLASSES
+ options:
+ show_root_heading: false
+ show_root_toc_entry: false
## See Also
diff --git a/mkdocs.yml b/mkdocs.yml
index a9b8de413..1748de127 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -128,17 +128,17 @@ nav:
- "widgets/button.md"
- "widgets/checkbox.md"
- "widgets/data_table.md"
- - "widgets/text_log.md"
- "widgets/directory_tree.md"
- "widgets/footer.md"
- "widgets/header.md"
- "widgets/index.md"
- "widgets/input.md"
- "widgets/label.md"
- - "widgets/list_view.md"
- "widgets/list_item.md"
+ - "widgets/list_view.md"
- "widgets/placeholder.md"
- "widgets/static.md"
+ - "widgets/text_log.md"
- "widgets/tree.md"
- API:
- "api/index.md"
@@ -252,6 +252,7 @@ plugins:
- search:
- autorefs:
- mkdocstrings:
+ custom_templates: docs/_templates
default_handler: python
handlers:
python:
@@ -263,9 +264,11 @@ plugins:
- "!^_"
- "^__init__$"
- "!^can_replace$"
-
watch:
- src/textual
+- exclude:
+ glob:
+ - "**/_template.md"
extra_css:
diff --git a/poetry.lock b/poetry.lock
index 1f4cd039d..7cd75899a 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,3 +1,5 @@
+# This file is automatically @generated by Poetry and should not be changed by hand.
+
[[package]]
name = "aiohttp"
version = "3.8.3"
@@ -5,1033 +7,7 @@ description = "Async http client/server framework (asyncio)"
category = "main"
optional = false
python-versions = ">=3.6"
-
-[package.dependencies]
-aiosignal = ">=1.1.2"
-async-timeout = ">=4.0.0a3,<5.0"
-asynctest = {version = "0.13.0", markers = "python_version < \"3.8\""}
-attrs = ">=17.3.0"
-charset-normalizer = ">=2.0,<3.0"
-frozenlist = ">=1.1.1"
-multidict = ">=4.5,<7.0"
-typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""}
-yarl = ">=1.0,<2.0"
-
-[package.extras]
-speedups = ["Brotli", "aiodns", "cchardet"]
-
-[[package]]
-name = "aiosignal"
-version = "1.3.1"
-description = "aiosignal: a list of registered asynchronous callbacks"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-frozenlist = ">=1.1.0"
-
-[[package]]
-name = "anyio"
-version = "3.6.2"
-description = "High level compatibility layer for multiple asynchronous event loop implementations"
-category = "dev"
-optional = false
-python-versions = ">=3.6.2"
-
-[package.dependencies]
-idna = ">=2.8"
-sniffio = ">=1.1"
-typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
-
-[package.extras]
-doc = ["packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"]
-test = ["contextlib2", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "uvloop (>=0.15)"]
-trio = ["trio (>=0.16,<0.22)"]
-
-[[package]]
-name = "async-timeout"
-version = "4.0.2"
-description = "Timeout context manager for asyncio programs"
-category = "main"
-optional = false
-python-versions = ">=3.6"
-
-[package.dependencies]
-typing-extensions = {version = ">=3.6.5", markers = "python_version < \"3.8\""}
-
-[[package]]
-name = "asynctest"
-version = "0.13.0"
-description = "Enhance the standard unittest package with features for testing asyncio libraries"
-category = "main"
-optional = false
-python-versions = ">=3.5"
-
-[[package]]
-name = "attrs"
-version = "22.2.0"
-description = "Classes Without Boilerplate"
-category = "main"
-optional = false
-python-versions = ">=3.6"
-
-[package.extras]
-cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"]
-dev = ["attrs[docs,tests]"]
-docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"]
-tests = ["attrs[tests-no-zope]", "zope.interface"]
-tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"]
-
-[[package]]
-name = "black"
-version = "22.8.0"
-description = "The uncompromising code formatter."
-category = "dev"
-optional = false
-python-versions = ">=3.6.2"
-
-[package.dependencies]
-click = ">=8.0.0"
-mypy-extensions = ">=0.4.3"
-pathspec = ">=0.9.0"
-platformdirs = ">=2"
-tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""}
-typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""}
-typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}
-
-[package.extras]
-colorama = ["colorama (>=0.4.3)"]
-d = ["aiohttp (>=3.7.4)"]
-jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
-uvloop = ["uvloop (>=0.15.2)"]
-
-[[package]]
-name = "cached-property"
-version = "1.5.2"
-description = "A decorator for caching properties in classes."
-category = "dev"
-optional = false
-python-versions = "*"
-
-[[package]]
-name = "certifi"
-version = "2022.12.7"
-description = "Python package for providing Mozilla's CA Bundle."
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[[package]]
-name = "cfgv"
-version = "3.3.1"
-description = "Validate configuration and produce human readable error messages."
-category = "dev"
-optional = false
-python-versions = ">=3.6.1"
-
-[[package]]
-name = "charset-normalizer"
-version = "2.1.1"
-description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
-category = "main"
-optional = false
-python-versions = ">=3.6.0"
-
-[package.extras]
-unicode-backport = ["unicodedata2"]
-
-[[package]]
-name = "click"
-version = "8.1.3"
-description = "Composable command line interface toolkit"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-colorama = {version = "*", markers = "platform_system == \"Windows\""}
-importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
-
-[[package]]
-name = "colorama"
-version = "0.4.6"
-description = "Cross-platform colored terminal text."
-category = "main"
-optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
-
-[[package]]
-name = "colored"
-version = "1.4.4"
-description = "Simple library for color and formatting to terminal"
-category = "dev"
-optional = false
-python-versions = "*"
-
-[[package]]
-name = "coverage"
-version = "7.1.0"
-description = "Code coverage measurement for Python"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.extras]
-toml = ["tomli"]
-
-[[package]]
-name = "distlib"
-version = "0.3.6"
-description = "Distribution utilities"
-category = "dev"
-optional = false
-python-versions = "*"
-
-[[package]]
-name = "exceptiongroup"
-version = "1.1.0"
-description = "Backport of PEP 654 (exception groups)"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.extras]
-test = ["pytest (>=6)"]
-
-[[package]]
-name = "filelock"
-version = "3.9.0"
-description = "A platform independent file lock."
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.extras]
-docs = ["furo (>=2022.12.7)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"]
-testing = ["covdefaults (>=2.2.2)", "coverage (>=7.0.1)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-timeout (>=2.1)"]
-
-[[package]]
-name = "frozenlist"
-version = "1.3.3"
-description = "A list-like structure which implements collections.abc.MutableSequence"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[[package]]
-name = "ghp-import"
-version = "2.1.0"
-description = "Copy your docs directly to the gh-pages branch."
-category = "dev"
-optional = false
-python-versions = "*"
-
-[package.dependencies]
-python-dateutil = ">=2.8.1"
-
-[package.extras]
-dev = ["flake8", "markdown", "twine", "wheel"]
-
-[[package]]
-name = "gitdb"
-version = "4.0.10"
-description = "Git Object Database"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-smmap = ">=3.0.1,<6"
-
-[[package]]
-name = "gitpython"
-version = "3.1.30"
-description = "GitPython is a python library used to interact with Git repositories"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-gitdb = ">=4.0.1,<5"
-typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\""}
-
-[[package]]
-name = "griffe"
-version = "0.25.4"
-description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API."
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-cached-property = {version = "*", markers = "python_version < \"3.8\""}
-colorama = ">=0.4"
-
-[package.extras]
-async = ["aiofiles (>=0.7,<1.0)"]
-
-[[package]]
-name = "h11"
-version = "0.14.0"
-description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
-
-[[package]]
-name = "httpcore"
-version = "0.16.3"
-description = "A minimal low-level HTTP client."
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-anyio = ">=3.0,<5.0"
-certifi = "*"
-h11 = ">=0.13,<0.15"
-sniffio = ">=1.0.0,<2.0.0"
-
-[package.extras]
-http2 = ["h2 (>=3,<5)"]
-socks = ["socksio (>=1.0.0,<2.0.0)"]
-
-[[package]]
-name = "httpx"
-version = "0.23.3"
-description = "The next generation HTTP client."
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-certifi = "*"
-httpcore = ">=0.15.0,<0.17.0"
-rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]}
-sniffio = "*"
-
-[package.extras]
-brotli = ["brotli", "brotlicffi"]
-cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<13)"]
-http2 = ["h2 (>=3,<5)"]
-socks = ["socksio (>=1.0.0,<2.0.0)"]
-
-[[package]]
-name = "identify"
-version = "2.5.15"
-description = "File identification library for Python"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.extras]
-license = ["ukkonen"]
-
-[[package]]
-name = "idna"
-version = "3.4"
-description = "Internationalized Domain Names in Applications (IDNA)"
-category = "main"
-optional = false
-python-versions = ">=3.5"
-
-[[package]]
-name = "importlib-metadata"
-version = "4.13.0"
-description = "Read metadata from Python packages"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
-zipp = ">=0.5"
-
-[package.extras]
-docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"]
-perf = ["ipython"]
-testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"]
-
-[[package]]
-name = "iniconfig"
-version = "2.0.0"
-description = "brain-dead simple config-ini parsing"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[[package]]
-name = "jinja2"
-version = "3.0.3"
-description = "A very fast and expressive template engine."
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[package.dependencies]
-MarkupSafe = ">=2.0"
-
-[package.extras]
-i18n = ["Babel (>=2.7)"]
-
-[[package]]
-name = "markdown"
-version = "3.3.7"
-description = "Python implementation of Markdown."
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[package.dependencies]
-importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""}
-
-[package.extras]
-testing = ["coverage", "pyyaml"]
-
-[[package]]
-name = "markdown-it-py"
-version = "2.1.0"
-description = "Python port of markdown-it. Markdown parsing, done right!"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-mdurl = ">=0.1,<1.0"
-typing_extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""}
-
-[package.extras]
-benchmarking = ["psutil", "pytest", "pytest-benchmark (>=3.2,<4.0)"]
-code-style = ["pre-commit (==2.6)"]
-compare = ["commonmark (>=0.9.1,<0.10.0)", "markdown (>=3.3.6,<3.4.0)", "mistletoe (>=0.8.1,<0.9.0)", "mistune (>=2.0.2,<2.1.0)", "panflute (>=2.1.3,<2.2.0)"]
-linkify = ["linkify-it-py (>=1.0,<2.0)"]
-plugins = ["mdit-py-plugins"]
-profiling = ["gprof2dot"]
-rtd = ["attrs", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
-testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
-
-[[package]]
-name = "markupsafe"
-version = "2.1.2"
-description = "Safely add untrusted strings to HTML/XML markup."
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[[package]]
-name = "mdurl"
-version = "0.1.2"
-description = "Markdown URL utilities"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[[package]]
-name = "mergedeep"
-version = "1.3.4"
-description = "A deep merge function for ๐."
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[[package]]
-name = "mkdocs"
-version = "1.4.2"
-description = "Project documentation with Markdown."
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-click = ">=7.0"
-colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""}
-ghp-import = ">=1.0"
-importlib-metadata = {version = ">=4.3", markers = "python_version < \"3.10\""}
-jinja2 = ">=2.11.1"
-markdown = ">=3.2.1,<3.4"
-mergedeep = ">=1.3.4"
-packaging = ">=20.5"
-pyyaml = ">=5.1"
-pyyaml-env-tag = ">=0.1"
-typing-extensions = {version = ">=3.10", markers = "python_version < \"3.8\""}
-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.3)", "jinja2 (==2.11.1)", "markdown (==3.2.1)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "packaging (==20.5)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "typing-extensions (==3.10)", "watchdog (==2.0)"]
-
-[[package]]
-name = "mkdocs-autorefs"
-version = "0.4.1"
-description = "Automatically link across pages in MkDocs."
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-Markdown = ">=3.3"
-mkdocs = ">=1.1"
-
-[[package]]
-name = "mkdocs-material"
-version = "8.5.11"
-description = "Documentation that simply works"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-jinja2 = ">=3.0.2"
-markdown = ">=3.2"
-mkdocs = ">=1.4.0"
-mkdocs-material-extensions = ">=1.1"
-pygments = ">=2.12"
-pymdown-extensions = ">=9.4"
-requests = ">=2.26"
-
-[[package]]
-name = "mkdocs-material-extensions"
-version = "1.1.1"
-description = "Extension pack for Python Markdown and MkDocs Material."
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[[package]]
-name = "mkdocs-rss-plugin"
-version = "1.5.0"
-description = "MkDocs plugin which generates a static RSS feed using git log and page.meta."
-category = "dev"
-optional = false
-python-versions = ">=3.7, <4"
-
-[package.dependencies]
-GitPython = ">=3.1,<3.2"
-mkdocs = ">=1.1,<2"
-pytz = {version = ">=2022.0.0,<2023.0.0", markers = "python_version < \"3.9\""}
-tzdata = {version = ">=2022.0.0,<2023.0.0", markers = "python_version >= \"3.9\" and sys_platform == \"win32\""}
-
-[package.extras]
-dev = ["black", "feedparser (>=6.0,<6.1)", "flake8 (>=4,<5.1)", "pre-commit (>=2.10,<2.21)", "pytest-cov (>=4.0.0,<4.1.0)", "validator-collection (>=1.5,<1.6)"]
-doc = ["mkdocs-bootswatch (>=1,<2)", "mkdocs-minify-plugin (>=0.5.0,<0.6.0)", "pygments (>=2.5,<3)", "pymdown-extensions (>=7,<10)"]
-
-[[package]]
-name = "mkdocstrings"
-version = "0.20.0"
-description = "Automatic documentation from sources, for MkDocs."
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-Jinja2 = ">=2.11.1"
-Markdown = ">=3.3"
-MarkupSafe = ">=1.1"
-mkdocs = ">=1.2"
-mkdocs-autorefs = ">=0.3.1"
-mkdocstrings-python = {version = ">=0.5.2", optional = true, markers = "extra == \"python\""}
-pymdown-extensions = ">=6.3"
-
-[package.extras]
-crystal = ["mkdocstrings-crystal (>=0.3.4)"]
-python = ["mkdocstrings-python (>=0.5.2)"]
-python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"]
-
-[[package]]
-name = "mkdocstrings-python"
-version = "0.8.3"
-description = "A Python handler for mkdocstrings."
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-griffe = ">=0.24"
-mkdocstrings = ">=0.19"
-
-[[package]]
-name = "msgpack"
-version = "1.0.4"
-description = "MessagePack serializer"
-category = "main"
-optional = true
-python-versions = "*"
-
-[[package]]
-name = "multidict"
-version = "6.0.4"
-description = "multidict implementation"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[[package]]
-name = "mypy"
-version = "0.990"
-description = "Optional static typing for Python"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-mypy-extensions = ">=0.4.3"
-tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
-typed-ast = {version = ">=1.4.0,<2", markers = "python_version < \"3.8\""}
-typing-extensions = ">=3.10"
-
-[package.extras]
-dmypy = ["psutil (>=4.0)"]
-install-types = ["pip"]
-python2 = ["typed-ast (>=1.4.0,<2)"]
-reports = ["lxml"]
-
-[[package]]
-name = "mypy-extensions"
-version = "0.4.3"
-description = "Experimental type system extensions for programs checked with the mypy typechecker."
-category = "dev"
-optional = false
-python-versions = "*"
-
-[[package]]
-name = "nanoid"
-version = "2.0.0"
-description = "A tiny, secure, URL-friendly, unique string ID generator for Python"
-category = "main"
-optional = false
-python-versions = "*"
-
-[[package]]
-name = "nodeenv"
-version = "1.7.0"
-description = "Node.js virtual environment builder"
-category = "dev"
-optional = false
-python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*"
-
-[package.dependencies]
-setuptools = "*"
-
-[[package]]
-name = "packaging"
-version = "23.0"
-description = "Core utilities for Python packages"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[[package]]
-name = "pathspec"
-version = "0.11.0"
-description = "Utility library for gitignore style pattern matching of file paths."
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[[package]]
-name = "platformdirs"
-version = "2.6.2"
-description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-typing-extensions = {version = ">=4.4", markers = "python_version < \"3.8\""}
-
-[package.extras]
-docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"]
-test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"]
-
-[[package]]
-name = "pluggy"
-version = "1.0.0"
-description = "plugin and hook calling mechanisms for python"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[package.dependencies]
-importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
-
-[package.extras]
-dev = ["pre-commit", "tox"]
-testing = ["pytest", "pytest-benchmark"]
-
-[[package]]
-name = "pre-commit"
-version = "2.21.0"
-description = "A framework for managing and maintaining multi-language pre-commit hooks."
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-cfgv = ">=2.0.0"
-identify = ">=1.0.0"
-importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
-nodeenv = ">=0.11.1"
-pyyaml = ">=5.1"
-virtualenv = ">=20.10.0"
-
-[[package]]
-name = "pygments"
-version = "2.14.0"
-description = "Pygments is a syntax highlighting package written in Python."
-category = "main"
-optional = false
-python-versions = ">=3.6"
-
-[package.extras]
-plugins = ["importlib-metadata"]
-
-[[package]]
-name = "pymdown-extensions"
-version = "9.9.2"
-description = "Extension pack for Python Markdown."
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-markdown = ">=3.2"
-
-[[package]]
-name = "pytest"
-version = "7.2.1"
-description = "pytest: simple powerful testing with Python"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-attrs = ">=19.2.0"
-colorama = {version = "*", markers = "sys_platform == \"win32\""}
-exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
-importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
-iniconfig = "*"
-packaging = "*"
-pluggy = ">=0.12,<2.0"
-tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
-
-[package.extras]
-testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
-
-[[package]]
-name = "pytest-aiohttp"
-version = "1.0.4"
-description = "Pytest plugin for aiohttp support"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-aiohttp = ">=3.8.1"
-pytest = ">=6.1.0"
-pytest-asyncio = ">=0.17.2"
-
-[package.extras]
-testing = ["coverage (==6.2)", "mypy (==0.931)"]
-
-[[package]]
-name = "pytest-asyncio"
-version = "0.20.3"
-description = "Pytest support for asyncio"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-pytest = ">=6.1.0"
-typing-extensions = {version = ">=3.7.2", markers = "python_version < \"3.8\""}
-
-[package.extras]
-docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"]
-testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"]
-
-[[package]]
-name = "pytest-cov"
-version = "2.12.1"
-description = "Pytest plugin for measuring coverage."
-category = "dev"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-
-[package.dependencies]
-coverage = ">=5.2.1"
-pytest = ">=4.6"
-toml = "*"
-
-[package.extras]
-testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"]
-
-[[package]]
-name = "python-dateutil"
-version = "2.8.2"
-description = "Extensions to the standard Python datetime module"
-category = "dev"
-optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
-
-[package.dependencies]
-six = ">=1.5"
-
-[[package]]
-name = "pytz"
-version = "2022.7.1"
-description = "World timezone definitions, modern and historical"
-category = "dev"
-optional = false
-python-versions = "*"
-
-[[package]]
-name = "pyyaml"
-version = "6.0"
-description = "YAML parser and emitter for Python"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[[package]]
-name = "pyyaml-env-tag"
-version = "0.1"
-description = "A custom YAML tag for referencing environment variables in YAML files. "
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[package.dependencies]
-pyyaml = "*"
-
-[[package]]
-name = "requests"
-version = "2.28.2"
-description = "Python HTTP for Humans."
-category = "dev"
-optional = false
-python-versions = ">=3.7, <4"
-
-[package.dependencies]
-certifi = ">=2017.4.17"
-charset-normalizer = ">=2,<4"
-idna = ">=2.5,<4"
-urllib3 = ">=1.21.1,<1.27"
-
-[package.extras]
-socks = ["PySocks (>=1.5.6,!=1.5.7)"]
-use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
-
-[[package]]
-name = "rfc3986"
-version = "1.5.0"
-description = "Validating URI References per RFC 3986"
-category = "dev"
-optional = false
-python-versions = "*"
-
-[package.dependencies]
-idna = {version = "*", optional = true, markers = "extra == \"idna2008\""}
-
-[package.extras]
-idna2008 = ["idna"]
-
-[[package]]
-name = "rich"
-version = "13.2.0"
-description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
-category = "main"
-optional = false
-python-versions = ">=3.7.0"
-
-[package.dependencies]
-markdown-it-py = ">=2.1.0,<3.0.0"
-pygments = ">=2.6.0,<3.0.0"
-typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""}
-
-[package.extras]
-jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"]
-
-[[package]]
-name = "setuptools"
-version = "66.1.1"
-description = "Easily download, build, install, upgrade, and uninstall Python packages"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.extras]
-docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
-testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
-testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
-
-[[package]]
-name = "six"
-version = "1.16.0"
-description = "Python 2 and 3 compatibility utilities"
-category = "dev"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
-
-[[package]]
-name = "smmap"
-version = "5.0.0"
-description = "A pure Python implementation of a sliding window memory map manager"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[[package]]
-name = "sniffio"
-version = "1.3.0"
-description = "Sniff out which async library your code is running under"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[[package]]
-name = "syrupy"
-version = "3.0.6"
-description = "Pytest Snapshot Test Utility"
-category = "dev"
-optional = false
-python-versions = ">=3.7,<4"
-
-[package.dependencies]
-colored = ">=1.3.92,<2.0.0"
-pytest = ">=5.1.0,<8.0.0"
-
-[[package]]
-name = "time-machine"
-version = "2.9.0"
-description = "Travel through time in your tests."
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-python-dateutil = "*"
-
-[[package]]
-name = "toml"
-version = "0.10.2"
-description = "Python Library for Tom's Obvious, Minimal Language"
-category = "dev"
-optional = false
-python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
-
-[[package]]
-name = "tomli"
-version = "2.0.1"
-description = "A lil' TOML parser"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[[package]]
-name = "typed-ast"
-version = "1.5.4"
-description = "a fork of Python 2 and 3 ast modules with type comment support"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[[package]]
-name = "typing-extensions"
-version = "4.4.0"
-description = "Backported and Experimental Type Hints for Python 3.7+"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[[package]]
-name = "tzdata"
-version = "2022.7"
-description = "Provider of IANA time zone data"
-category = "dev"
-optional = false
-python-versions = ">=2"
-
-[[package]]
-name = "urllib3"
-version = "1.26.14"
-description = "HTTP library with thread-safe connection pooling, file post, and more."
-category = "dev"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
-
-[package.extras]
-brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
-secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
-socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
-
-[[package]]
-name = "virtualenv"
-version = "20.17.1"
-description = "Virtual Python Environment builder"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[package.dependencies]
-distlib = ">=0.3.6,<1"
-filelock = ">=3.4.1,<4"
-importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.8\""}
-platformdirs = ">=2.4,<3"
-
-[package.extras]
-docs = ["proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-argparse (>=0.3.2)", "sphinx-rtd-theme (>=1)", "towncrier (>=22.8)"]
-testing = ["coverage (>=6.2)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=21.3)", "pytest (>=7.0.1)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.6.1)", "pytest-randomly (>=3.10.3)", "pytest-timeout (>=2.1)"]
-
-[[package]]
-name = "watchdog"
-version = "2.2.1"
-description = "Filesystem events monitoring"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[package.extras]
-watchmedo = ["PyYAML (>=3.10)"]
-
-[[package]]
-name = "yarl"
-version = "1.8.2"
-description = "Yet another URL library"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-idna = ">=2.0"
-multidict = ">=4.0"
-typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""}
-
-[[package]]
-name = "zipp"
-version = "3.11.0"
-description = "Backport of pathlib-compatible object wrapper for zip files"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[package.extras]
-docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"]
-testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
-
-[extras]
-dev = ["aiohttp", "click", "msgpack"]
-
-[metadata]
-lock-version = "1.1"
-python-versions = "^3.7"
-content-hash = "d76445ef1521cd4068907433b09d59fc1ed56f03e61063c5ad7376bb9823a8e7"
-
-[metadata.files]
-aiohttp = [
+files = [
{file = "aiohttp-3.8.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ba71c9b4dcbb16212f334126cc3d8beb6af377f6703d9dc2d9fb3874fd667ee9"},
{file = "aiohttp-3.8.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d24b8bb40d5c61ef2d9b6a8f4528c2f17f1c5d2d31fed62ec860f6006142e83e"},
{file = "aiohttp-3.8.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f88df3a83cf9df566f171adba39d5bd52814ac0b94778d2448652fc77f9eb491"},
@@ -1120,27 +96,112 @@ aiohttp = [
{file = "aiohttp-3.8.3-cp39-cp39-win_amd64.whl", hash = "sha256:88e5be56c231981428f4f506c68b6a46fa25c4123a2e86d156c58a8369d31ab7"},
{file = "aiohttp-3.8.3.tar.gz", hash = "sha256:3828fb41b7203176b82fe5d699e0d845435f2374750a44b480ea6b930f6be269"},
]
-aiosignal = [
+
+[package.dependencies]
+aiosignal = ">=1.1.2"
+async-timeout = ">=4.0.0a3,<5.0"
+asynctest = {version = "0.13.0", markers = "python_version < \"3.8\""}
+attrs = ">=17.3.0"
+charset-normalizer = ">=2.0,<3.0"
+frozenlist = ">=1.1.1"
+multidict = ">=4.5,<7.0"
+typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""}
+yarl = ">=1.0,<2.0"
+
+[package.extras]
+speedups = ["Brotli", "aiodns", "cchardet"]
+
+[[package]]
+name = "aiosignal"
+version = "1.3.1"
+description = "aiosignal: a list of registered asynchronous callbacks"
+category = "main"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"},
{file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"},
]
-anyio = [
+
+[package.dependencies]
+frozenlist = ">=1.1.0"
+
+[[package]]
+name = "anyio"
+version = "3.6.2"
+description = "High level compatibility layer for multiple asynchronous event loop implementations"
+category = "dev"
+optional = false
+python-versions = ">=3.6.2"
+files = [
{file = "anyio-3.6.2-py3-none-any.whl", hash = "sha256:fbbe32bd270d2a2ef3ed1c5d45041250284e31fc0a4df4a5a6071842051a51e3"},
{file = "anyio-3.6.2.tar.gz", hash = "sha256:25ea0d673ae30af41a0c442f81cf3b38c7e79fdc7b60335a4c14e05eb0947421"},
]
-async-timeout = [
+
+[package.dependencies]
+idna = ">=2.8"
+sniffio = ">=1.1"
+typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
+
+[package.extras]
+doc = ["packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"]
+test = ["contextlib2", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "uvloop (>=0.15)"]
+trio = ["trio (>=0.16,<0.22)"]
+
+[[package]]
+name = "async-timeout"
+version = "4.0.2"
+description = "Timeout context manager for asyncio programs"
+category = "main"
+optional = false
+python-versions = ">=3.6"
+files = [
{file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"},
{file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"},
]
-asynctest = [
+
+[package.dependencies]
+typing-extensions = {version = ">=3.6.5", markers = "python_version < \"3.8\""}
+
+[[package]]
+name = "asynctest"
+version = "0.13.0"
+description = "Enhance the standard unittest package with features for testing asyncio libraries"
+category = "main"
+optional = false
+python-versions = ">=3.5"
+files = [
{file = "asynctest-0.13.0-py3-none-any.whl", hash = "sha256:5da6118a7e6d6b54d83a8f7197769d046922a44d2a99c21382f0a6e4fadae676"},
{file = "asynctest-0.13.0.tar.gz", hash = "sha256:c27862842d15d83e6a34eb0b2866c323880eb3a75e4485b079ea11748fd77fac"},
]
-attrs = [
+
+[[package]]
+name = "attrs"
+version = "22.2.0"
+description = "Classes Without Boilerplate"
+category = "main"
+optional = false
+python-versions = ">=3.6"
+files = [
{file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"},
{file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"},
]
-black = [
+
+[package.extras]
+cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"]
+dev = ["attrs[docs,tests]"]
+docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"]
+tests = ["attrs[tests-no-zope]", "zope.interface"]
+tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"]
+
+[[package]]
+name = "black"
+version = "22.8.0"
+description = "The uncompromising code formatter."
+category = "dev"
+optional = false
+python-versions = ">=3.6.2"
+files = [
{file = "black-22.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ce957f1d6b78a8a231b18e0dd2d94a33d2ba738cd88a7fe64f53f659eea49fdd"},
{file = "black-22.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5107ea36b2b61917956d018bd25129baf9ad1125e39324a9b18248d362156a27"},
{file = "black-22.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8166b7bfe5dcb56d325385bd1d1e0f635f24aae14b3ae437102dedc0c186747"},
@@ -1165,34 +226,120 @@ black = [
{file = "black-22.8.0-py3-none-any.whl", hash = "sha256:d2c21d439b2baf7aa80d6dd4e3659259be64c6f49dfd0f32091063db0e006db4"},
{file = "black-22.8.0.tar.gz", hash = "sha256:792f7eb540ba9a17e8656538701d3eb1afcb134e3b45b71f20b25c77a8db7e6e"},
]
-cached-property = [
+
+[package.dependencies]
+click = ">=8.0.0"
+mypy-extensions = ">=0.4.3"
+pathspec = ">=0.9.0"
+platformdirs = ">=2"
+tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""}
+typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""}
+typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}
+
+[package.extras]
+colorama = ["colorama (>=0.4.3)"]
+d = ["aiohttp (>=3.7.4)"]
+jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
+uvloop = ["uvloop (>=0.15.2)"]
+
+[[package]]
+name = "cached-property"
+version = "1.5.2"
+description = "A decorator for caching properties in classes."
+category = "dev"
+optional = false
+python-versions = "*"
+files = [
{file = "cached-property-1.5.2.tar.gz", hash = "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130"},
{file = "cached_property-1.5.2-py2.py3-none-any.whl", hash = "sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0"},
]
-certifi = [
+
+[[package]]
+name = "certifi"
+version = "2022.12.7"
+description = "Python package for providing Mozilla's CA Bundle."
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+files = [
{file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"},
{file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"},
]
-cfgv = [
+
+[[package]]
+name = "cfgv"
+version = "3.3.1"
+description = "Validate configuration and produce human readable error messages."
+category = "dev"
+optional = false
+python-versions = ">=3.6.1"
+files = [
{file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"},
{file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"},
]
-charset-normalizer = [
+
+[[package]]
+name = "charset-normalizer"
+version = "2.1.1"
+description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
+category = "main"
+optional = false
+python-versions = ">=3.6.0"
+files = [
{file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"},
{file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"},
]
-click = [
+
+[package.extras]
+unicode-backport = ["unicodedata2"]
+
+[[package]]
+name = "click"
+version = "8.1.3"
+description = "Composable command line interface toolkit"
+category = "main"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
{file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
]
-colorama = [
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+description = "Cross-platform colored terminal text."
+category = "main"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
+files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
-colored = [
+
+[[package]]
+name = "colored"
+version = "1.4.4"
+description = "Simple library for color and formatting to terminal"
+category = "dev"
+optional = false
+python-versions = "*"
+files = [
{file = "colored-1.4.4.tar.gz", hash = "sha256:04ff4d4dd514274fe3b99a21bb52fb96f2688c01e93fba7bef37221e7cb56ce0"},
]
-coverage = [
+
+[[package]]
+name = "coverage"
+version = "7.1.0"
+description = "Code coverage measurement for Python"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "coverage-7.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3b946bbcd5a8231383450b195cfb58cb01cbe7f8949f5758566b881df4b33baf"},
{file = "coverage-7.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ec8e767f13be637d056f7e07e61d089e555f719b387a7070154ad80a0ff31801"},
{file = "coverage-7.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4a5a5879a939cb84959d86869132b00176197ca561c664fc21478c1eee60d75"},
@@ -1245,19 +392,61 @@ coverage = [
{file = "coverage-7.1.0-pp37.pp38.pp39-none-any.whl", hash = "sha256:755e89e32376c850f826c425ece2c35a4fc266c081490eb0a841e7c1cb0d3bda"},
{file = "coverage-7.1.0.tar.gz", hash = "sha256:10188fe543560ec4874f974b5305cd1a8bdcfa885ee00ea3a03733464c4ca265"},
]
-distlib = [
+
+[package.extras]
+toml = ["tomli"]
+
+[[package]]
+name = "distlib"
+version = "0.3.6"
+description = "Distribution utilities"
+category = "dev"
+optional = false
+python-versions = "*"
+files = [
{file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"},
{file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"},
]
-exceptiongroup = [
+
+[[package]]
+name = "exceptiongroup"
+version = "1.1.0"
+description = "Backport of PEP 654 (exception groups)"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "exceptiongroup-1.1.0-py3-none-any.whl", hash = "sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e"},
{file = "exceptiongroup-1.1.0.tar.gz", hash = "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23"},
]
-filelock = [
+
+[package.extras]
+test = ["pytest (>=6)"]
+
+[[package]]
+name = "filelock"
+version = "3.9.0"
+description = "A platform independent file lock."
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "filelock-3.9.0-py3-none-any.whl", hash = "sha256:f58d535af89bb9ad5cd4df046f741f8553a418c01a7856bf0d173bbc9f6bd16d"},
{file = "filelock-3.9.0.tar.gz", hash = "sha256:7b319f24340b51f55a2bf7a12ac0755a9b03e718311dac567a0f4f7fabd2f5de"},
]
-frozenlist = [
+
+[package.extras]
+docs = ["furo (>=2022.12.7)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"]
+testing = ["covdefaults (>=2.2.2)", "coverage (>=7.0.1)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-timeout (>=2.1)"]
+
+[[package]]
+name = "frozenlist"
+version = "1.3.3"
+description = "A list-like structure which implements collections.abc.MutableSequence"
+category = "main"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "frozenlist-1.3.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff8bf625fe85e119553b5383ba0fb6aa3d0ec2ae980295aaefa552374926b3f4"},
{file = "frozenlist-1.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dfbac4c2dfcc082fcf8d942d1e49b6aa0766c19d3358bd86e2000bf0fa4a9cf0"},
{file = "frozenlist-1.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b1c63e8d377d039ac769cd0926558bb7068a1f7abb0f003e3717ee003ad85530"},
@@ -1333,63 +522,266 @@ frozenlist = [
{file = "frozenlist-1.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:cfe33efc9cb900a4c46f91a5ceba26d6df370ffddd9ca386eb1d4f0ad97b9ea9"},
{file = "frozenlist-1.3.3.tar.gz", hash = "sha256:58bcc55721e8a90b88332d6cd441261ebb22342e238296bb330968952fbb3a6a"},
]
-ghp-import = [
+
+[[package]]
+name = "ghp-import"
+version = "2.1.0"
+description = "Copy your docs directly to the gh-pages branch."
+category = "main"
+optional = false
+python-versions = "*"
+files = [
{file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"},
{file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"},
]
-gitdb = [
+
+[package.dependencies]
+python-dateutil = ">=2.8.1"
+
+[package.extras]
+dev = ["flake8", "markdown", "twine", "wheel"]
+
+[[package]]
+name = "gitdb"
+version = "4.0.10"
+description = "Git Object Database"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "gitdb-4.0.10-py3-none-any.whl", hash = "sha256:c286cf298426064079ed96a9e4a9d39e7f3e9bf15ba60701e95f5492f28415c7"},
{file = "gitdb-4.0.10.tar.gz", hash = "sha256:6eb990b69df4e15bad899ea868dc46572c3f75339735663b81de79b06f17eb9a"},
]
-gitpython = [
+
+[package.dependencies]
+smmap = ">=3.0.1,<6"
+
+[[package]]
+name = "gitpython"
+version = "3.1.30"
+description = "GitPython is a python library used to interact with Git repositories"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "GitPython-3.1.30-py3-none-any.whl", hash = "sha256:cd455b0000615c60e286208ba540271af9fe531fa6a87cc590a7298785ab2882"},
{file = "GitPython-3.1.30.tar.gz", hash = "sha256:769c2d83e13f5d938b7688479da374c4e3d49f71549aaf462b646db9602ea6f8"},
]
-griffe = [
+
+[package.dependencies]
+gitdb = ">=4.0.1,<5"
+typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\""}
+
+[[package]]
+name = "griffe"
+version = "0.25.4"
+description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API."
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "griffe-0.25.4-py3-none-any.whl", hash = "sha256:919f935a358b31074d16e324e26b041883c60a8cf10504655e394afc3a7caad8"},
{file = "griffe-0.25.4.tar.gz", hash = "sha256:f190edf8ef58d43c856d2d6761ec324a043ff60deb8c14359263571e8b91fe68"},
]
-h11 = [
+
+[package.dependencies]
+cached-property = {version = "*", markers = "python_version < \"3.8\""}
+colorama = ">=0.4"
+
+[package.extras]
+async = ["aiofiles (>=0.7,<1.0)"]
+
+[[package]]
+name = "h11"
+version = "0.14.0"
+description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"},
{file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
]
-httpcore = [
+
+[package.dependencies]
+typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
+
+[[package]]
+name = "httpcore"
+version = "0.16.3"
+description = "A minimal low-level HTTP client."
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "httpcore-0.16.3-py3-none-any.whl", hash = "sha256:da1fb708784a938aa084bde4feb8317056c55037247c787bd7e19eb2c2949dc0"},
{file = "httpcore-0.16.3.tar.gz", hash = "sha256:c5d6f04e2fc530f39e0c077e6a30caa53f1451096120f1f38b954afd0b17c0cb"},
]
-httpx = [
+
+[package.dependencies]
+anyio = ">=3.0,<5.0"
+certifi = "*"
+h11 = ">=0.13,<0.15"
+sniffio = ">=1.0.0,<2.0.0"
+
+[package.extras]
+http2 = ["h2 (>=3,<5)"]
+socks = ["socksio (>=1.0.0,<2.0.0)"]
+
+[[package]]
+name = "httpx"
+version = "0.23.3"
+description = "The next generation HTTP client."
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "httpx-0.23.3-py3-none-any.whl", hash = "sha256:a211fcce9b1254ea24f0cd6af9869b3d29aba40154e947d2a07bb499b3e310d6"},
{file = "httpx-0.23.3.tar.gz", hash = "sha256:9818458eb565bb54898ccb9b8b251a28785dd4a55afbc23d0eb410754fe7d0f9"},
]
-identify = [
+
+[package.dependencies]
+certifi = "*"
+httpcore = ">=0.15.0,<0.17.0"
+rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]}
+sniffio = "*"
+
+[package.extras]
+brotli = ["brotli", "brotlicffi"]
+cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<13)"]
+http2 = ["h2 (>=3,<5)"]
+socks = ["socksio (>=1.0.0,<2.0.0)"]
+
+[[package]]
+name = "identify"
+version = "2.5.15"
+description = "File identification library for Python"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "identify-2.5.15-py2.py3-none-any.whl", hash = "sha256:1f4b36c5f50f3f950864b2a047308743f064eaa6f6645da5e5c780d1c7125487"},
{file = "identify-2.5.15.tar.gz", hash = "sha256:c22aa206f47cc40486ecf585d27ad5f40adbfc494a3fa41dc3ed0499a23b123f"},
]
-idna = [
+
+[package.extras]
+license = ["ukkonen"]
+
+[[package]]
+name = "idna"
+version = "3.4"
+description = "Internationalized Domain Names in Applications (IDNA)"
+category = "main"
+optional = false
+python-versions = ">=3.5"
+files = [
{file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
{file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
]
-importlib-metadata = [
+
+[[package]]
+name = "importlib-metadata"
+version = "4.13.0"
+description = "Read metadata from Python packages"
+category = "main"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "importlib_metadata-4.13.0-py3-none-any.whl", hash = "sha256:8a8a81bcf996e74fee46f0d16bd3eaa382a7eb20fd82445c3ad11f4090334116"},
{file = "importlib_metadata-4.13.0.tar.gz", hash = "sha256:dd0173e8f150d6815e098fd354f6414b0f079af4644ddfe90c71e2fc6174346d"},
]
-iniconfig = [
+
+[package.dependencies]
+typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
+zipp = ">=0.5"
+
+[package.extras]
+docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"]
+perf = ["ipython"]
+testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"]
+
+[[package]]
+name = "iniconfig"
+version = "2.0.0"
+description = "brain-dead simple config-ini parsing"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
]
-jinja2 = [
+
+[[package]]
+name = "jinja2"
+version = "3.0.3"
+description = "A very fast and expressive template engine."
+category = "main"
+optional = false
+python-versions = ">=3.6"
+files = [
{file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"},
{file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"},
]
-markdown = [
+
+[package.dependencies]
+MarkupSafe = ">=2.0"
+
+[package.extras]
+i18n = ["Babel (>=2.7)"]
+
+[[package]]
+name = "markdown"
+version = "3.3.7"
+description = "Python implementation of Markdown."
+category = "main"
+optional = false
+python-versions = ">=3.6"
+files = [
{file = "Markdown-3.3.7-py3-none-any.whl", hash = "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621"},
{file = "Markdown-3.3.7.tar.gz", hash = "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874"},
]
-markdown-it-py = [
+
+[package.dependencies]
+importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""}
+
+[package.extras]
+testing = ["coverage", "pyyaml"]
+
+[[package]]
+name = "markdown-it-py"
+version = "2.1.0"
+description = "Python port of markdown-it. Markdown parsing, done right!"
+category = "main"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "markdown-it-py-2.1.0.tar.gz", hash = "sha256:cf7e59fed14b5ae17c0006eff14a2d9a00ed5f3a846148153899a0224e2c07da"},
{file = "markdown_it_py-2.1.0-py3-none-any.whl", hash = "sha256:93de681e5c021a432c63147656fe21790bc01231e0cd2da73626f1aa3ac0fe27"},
]
-markupsafe = [
+
+[package.dependencies]
+mdurl = ">=0.1,<1.0"
+typing_extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""}
+
+[package.extras]
+benchmarking = ["psutil", "pytest", "pytest-benchmark (>=3.2,<4.0)"]
+code-style = ["pre-commit (==2.6)"]
+compare = ["commonmark (>=0.9.1,<0.10.0)", "markdown (>=3.3.6,<3.4.0)", "mistletoe (>=0.8.1,<0.9.0)", "mistune (>=2.0.2,<2.1.0)", "panflute (>=2.1.3,<2.2.0)"]
+linkify = ["linkify-it-py (>=1.0,<2.0)"]
+plugins = ["mdit-py-plugins"]
+profiling = ["gprof2dot"]
+rtd = ["attrs", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
+testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
+
+[[package]]
+name = "markupsafe"
+version = "2.1.2"
+description = "Safely add untrusted strings to HTML/XML markup."
+category = "main"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7"},
{file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036"},
{file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1"},
@@ -1441,43 +833,196 @@ markupsafe = [
{file = "MarkupSafe-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed"},
{file = "MarkupSafe-2.1.2.tar.gz", hash = "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d"},
]
-mdurl = [
+
+[[package]]
+name = "mdurl"
+version = "0.1.2"
+description = "Markdown URL utilities"
+category = "main"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
{file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
]
-mergedeep = [
+
+[[package]]
+name = "mergedeep"
+version = "1.3.4"
+description = "A deep merge function for ๐."
+category = "main"
+optional = false
+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"},
]
-mkdocs = [
+
+[[package]]
+name = "mkdocs"
+version = "1.4.2"
+description = "Project documentation with Markdown."
+category = "main"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "mkdocs-1.4.2-py3-none-any.whl", hash = "sha256:c8856a832c1e56702577023cd64cc5f84948280c1c0fcc6af4cd39006ea6aa8c"},
{file = "mkdocs-1.4.2.tar.gz", hash = "sha256:8947af423a6d0facf41ea1195b8e1e8c85ad94ac95ae307fe11232e0424b11c5"},
]
-mkdocs-autorefs = [
+
+[package.dependencies]
+click = ">=7.0"
+colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""}
+ghp-import = ">=1.0"
+importlib-metadata = {version = ">=4.3", markers = "python_version < \"3.10\""}
+jinja2 = ">=2.11.1"
+markdown = ">=3.2.1,<3.4"
+mergedeep = ">=1.3.4"
+packaging = ">=20.5"
+pyyaml = ">=5.1"
+pyyaml-env-tag = ">=0.1"
+typing-extensions = {version = ">=3.10", markers = "python_version < \"3.8\""}
+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.3)", "jinja2 (==2.11.1)", "markdown (==3.2.1)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "packaging (==20.5)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "typing-extensions (==3.10)", "watchdog (==2.0)"]
+
+[[package]]
+name = "mkdocs-autorefs"
+version = "0.4.1"
+description = "Automatically link across pages in MkDocs."
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "mkdocs-autorefs-0.4.1.tar.gz", hash = "sha256:70748a7bd025f9ecd6d6feeba8ba63f8e891a1af55f48e366d6d6e78493aba84"},
{file = "mkdocs_autorefs-0.4.1-py3-none-any.whl", hash = "sha256:a2248a9501b29dc0cc8ba4c09f4f47ff121945f6ce33d760f145d6f89d313f5b"},
]
-mkdocs-material = [
+
+[package.dependencies]
+Markdown = ">=3.3"
+mkdocs = ">=1.1"
+
+[[package]]
+name = "mkdocs-exclude"
+version = "1.0.2"
+description = "A mkdocs plugin that lets you exclude files or trees."
+category = "main"
+optional = false
+python-versions = "*"
+files = [
+ {file = "mkdocs-exclude-1.0.2.tar.gz", hash = "sha256:ba6fab3c80ddbe3fd31d3e579861fd3124513708271180a5f81846da8c7e2a51"},
+]
+
+[package.dependencies]
+mkdocs = "*"
+
+[[package]]
+name = "mkdocs-material"
+version = "8.5.11"
+description = "Documentation that simply works"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "mkdocs_material-8.5.11-py3-none-any.whl", hash = "sha256:c907b4b052240a5778074a30a78f31a1f8ff82d7012356dc26898b97559f082e"},
{file = "mkdocs_material-8.5.11.tar.gz", hash = "sha256:b0ea0513fd8cab323e8a825d6692ea07fa83e917bb5db042e523afecc7064ab7"},
]
-mkdocs-material-extensions = [
+
+[package.dependencies]
+jinja2 = ">=3.0.2"
+markdown = ">=3.2"
+mkdocs = ">=1.4.0"
+mkdocs-material-extensions = ">=1.1"
+pygments = ">=2.12"
+pymdown-extensions = ">=9.4"
+requests = ">=2.26"
+
+[[package]]
+name = "mkdocs-material-extensions"
+version = "1.1.1"
+description = "Extension pack for Python Markdown and MkDocs Material."
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "mkdocs_material_extensions-1.1.1-py3-none-any.whl", hash = "sha256:e41d9f38e4798b6617ad98ca8f7f1157b1e4385ac1459ca1e4ea219b556df945"},
{file = "mkdocs_material_extensions-1.1.1.tar.gz", hash = "sha256:9c003da71e2cc2493d910237448c672e00cefc800d3d6ae93d2fc69979e3bd93"},
]
-mkdocs-rss-plugin = [
+
+[[package]]
+name = "mkdocs-rss-plugin"
+version = "1.5.0"
+description = "MkDocs plugin which generates a static RSS feed using git log and page.meta."
+category = "dev"
+optional = false
+python-versions = ">=3.7, <4"
+files = [
{file = "mkdocs-rss-plugin-1.5.0.tar.gz", hash = "sha256:4178b3830dcbad9b53b12459e315b1aad6b37d1e7e5c56c686866a10f99878a4"},
{file = "mkdocs_rss_plugin-1.5.0-py2.py3-none-any.whl", hash = "sha256:2ab14c20bf6b7983acbe50181e7e4a0778731d9c2d5c38107ca7047a7abd2165"},
]
-mkdocstrings = [
+
+[package.dependencies]
+GitPython = ">=3.1,<3.2"
+mkdocs = ">=1.1,<2"
+pytz = {version = ">=2022.0.0,<2023.0.0", markers = "python_version < \"3.9\""}
+tzdata = {version = ">=2022.0.0,<2023.0.0", markers = "python_version >= \"3.9\" and sys_platform == \"win32\""}
+
+[package.extras]
+dev = ["black", "feedparser (>=6.0,<6.1)", "flake8 (>=4,<5.1)", "pre-commit (>=2.10,<2.21)", "pytest-cov (>=4.0.0,<4.1.0)", "validator-collection (>=1.5,<1.6)"]
+doc = ["mkdocs-bootswatch (>=1,<2)", "mkdocs-minify-plugin (>=0.5.0,<0.6.0)", "pygments (>=2.5,<3)", "pymdown-extensions (>=7,<10)"]
+
+[[package]]
+name = "mkdocstrings"
+version = "0.20.0"
+description = "Automatic documentation from sources, for MkDocs."
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "mkdocstrings-0.20.0-py3-none-any.whl", hash = "sha256:f17fc2c4f760ec302b069075ef9e31045aa6372ca91d2f35ded3adba8e25a472"},
{file = "mkdocstrings-0.20.0.tar.gz", hash = "sha256:c757f4f646d4f939491d6bc9256bfe33e36c5f8026392f49eaa351d241c838e5"},
]
-mkdocstrings-python = [
+
+[package.dependencies]
+Jinja2 = ">=2.11.1"
+Markdown = ">=3.3"
+MarkupSafe = ">=1.1"
+mkdocs = ">=1.2"
+mkdocs-autorefs = ">=0.3.1"
+mkdocstrings-python = {version = ">=0.5.2", optional = true, markers = "extra == \"python\""}
+pymdown-extensions = ">=6.3"
+
+[package.extras]
+crystal = ["mkdocstrings-crystal (>=0.3.4)"]
+python = ["mkdocstrings-python (>=0.5.2)"]
+python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"]
+
+[[package]]
+name = "mkdocstrings-python"
+version = "0.8.3"
+description = "A Python handler for mkdocstrings."
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "mkdocstrings-python-0.8.3.tar.gz", hash = "sha256:9ae473f6dc599339b09eee17e4d2b05d6ac0ec29860f3fc9b7512d940fc61adf"},
{file = "mkdocstrings_python-0.8.3-py3-none-any.whl", hash = "sha256:4e6e1cd6f37a785de0946ced6eb846eb2f5d891ac1cc2c7b832943d3529087a7"},
]
-msgpack = [
+
+[package.dependencies]
+griffe = ">=0.24"
+mkdocstrings = ">=0.19"
+
+[[package]]
+name = "msgpack"
+version = "1.0.4"
+description = "MessagePack serializer"
+category = "main"
+optional = true
+python-versions = "*"
+files = [
{file = "msgpack-1.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4ab251d229d10498e9a2f3b1e68ef64cb393394ec477e3370c457f9430ce9250"},
{file = "msgpack-1.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:112b0f93202d7c0fef0b7810d465fde23c746a2d482e1e2de2aafd2ce1492c88"},
{file = "msgpack-1.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:002b5c72b6cd9b4bafd790f364b8480e859b4712e91f43014fe01e4f957b8467"},
@@ -1531,7 +1076,15 @@ msgpack = [
{file = "msgpack-1.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:4d5834a2a48965a349da1c5a79760d94a1a0172fbb5ab6b5b33cbf8447e109ce"},
{file = "msgpack-1.0.4.tar.gz", hash = "sha256:f5d869c18f030202eb412f08b28d2afeea553d6613aee89e200d7aca7ef01f5f"},
]
-multidict = [
+
+[[package]]
+name = "multidict"
+version = "6.0.4"
+description = "multidict implementation"
+category = "main"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "multidict-6.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8"},
{file = "multidict-6.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171"},
{file = "multidict-6.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7"},
@@ -1607,7 +1160,15 @@ multidict = [
{file = "multidict-6.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2"},
{file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"},
]
-mypy = [
+
+[[package]]
+name = "mypy"
+version = "0.990"
+description = "Optional static typing for Python"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "mypy-0.990-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:aaf1be63e0207d7d17be942dcf9a6b641745581fe6c64df9a38deb562a7dbafa"},
{file = "mypy-0.990-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d555aa7f44cecb7ea3c0ac69d58b1a5afb92caa017285a8e9c4efbf0518b61b4"},
{file = "mypy-0.990-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f694d6d09a460b117dccb6857dda269188e3437c880d7b60fa0014fa872d1e9"},
@@ -1639,71 +1200,290 @@ mypy = [
{file = "mypy-0.990-py3-none-any.whl", hash = "sha256:8f1940325a8ed460ba03d19ab83742260fa9534804c317224e5d4e5aa588e2d6"},
{file = "mypy-0.990.tar.gz", hash = "sha256:72382cb609142dba3f04140d016c94b4092bc7b4d98ca718740dc989e5271b8d"},
]
-mypy-extensions = [
+
+[package.dependencies]
+mypy-extensions = ">=0.4.3"
+tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
+typed-ast = {version = ">=1.4.0,<2", markers = "python_version < \"3.8\""}
+typing-extensions = ">=3.10"
+
+[package.extras]
+dmypy = ["psutil (>=4.0)"]
+install-types = ["pip"]
+python2 = ["typed-ast (>=1.4.0,<2)"]
+reports = ["lxml"]
+
+[[package]]
+name = "mypy-extensions"
+version = "0.4.3"
+description = "Experimental type system extensions for programs checked with the mypy typechecker."
+category = "dev"
+optional = false
+python-versions = "*"
+files = [
{file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
{file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
]
-nanoid = [
+
+[[package]]
+name = "nanoid"
+version = "2.0.0"
+description = "A tiny, secure, URL-friendly, unique string ID generator for Python"
+category = "main"
+optional = false
+python-versions = "*"
+files = [
{file = "nanoid-2.0.0-py3-none-any.whl", hash = "sha256:90aefa650e328cffb0893bbd4c236cfd44c48bc1f2d0b525ecc53c3187b653bb"},
{file = "nanoid-2.0.0.tar.gz", hash = "sha256:5a80cad5e9c6e9ae3a41fa2fb34ae189f7cb420b2a5d8f82bd9d23466e4efa68"},
]
-nodeenv = [
+
+[[package]]
+name = "nodeenv"
+version = "1.7.0"
+description = "Node.js virtual environment builder"
+category = "dev"
+optional = false
+python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*"
+files = [
{file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"},
{file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"},
]
-packaging = [
+
+[package.dependencies]
+setuptools = "*"
+
+[[package]]
+name = "packaging"
+version = "23.0"
+description = "Core utilities for Python packages"
+category = "main"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"},
{file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"},
]
-pathspec = [
+
+[[package]]
+name = "pathspec"
+version = "0.11.0"
+description = "Utility library for gitignore style pattern matching of file paths."
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "pathspec-0.11.0-py3-none-any.whl", hash = "sha256:3a66eb970cbac598f9e5ccb5b2cf58930cd8e3ed86d393d541eaf2d8b1705229"},
{file = "pathspec-0.11.0.tar.gz", hash = "sha256:64d338d4e0914e91c1792321e6907b5a593f1ab1851de7fc269557a21b30ebbc"},
]
-platformdirs = [
+
+[[package]]
+name = "platformdirs"
+version = "2.6.2"
+description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "platformdirs-2.6.2-py3-none-any.whl", hash = "sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490"},
{file = "platformdirs-2.6.2.tar.gz", hash = "sha256:e1fea1fe471b9ff8332e229df3cb7de4f53eeea4998d3b6bfff542115e998bd2"},
]
-pluggy = [
+
+[package.dependencies]
+typing-extensions = {version = ">=4.4", markers = "python_version < \"3.8\""}
+
+[package.extras]
+docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"]
+test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"]
+
+[[package]]
+name = "pluggy"
+version = "1.0.0"
+description = "plugin and hook calling mechanisms for python"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+files = [
{file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
{file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
]
-pre-commit = [
+
+[package.dependencies]
+importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
+
+[package.extras]
+dev = ["pre-commit", "tox"]
+testing = ["pytest", "pytest-benchmark"]
+
+[[package]]
+name = "pre-commit"
+version = "2.21.0"
+description = "A framework for managing and maintaining multi-language pre-commit hooks."
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "pre_commit-2.21.0-py2.py3-none-any.whl", hash = "sha256:e2f91727039fc39a92f58a588a25b87f936de6567eed4f0e673e0507edc75bad"},
{file = "pre_commit-2.21.0.tar.gz", hash = "sha256:31ef31af7e474a8d8995027fefdfcf509b5c913ff31f2015b4ec4beb26a6f658"},
]
-pygments = [
+
+[package.dependencies]
+cfgv = ">=2.0.0"
+identify = ">=1.0.0"
+importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
+nodeenv = ">=0.11.1"
+pyyaml = ">=5.1"
+virtualenv = ">=20.10.0"
+
+[[package]]
+name = "pygments"
+version = "2.14.0"
+description = "Pygments is a syntax highlighting package written in Python."
+category = "main"
+optional = false
+python-versions = ">=3.6"
+files = [
{file = "Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"},
{file = "Pygments-2.14.0.tar.gz", hash = "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297"},
]
-pymdown-extensions = [
+
+[package.extras]
+plugins = ["importlib-metadata"]
+
+[[package]]
+name = "pymdown-extensions"
+version = "9.9.2"
+description = "Extension pack for Python Markdown."
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "pymdown_extensions-9.9.2-py3-none-any.whl", hash = "sha256:c3d804eb4a42b85bafb5f36436342a5ad38df03878bb24db8855a4aa8b08b765"},
{file = "pymdown_extensions-9.9.2.tar.gz", hash = "sha256:ebb33069bafcb64d5f5988043331d4ea4929325dc678a6bcf247ddfcf96499f8"},
]
-pytest = [
+
+[package.dependencies]
+markdown = ">=3.2"
+
+[[package]]
+name = "pytest"
+version = "7.2.1"
+description = "pytest: simple powerful testing with Python"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "pytest-7.2.1-py3-none-any.whl", hash = "sha256:c7c6ca206e93355074ae32f7403e8ea12163b1163c976fee7d4d84027c162be5"},
{file = "pytest-7.2.1.tar.gz", hash = "sha256:d45e0952f3727241918b8fd0f376f5ff6b301cc0777c6f9a556935c92d8a7d42"},
]
-pytest-aiohttp = [
+
+[package.dependencies]
+attrs = ">=19.2.0"
+colorama = {version = "*", markers = "sys_platform == \"win32\""}
+exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
+importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
+iniconfig = "*"
+packaging = "*"
+pluggy = ">=0.12,<2.0"
+tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
+
+[package.extras]
+testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
+
+[[package]]
+name = "pytest-aiohttp"
+version = "1.0.4"
+description = "Pytest plugin for aiohttp support"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "pytest-aiohttp-1.0.4.tar.gz", hash = "sha256:39ff3a0d15484c01d1436cbedad575c6eafbf0f57cdf76fb94994c97b5b8c5a4"},
{file = "pytest_aiohttp-1.0.4-py3-none-any.whl", hash = "sha256:1d2dc3a304c2be1fd496c0c2fb6b31ab60cd9fc33984f761f951f8ea1eb4ca95"},
]
-pytest-asyncio = [
+
+[package.dependencies]
+aiohttp = ">=3.8.1"
+pytest = ">=6.1.0"
+pytest-asyncio = ">=0.17.2"
+
+[package.extras]
+testing = ["coverage (==6.2)", "mypy (==0.931)"]
+
+[[package]]
+name = "pytest-asyncio"
+version = "0.20.3"
+description = "Pytest support for asyncio"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "pytest-asyncio-0.20.3.tar.gz", hash = "sha256:83cbf01169ce3e8eb71c6c278ccb0574d1a7a3bb8eaaf5e50e0ad342afb33b36"},
{file = "pytest_asyncio-0.20.3-py3-none-any.whl", hash = "sha256:f129998b209d04fcc65c96fc85c11e5316738358909a8399e93be553d7656442"},
]
-pytest-cov = [
+
+[package.dependencies]
+pytest = ">=6.1.0"
+typing-extensions = {version = ">=3.7.2", markers = "python_version < \"3.8\""}
+
+[package.extras]
+docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"]
+testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"]
+
+[[package]]
+name = "pytest-cov"
+version = "2.12.1"
+description = "Pytest plugin for measuring coverage."
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+files = [
{file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"},
{file = "pytest_cov-2.12.1-py2.py3-none-any.whl", hash = "sha256:261bb9e47e65bd099c89c3edf92972865210c36813f80ede5277dceb77a4a62a"},
]
-python-dateutil = [
+
+[package.dependencies]
+coverage = ">=5.2.1"
+pytest = ">=4.6"
+toml = "*"
+
+[package.extras]
+testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"]
+
+[[package]]
+name = "python-dateutil"
+version = "2.8.2"
+description = "Extensions to the standard Python datetime module"
+category = "main"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+files = [
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
]
-pytz = [
+
+[package.dependencies]
+six = ">=1.5"
+
+[[package]]
+name = "pytz"
+version = "2022.7.1"
+description = "World timezone definitions, modern and historical"
+category = "dev"
+optional = false
+python-versions = "*"
+files = [
{file = "pytz-2022.7.1-py2.py3-none-any.whl", hash = "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"},
{file = "pytz-2022.7.1.tar.gz", hash = "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0"},
]
-pyyaml = [
+
+[[package]]
+name = "pyyaml"
+version = "6.0"
+description = "YAML parser and emitter for Python"
+category = "main"
+optional = false
+python-versions = ">=3.6"
+files = [
{file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
{file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"},
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"},
@@ -1745,43 +1525,159 @@ pyyaml = [
{file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"},
{file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
]
-pyyaml-env-tag = [
+
+[[package]]
+name = "pyyaml-env-tag"
+version = "0.1"
+description = "A custom YAML tag for referencing environment variables in YAML files. "
+category = "main"
+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"},
]
-requests = [
+
+[package.dependencies]
+pyyaml = "*"
+
+[[package]]
+name = "requests"
+version = "2.28.2"
+description = "Python HTTP for Humans."
+category = "dev"
+optional = false
+python-versions = ">=3.7, <4"
+files = [
{file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"},
{file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"},
]
-rfc3986 = [
+
+[package.dependencies]
+certifi = ">=2017.4.17"
+charset-normalizer = ">=2,<4"
+idna = ">=2.5,<4"
+urllib3 = ">=1.21.1,<1.27"
+
+[package.extras]
+socks = ["PySocks (>=1.5.6,!=1.5.7)"]
+use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
+
+[[package]]
+name = "rfc3986"
+version = "1.5.0"
+description = "Validating URI References per RFC 3986"
+category = "dev"
+optional = false
+python-versions = "*"
+files = [
{file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"},
{file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"},
]
-rich = [
+
+[package.dependencies]
+idna = {version = "*", optional = true, markers = "extra == \"idna2008\""}
+
+[package.extras]
+idna2008 = ["idna"]
+
+[[package]]
+name = "rich"
+version = "13.2.0"
+description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
+category = "main"
+optional = false
+python-versions = ">=3.7.0"
+files = [
{file = "rich-13.2.0-py3-none-any.whl", hash = "sha256:7c963f0d03819221e9ac561e1bc866e3f95a02248c1234daa48954e6d381c003"},
{file = "rich-13.2.0.tar.gz", hash = "sha256:f1a00cdd3eebf999a15d85ec498bfe0b1a77efe9b34f645768a54132ef444ac5"},
]
-setuptools = [
+
+[package.dependencies]
+markdown-it-py = ">=2.1.0,<3.0.0"
+pygments = ">=2.6.0,<3.0.0"
+typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""}
+
+[package.extras]
+jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"]
+
+[[package]]
+name = "setuptools"
+version = "66.1.1"
+description = "Easily download, build, install, upgrade, and uninstall Python packages"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "setuptools-66.1.1-py3-none-any.whl", hash = "sha256:6f590d76b713d5de4e49fe4fbca24474469f53c83632d5d0fd056f7ff7e8112b"},
{file = "setuptools-66.1.1.tar.gz", hash = "sha256:ac4008d396bc9cd983ea483cb7139c0240a07bbc74ffb6232fceffedc6cf03a8"},
]
-six = [
+
+[package.extras]
+docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
+testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
+testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
+
+[[package]]
+name = "six"
+version = "1.16.0"
+description = "Python 2 and 3 compatibility utilities"
+category = "main"
+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"},
]
-smmap = [
+
+[[package]]
+name = "smmap"
+version = "5.0.0"
+description = "A pure Python implementation of a sliding window memory map manager"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+files = [
{file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"},
{file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"},
]
-sniffio = [
+
+[[package]]
+name = "sniffio"
+version = "1.3.0"
+description = "Sniff out which async library your code is running under"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"},
{file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"},
]
-syrupy = [
+
+[[package]]
+name = "syrupy"
+version = "3.0.6"
+description = "Pytest Snapshot Test Utility"
+category = "dev"
+optional = false
+python-versions = ">=3.7,<4"
+files = [
{file = "syrupy-3.0.6-py3-none-any.whl", hash = "sha256:9c18e22264026b34239bcc87ab7cc8d893eb17236ea7dae634217ea4f22a848d"},
{file = "syrupy-3.0.6.tar.gz", hash = "sha256:583aa5ca691305c27902c3e29a1ce9da50ff9ab5f184c54b1dc124a16e4a6cf4"},
]
-time-machine = [
+
+[package.dependencies]
+colored = ">=1.3.92,<2.0.0"
+pytest = ">=5.1.0,<8.0.0"
+
+[[package]]
+name = "time-machine"
+version = "2.9.0"
+description = "Travel through time in your tests."
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "time-machine-2.9.0.tar.gz", hash = "sha256:60222d43f6e93a926adc36ed37a54bc8e4d0d8d1c4d449096afcfe85086129c2"},
{file = "time_machine-2.9.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fd72c0b2e7443fff6e4481991742b72c17f73735e5fdd176406ca48df187a5c9"},
{file = "time_machine-2.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5657e0e6077cf15b37f0d8cf78e868113bbb3ecccc60064c40fe52d8166ca8b1"},
@@ -1836,15 +1732,42 @@ time-machine = [
{file = "time_machine-2.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:cc6bf01211b5ea40f633d5502c5aa495b415ebaff66e041820997dae70a508e1"},
{file = "time_machine-2.9.0-cp39-cp39-win_arm64.whl", hash = "sha256:3ce445775fcf7cb4040cfdba4b7c4888e7fd98bbcccfe1dc3fa8a798ed1f1d24"},
]
-toml = [
+
+[package.dependencies]
+python-dateutil = "*"
+
+[[package]]
+name = "toml"
+version = "0.10.2"
+description = "Python Library for Tom's Obvious, Minimal Language"
+category = "dev"
+optional = false
+python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
+files = [
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
]
-tomli = [
+
+[[package]]
+name = "tomli"
+version = "2.0.1"
+description = "A lil' TOML parser"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
]
-typed-ast = [
+
+[[package]]
+name = "typed-ast"
+version = "1.5.4"
+description = "a fork of Python 2 and 3 ast modules with type comment support"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+files = [
{file = "typed_ast-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4"},
{file = "typed_ast-1.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62"},
{file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac"},
@@ -1870,23 +1793,78 @@ typed-ast = [
{file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"},
{file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"},
]
-typing-extensions = [
+
+[[package]]
+name = "typing-extensions"
+version = "4.4.0"
+description = "Backported and Experimental Type Hints for Python 3.7+"
+category = "main"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"},
{file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"},
]
-tzdata = [
+
+[[package]]
+name = "tzdata"
+version = "2022.7"
+description = "Provider of IANA time zone data"
+category = "dev"
+optional = false
+python-versions = ">=2"
+files = [
{file = "tzdata-2022.7-py2.py3-none-any.whl", hash = "sha256:2b88858b0e3120792a3c0635c23daf36a7d7eeeca657c323da299d2094402a0d"},
{file = "tzdata-2022.7.tar.gz", hash = "sha256:fe5f866eddd8b96e9fcba978f8e503c909b19ea7efda11e52e39494bad3a7bfa"},
]
-urllib3 = [
+
+[[package]]
+name = "urllib3"
+version = "1.26.14"
+description = "HTTP library with thread-safe connection pooling, file post, and more."
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
+files = [
{file = "urllib3-1.26.14-py2.py3-none-any.whl", hash = "sha256:75edcdc2f7d85b137124a6c3c9fc3933cdeaa12ecb9a6a959f22797a0feca7e1"},
{file = "urllib3-1.26.14.tar.gz", hash = "sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72"},
]
-virtualenv = [
+
+[package.extras]
+brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
+secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
+socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
+
+[[package]]
+name = "virtualenv"
+version = "20.17.1"
+description = "Virtual Python Environment builder"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+files = [
{file = "virtualenv-20.17.1-py3-none-any.whl", hash = "sha256:ce3b1684d6e1a20a3e5ed36795a97dfc6af29bc3970ca8dab93e11ac6094b3c4"},
{file = "virtualenv-20.17.1.tar.gz", hash = "sha256:f8b927684efc6f1cc206c9db297a570ab9ad0e51c16fa9e45487d36d1905c058"},
]
-watchdog = [
+
+[package.dependencies]
+distlib = ">=0.3.6,<1"
+filelock = ">=3.4.1,<4"
+importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.8\""}
+platformdirs = ">=2.4,<3"
+
+[package.extras]
+docs = ["proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-argparse (>=0.3.2)", "sphinx-rtd-theme (>=1)", "towncrier (>=22.8)"]
+testing = ["coverage (>=6.2)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=21.3)", "pytest (>=7.0.1)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.6.1)", "pytest-randomly (>=3.10.3)", "pytest-timeout (>=2.1)"]
+
+[[package]]
+name = "watchdog"
+version = "2.2.1"
+description = "Filesystem events monitoring"
+category = "main"
+optional = false
+python-versions = ">=3.6"
+files = [
{file = "watchdog-2.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a09483249d25cbdb4c268e020cb861c51baab2d1affd9a6affc68ffe6a231260"},
{file = "watchdog-2.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5100eae58133355d3ca6c1083a33b81355c4f452afa474c2633bd2fbbba398b3"},
{file = "watchdog-2.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e618a4863726bc7a3c64f95c218437f3349fb9d909eb9ea3a1ed3b567417c661"},
@@ -1916,7 +1894,18 @@ watchdog = [
{file = "watchdog-2.2.1-py3-none-win_ia64.whl", hash = "sha256:195ab1d9d611a4c1e5311cbf42273bc541e18ea8c32712f2fb703cfc6ff006f9"},
{file = "watchdog-2.2.1.tar.gz", hash = "sha256:cdcc23c9528601a8a293eb4369cbd14f6b4f34f07ae8769421252e9c22718b6f"},
]
-yarl = [
+
+[package.extras]
+watchmedo = ["PyYAML (>=3.10)"]
+
+[[package]]
+name = "yarl"
+version = "1.8.2"
+description = "Yet another URL library"
+category = "main"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "yarl-1.8.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bb81f753c815f6b8e2ddd2eef3c855cf7da193b82396ac013c661aaa6cc6b0a5"},
{file = "yarl-1.8.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:47d49ac96156f0928f002e2424299b2c91d9db73e08c4cd6742923a086f1c863"},
{file = "yarl-1.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3fc056e35fa6fba63248d93ff6e672c096f95f7836938241ebc8260e062832fe"},
@@ -1992,7 +1981,32 @@ yarl = [
{file = "yarl-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:6604711362f2dbf7160df21c416f81fac0de6dbcf0b5445a2ef25478ecc4c778"},
{file = "yarl-1.8.2.tar.gz", hash = "sha256:49d43402c6e3013ad0978602bf6bf5328535c48d192304b91b97a3c6790b1562"},
]
-zipp = [
+
+[package.dependencies]
+idna = ">=2.0"
+multidict = ">=4.0"
+typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""}
+
+[[package]]
+name = "zipp"
+version = "3.11.0"
+description = "Backport of pathlib-compatible object wrapper for zip files"
+category = "main"
+optional = false
+python-versions = ">=3.7"
+files = [
{file = "zipp-3.11.0-py3-none-any.whl", hash = "sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa"},
{file = "zipp-3.11.0.tar.gz", hash = "sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766"},
]
+
+[package.extras]
+docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"]
+testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
+
+[extras]
+dev = ["aiohttp", "click", "msgpack"]
+
+[metadata]
+lock-version = "2.0"
+python-versions = "^3.7"
+content-hash = "b70dc64a3c9e7a7b765252f5dd1a5de8ed6efacd0695cde32ff983b14ec55ca6"
diff --git a/pyproject.toml b/pyproject.toml
index e16e5253e..9582f1550 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -40,6 +40,7 @@ aiohttp = { version = ">=3.8.1", optional = true }
click = {version = ">=8.1.2", optional = true}
msgpack = { version = ">=1.0.3", optional = true }
nanoid = ">=2.0.0"
+mkdocs-exclude = "^1.0.2"
[tool.poetry.extras]
dev = ["aiohttp", "click", "msgpack"]
diff --git a/src/textual/_wait.py b/src/textual/_wait.py
index 67a124954..f7ed7d3f3 100644
--- a/src/textual/_wait.py
+++ b/src/textual/_wait.py
@@ -10,11 +10,11 @@ async def wait_for_idle(
) -> None:
"""Wait until the process isn't working very hard.
- This will compare wall clock time with process time, if the process time
- is not advancing the same as wall clock time it means the process is in a
- sleep state or waiting for input.
+ This will compare wall clock time with process time. If the process time
+ is not advancing at the same rate as wall clock time it means the process is
+ idle (i.e. sleeping or waiting for input).
- When the process is idle it suggests that input has been processes and the state
+ When the process is idle it suggests that input has been processed and the state
is predictable enough to test.
Args:
diff --git a/src/textual/app.py b/src/textual/app.py
index 46ac67903..6abf74839 100644
--- a/src/textual/app.py
+++ b/src/textual/app.py
@@ -1901,9 +1901,11 @@ class App(Generic[ReturnType], DOMNode):
else:
await self.screen._forward_event(event)
- elif isinstance(event, events.Paste):
+ elif isinstance(event, events.Paste) and not event.is_forwarded:
if self.focused is not None:
await self.focused._forward_event(event)
+ else:
+ await self.screen._forward_event(event)
else:
await super().on_event(event)
diff --git a/src/textual/events.py b/src/textual/events.py
index d2f7dfe49..9914c03d5 100644
--- a/src/textual/events.py
+++ b/src/textual/events.py
@@ -7,7 +7,7 @@ from rich.style import Style
from ._types import MessageTarget
from .geometry import Offset, Size
-from .keys import _get_key_aliases, _get_key_display
+from .keys import _get_key_aliases
from .message import Message
MouseEventT = TypeVar("MouseEventT", bound="MouseEvent")
diff --git a/src/textual/widgets/__init__.py b/src/textual/widgets/__init__.py
index 295b8bf12..98dd81f18 100644
--- a/src/textual/widgets/__init__.py
+++ b/src/textual/widgets/__init__.py
@@ -4,7 +4,7 @@ import typing
from ..case import camel_to_snake
-# โ ๏ธFor any new built-in Widget we create, not only do we have to import them here and add them to `__all__`,
+# For any new built-in Widget we create, not only do we have to import them here and add them to `__all__`,
# but also to the `__init__.pyi` file in this same folder - otherwise text editors and type checkers won't
# be able to "see" them.
if typing.TYPE_CHECKING:
diff --git a/src/textual/widgets/_button.py b/src/textual/widgets/_button.py
index 90da10c5d..164ca38ef 100644
--- a/src/textual/widgets/_button.py
+++ b/src/textual/widgets/_button.py
@@ -150,9 +150,21 @@ class Button(Static, can_focus=True):
ACTIVE_EFFECT_DURATION = 0.3
"""When buttons are clicked they get the `-active` class for this duration (in seconds)"""
+ label: Reactive[RenderableType] = Reactive("")
+ """The text label that appears within the button."""
+
+ variant = Reactive.init("default")
+ """The variant name for the button."""
+
+ disabled = Reactive(False)
+ """The disabled state of the button; `True` if disabled, `False` if not."""
+
class Pressed(Message, bubble=True):
"""Event sent when a `Button` is pressed.
+ Can be handled using `on_button_pressed` in a subclass of `Button` or
+ in a parent widget in the DOM.
+
Attributes:
button: The button that was pressed.
"""
@@ -194,15 +206,6 @@ class Button(Static, can_focus=True):
self.variant = self.validate_variant(variant)
- label: Reactive[RenderableType] = Reactive("")
- """The text label that appears within the button."""
-
- variant = Reactive.init("default")
- """The variant name for the button."""
-
- disabled = Reactive(False)
- """The disabled state of the button; `True` if disabled, `False` if not."""
-
def __rich_repr__(self) -> rich.repr.Result:
yield from super().__rich_repr__()
yield "variant", self.variant, "default"
diff --git a/src/textual/widgets/_checkbox.py b/src/textual/widgets/_checkbox.py
index 55a656206..305858faf 100644
--- a/src/textual/widgets/_checkbox.py
+++ b/src/textual/widgets/_checkbox.py
@@ -4,7 +4,7 @@ from typing import ClassVar
from rich.console import RenderableType
-from ..binding import Binding
+from ..binding import Binding, BindingType
from ..geometry import Size
from ..message import Message
from ..reactive import reactive
@@ -13,12 +13,33 @@ from ..scrollbar import ScrollBarRender
class Checkbox(Widget, can_focus=True):
- """A checkbox widget. Represents a boolean value. Can be toggled by clicking
- on it or by pressing the enter key or space bar while it has focus.
+ """A checkbox widget that represents a boolean value.
+
+ Can be toggled by clicking on it or through its [bindings][textual.widgets.Checkbox.BINDINGS].
+
+ The checkbox widget also contains [component classes][textual.widgets.Checkbox.COMPONENT_CLASSES]
+ that enable more customization.
+ """
+
+ BINDINGS: ClassVar[list[BindingType]] = [
+ Binding("enter,space", "toggle", "Toggle", show=False),
+ ]
+ """
+ | Key(s) | Description |
+ | :- | :- |
+ | enter,space | Toggle the checkbox status. |
+ """
+
+ COMPONENT_CLASSES: ClassVar[set[str]] = {
+ "checkbox--switch",
+ }
+ """
+ | Class | Description |
+ | :- | :- |
+ | `checkbox--switch` | Targets the switch of the checkbox. |
"""
DEFAULT_CSS = """
-
Checkbox {
border: tall transparent;
background: $panel;
@@ -49,13 +70,27 @@ class Checkbox(Widget, can_focus=True):
}
"""
- BINDINGS = [
- Binding("enter,space", "toggle", "toggle", show=False),
- ]
+ value = reactive(False, init=False)
+ """The value of the checkbox; `True` for on and `False` for off."""
- COMPONENT_CLASSES: ClassVar[set[str]] = {
- "checkbox--switch",
- }
+ slider_pos = reactive(0.0)
+ """The position of the slider."""
+
+ class Changed(Message, bubble=True):
+ """Emitted when the status of the checkbox changes.
+
+ Can be handled using `on_checkbox_changed` in a subclass of `Checkbox`
+ or in a parent widget in the DOM.
+
+ Attributes:
+ value: The value that the checkbox was changed to.
+ input: The `Checkbox` widget that was changed.
+ """
+
+ def __init__(self, sender: Checkbox, value: bool) -> None:
+ super().__init__(sender)
+ self.value: bool = value
+ self.input: Checkbox = sender
def __init__(
self,
@@ -81,12 +116,6 @@ class Checkbox(Widget, can_focus=True):
self._reactive_value = value
self._should_animate = animate
- value = reactive(False, init=False)
- """The value of the checkbox; `True` for on and `False` for off."""
-
- slider_pos = reactive(0.0)
- """The position of the slider."""
-
def watch_value(self, value: bool) -> None:
target_slider_pos = 1.0 if value else 0.0
if self._should_animate:
@@ -124,16 +153,3 @@ class Checkbox(Widget, can_focus=True):
"""Toggle the checkbox value. As a result of the value changing,
a Checkbox.Changed message will be emitted."""
self.value = not self.value
-
- class Changed(Message, bubble=True):
- """Checkbox was toggled.
-
- Attributes:
- value: The value that the checkbox was changed to.
- input: The `Checkbox` widget that was changed.
- """
-
- def __init__(self, sender: Checkbox, value: bool) -> None:
- super().__init__(sender)
- self.value: bool = value
- self.input: Checkbox = sender
diff --git a/src/textual/widgets/_data_table.py b/src/textual/widgets/_data_table.py
index 799403c85..f6a2069b2 100644
--- a/src/textual/widgets/_data_table.py
+++ b/src/textual/widgets/_data_table.py
@@ -32,6 +32,8 @@ from .._two_way_dict import TwoWayDict
from .._types import SegmentLines
from .._typing import Literal, TypeAlias
from ..binding import Binding
+from .._typing import Literal
+from ..binding import Binding, BindingType
from ..coordinate import Coordinate
from ..geometry import Region, Size, Spacing, clamp
from ..message import Message
@@ -140,6 +142,48 @@ class Row:
class DataTable(ScrollView, Generic[CellType], can_focus=True):
+ """A tabular widget that contains data."""
+
+ BINDINGS: ClassVar[list[BindingType]] = [
+ Binding("enter", "select_cursor", "Select", show=False),
+ Binding("up", "cursor_up", "Cursor Up", show=False),
+ Binding("down", "cursor_down", "Cursor Down", show=False),
+ Binding("right", "cursor_right", "Cursor Right", show=False),
+ Binding("left", "cursor_left", "Cursor Left", show=False),
+ ]
+ """
+ | Key(s) | Description |
+ | :- | :- |
+ | enter | Select cells under the cursor. |
+ | up | Move the cursor up. |
+ | down | Move the cursor down. |
+ | right | Move the cursor right. |
+ | left | Move the cursor left. |
+ """
+
+ COMPONENT_CLASSES: ClassVar[set[str]] = {
+ "datatable--header",
+ "datatable--cursor-fixed",
+ "datatable--highlight-fixed",
+ "datatable--fixed",
+ "datatable--odd-row",
+ "datatable--even-row",
+ "datatable--highlight",
+ "datatable--cursor",
+ }
+ """
+ | Class | Description |
+ | :- | :- |
+ | `datatable--cursor` | Target the cursor. |
+ | `datatable--cursor-fixed` | Target fixed columns or header under the cursor. |
+ | `datatable--even-row` | Target even rows (row indices start at 0). |
+ | `datatable--fixed` | Target fixed columns or header. |
+ | `datatable--header` | Target the header of the data table. |
+ | `datatable--highlight` | Target the highlighted cell(s). |
+ | `datatable--highlight-fixed` | Target highlighted and fixed columns or header. |
+ | `datatable--odd-row` | Target odd rows (row indices start at 0). |
+ """
+
DEFAULT_CSS = """
App.-dark DataTable {
background:;
@@ -190,25 +234,6 @@ class DataTable(ScrollView, Generic[CellType], can_focus=True):
}
"""
- COMPONENT_CLASSES: ClassVar[set[str]] = {
- "datatable--header",
- "datatable--cursor-fixed",
- "datatable--highlight-fixed",
- "datatable--fixed",
- "datatable--odd-row",
- "datatable--even-row",
- "datatable--highlight",
- "datatable--cursor",
- }
-
- BINDINGS = [
- Binding("enter", "select_cursor", "Select", show=False),
- Binding("up", "cursor_up", "Cursor Up", show=False),
- Binding("down", "cursor_down", "Cursor Down", show=False),
- Binding("right", "cursor_right", "Cursor Right", show=False),
- Binding("left", "cursor_left", "Cursor Left", show=False),
- ]
-
show_header = Reactive(True)
fixed_rows = Reactive(0)
fixed_columns = Reactive(0)
@@ -222,6 +247,125 @@ class DataTable(ScrollView, Generic[CellType], can_focus=True):
)
hover_cell: Reactive[Coordinate] = Reactive(Coordinate(0, 0), repaint=False)
+ class CellHighlighted(Message, bubble=True):
+ """Emitted when the cursor moves to highlight a new cell.
+ It's only relevant when the `cursor_type` is `"cell"`.
+ It's also emitted when the cell cursor is re-enabled (by setting `show_cursor=True`),
+ and when the cursor type is changed to `"cell"`. Can be handled using
+ `on_data_table_cell_highlighted` in a subclass of `DataTable` or in a parent
+ widget in the DOM.
+
+ Attributes:
+ value: The value in the highlighted cell.
+ coordinate: The coordinate of the highlighted cell.
+ """
+
+ def __init__(
+ self, sender: DataTable, value: CellType, coordinate: Coordinate
+ ) -> None:
+ self.value: CellType = value
+ self.coordinate: Coordinate = coordinate
+ super().__init__(sender)
+
+ def __rich_repr__(self) -> rich.repr.Result:
+ yield "sender", self.sender
+ yield "value", self.value
+ yield "coordinate", self.coordinate
+
+ class CellSelected(Message, bubble=True):
+ """Emitted by the `DataTable` widget when a cell is selected.
+ It's only relevant when the `cursor_type` is `"cell"`. Can be handled using
+ `on_data_table_cell_selected` in a subclass of `DataTable` or in a parent
+ widget in the DOM.
+
+ Attributes:
+ value: The value in the cell that was selected.
+ coordinate: The coordinate of the cell that was selected.
+ """
+
+ def __init__(
+ self, sender: DataTable, value: CellType, coordinate: Coordinate
+ ) -> None:
+ self.value: CellType = value
+ self.coordinate: Coordinate = coordinate
+ super().__init__(sender)
+
+ def __rich_repr__(self) -> rich.repr.Result:
+ yield "sender", self.sender
+ yield "value", self.value
+ yield "coordinate", self.coordinate
+
+ class RowHighlighted(Message, bubble=True):
+ """Emitted when a row is highlighted. This message is only emitted when the
+ `cursor_type` is set to `"row"`. Can be handled using `on_data_table_row_highlighted`
+ in a subclass of `DataTable` or in a parent widget in the DOM.
+
+ Attributes:
+ cursor_row: The y-coordinate of the cursor that highlighted the row.
+ """
+
+ def __init__(self, sender: DataTable, cursor_row: int) -> None:
+ self.cursor_row: int = cursor_row
+ super().__init__(sender)
+
+ def __rich_repr__(self) -> rich.repr.Result:
+ yield "sender", self.sender
+ yield "cursor_row", self.cursor_row
+
+ class RowSelected(Message, bubble=True):
+ """Emitted when a row is selected. This message is only emitted when the
+ `cursor_type` is set to `"row"`. Can be handled using
+ `on_data_table_row_selected` in a subclass of `DataTable` or in a parent
+ widget in the DOM.
+
+ Attributes:
+ cursor_row: The y-coordinate of the cursor that made the selection.
+ """
+
+ def __init__(self, sender: DataTable, cursor_row: int) -> None:
+ self.cursor_row: int = cursor_row
+ super().__init__(sender)
+
+ def __rich_repr__(self) -> rich.repr.Result:
+ yield "sender", self.sender
+ yield "cursor_row", self.cursor_row
+
+ class ColumnHighlighted(Message, bubble=True):
+ """Emitted when a column is highlighted. This message is only emitted when the
+ `cursor_type` is set to `"column"`. Can be handled using
+ `on_data_table_column_highlighted` in a subclass of `DataTable` or in a parent
+ widget in the DOM.
+
+ Attributes:
+ cursor_column: The x-coordinate of the column that was highlighted.
+ """
+
+ def __init__(self, sender: DataTable, cursor_column: int) -> None:
+ self.cursor_column: int = cursor_column
+ super().__init__(sender)
+
+ def __rich_repr__(self) -> rich.repr.Result:
+ yield "sender", self.sender
+ yield "cursor_column", self.cursor_column
+
+ class ColumnSelected(Message, bubble=True):
+ """Emitted when a column is selected. This message is only emitted when the
+ `cursor_type` is set to `"column"`. Can be handled using
+ `on_data_table_column_selected` in a subclass of `DataTable` or in a parent
+ widget in the DOM.
+
+ Attributes:
+ cursor_column: The x-coordinate of the column that was selected.
+ """
+
+ def __init__(self, sender: DataTable, cursor_column: int) -> None:
+ self.cursor_column: int = cursor_column
+ super().__init__(sender)
+
+ def __rich_repr__(self) -> rich.repr.Result:
+ yield "sender", self.sender
+ yield "cursor_column", self.cursor_column
+
def __init__(
self,
*,
@@ -1259,122 +1403,3 @@ class DataTable(ScrollView, Generic[CellType], can_focus=True):
elif cursor_type == "column":
_, column = cursor_cell
self.emit_no_wait(DataTable.ColumnSelected(self, column))
-
- class CellHighlighted(Message, bubble=True):
- """Emitted when the cursor moves to highlight a new cell.
- It's only relevant when the `cursor_type` is `"cell"`.
- It's also emitted when the cell cursor is re-enabled (by setting `show_cursor=True`),
- and when the cursor type is changed to `"cell"`. Can be handled using
- `on_data_table_cell_highlighted` in a subclass of `DataTable` or in a parent
- widget in the DOM.
-
- Attributes:
- value: The value in the highlighted cell.
- coordinate: The coordinate of the highlighted cell.
- """
-
- def __init__(
- self, sender: DataTable, value: CellType, coordinate: Coordinate
- ) -> None:
- self.value: CellType = value
- self.coordinate: Coordinate = coordinate
- super().__init__(sender)
-
- def __rich_repr__(self) -> rich.repr.Result:
- yield "sender", self.sender
- yield "value", self.value
- yield "coordinate", self.coordinate
-
- class CellSelected(Message, bubble=True):
- """Emitted by the `DataTable` widget when a cell is selected.
- It's only relevant when the `cursor_type` is `"cell"`. Can be handled using
- `on_data_table_cell_selected` in a subclass of `DataTable` or in a parent
- widget in the DOM.
-
- Attributes:
- value: The value in the cell that was selected.
- coordinate: The coordinate of the cell that was selected.
- """
-
- def __init__(
- self, sender: DataTable, value: CellType, coordinate: Coordinate
- ) -> None:
- self.value: CellType = value
- self.coordinate: Coordinate = coordinate
- super().__init__(sender)
-
- def __rich_repr__(self) -> rich.repr.Result:
- yield "sender", self.sender
- yield "value", self.value
- yield "coordinate", self.coordinate
-
- class RowHighlighted(Message, bubble=True):
- """Emitted when a row is highlighted. This message is only emitted when the
- `cursor_type` is set to `"row"`. Can be handled using `on_data_table_row_highlighted`
- in a subclass of `DataTable` or in a parent widget in the DOM.
-
- Attributes:
- cursor_row: The y-coordinate of the cursor that highlighted the row.
- """
-
- def __init__(self, sender: DataTable, cursor_row: int) -> None:
- self.cursor_row: int = cursor_row
- super().__init__(sender)
-
- def __rich_repr__(self) -> rich.repr.Result:
- yield "sender", self.sender
- yield "cursor_row", self.cursor_row
-
- class RowSelected(Message, bubble=True):
- """Emitted when a row is selected. This message is only emitted when the
- `cursor_type` is set to `"row"`. Can be handled using
- `on_data_table_row_selected` in a subclass of `DataTable` or in a parent
- widget in the DOM.
-
- Attributes:
- cursor_row: The y-coordinate of the cursor that made the selection.
- """
-
- def __init__(self, sender: DataTable, cursor_row: int) -> None:
- self.cursor_row: int = cursor_row
- super().__init__(sender)
-
- def __rich_repr__(self) -> rich.repr.Result:
- yield "sender", self.sender
- yield "cursor_row", self.cursor_row
-
- class ColumnHighlighted(Message, bubble=True):
- """Emitted when a column is highlighted. This message is only emitted when the
- `cursor_type` is set to `"column"`. Can be handled using
- `on_data_table_column_highlighted` in a subclass of `DataTable` or in a parent
- widget in the DOM.
-
- Attributes:
- cursor_column: The x-coordinate of the column that was highlighted.
- """
-
- def __init__(self, sender: DataTable, cursor_column: int) -> None:
- self.cursor_column: int = cursor_column
- super().__init__(sender)
-
- def __rich_repr__(self) -> rich.repr.Result:
- yield "sender", self.sender
- yield "cursor_column", self.cursor_column
-
- class ColumnSelected(Message, bubble=True):
- """Emitted when a column is selected. This message is only emitted when the
- `cursor_type` is set to `"column"`. Can be handled using
- `on_data_table_column_selected` in a subclass of `DataTable` or in a parent
- widget in the DOM.
-
- Attributes:
- cursor_column: The x-coordinate of the column that was selected.
- """
-
- def __init__(self, sender: DataTable, cursor_column: int) -> None:
- self.cursor_column: int = cursor_column
- super().__init__(sender)
-
- def __rich_repr__(self) -> rich.repr.Result:
- yield "sender", self.sender
- yield "cursor_column", self.cursor_column
diff --git a/src/textual/widgets/_directory_tree.py b/src/textual/widgets/_directory_tree.py
index 2ca41badd..0be163d67 100644
--- a/src/textual/widgets/_directory_tree.py
+++ b/src/textual/widgets/_directory_tree.py
@@ -32,18 +32,21 @@ class DirectoryTree(Tree[DirEntry]):
"""
COMPONENT_CLASSES: ClassVar[set[str]] = {
- "tree--label",
- "tree--guides",
- "tree--guides-hover",
- "tree--guides-selected",
- "tree--cursor",
- "tree--highlight",
- "tree--highlight-line",
"directory-tree--folder",
"directory-tree--file",
"directory-tree--extension",
"directory-tree--hidden",
}
+ """
+ | Class | Description |
+ | :- | :- |
+ | `directory-tree--extension` | Target the extension of a file name. |
+ | `directory-tree--file` | Target files in the directory structure. |
+ | `directory-tree--folder` | Target folders in the directory structure. |
+ | `directory-tree--hidden` | Target hidden items in the directory structure. |
+
+ See also the [component classes for `Tree`][textual.widgets.Tree.COMPONENT_CLASSES].
+ """
DEFAULT_CSS = """
DirectoryTree > .directory-tree--folder {
@@ -64,8 +67,17 @@ class DirectoryTree(Tree[DirEntry]):
"""
class FileSelected(Message, bubble=True):
+ """Emitted when a file is selected.
+
+ Can be handled using `on_directory_tree_file_selected` in a subclass of
+ `DirectoryTree` or in a parent widget in the DOM.
+
+ Attributes:
+ path: The path of the file that was selected.
+ """
+
def __init__(self, sender: MessageTarget, path: str) -> None:
- self.path = path
+ self.path: str = path
super().__init__(sender)
def __init__(
diff --git a/src/textual/widgets/_footer.py b/src/textual/widgets/_footer.py
index 24e6826c0..0b1c9a808 100644
--- a/src/textual/widgets/_footer.py
+++ b/src/textual/widgets/_footer.py
@@ -1,13 +1,13 @@
from __future__ import annotations
from collections import defaultdict
+from typing import ClassVar
import rich.repr
from rich.console import RenderableType
from rich.text import Text
from .. import events
-from ..keys import _get_key_display
from ..reactive import Reactive, watch
from ..widget import Widget
@@ -16,6 +16,21 @@ from ..widget import Widget
class Footer(Widget):
"""A simple footer widget which docks itself to the bottom of the parent container."""
+ COMPONENT_CLASSES: ClassVar[set[str]] = {
+ "footer--description",
+ "footer--key",
+ "footer--highlight",
+ "footer--highlight-key",
+ }
+ """
+ | Class | Description |
+ | :- | :- |
+ | `footer--description` | Targets the descriptions of the key bindings. |
+ | `footer--highlight` | Targets the highlighted key binding. |
+ | `footer--highlight-key` | Targets the key portion of the highlighted key binding. |
+ | `footer--key` | Targets the key portions of the key bindings. |
+ """
+
DEFAULT_CSS = """
Footer {
background: $accent;
@@ -38,20 +53,13 @@ class Footer(Widget):
}
"""
- COMPONENT_CLASSES = {
- "footer--description",
- "footer--key",
- "footer--highlight",
- "footer--highlight-key",
- }
+ highlight_key: Reactive[str | None] = Reactive(None)
def __init__(self) -> None:
super().__init__()
self._key_text: Text | None = None
self.auto_links = False
- highlight_key: Reactive[str | None] = Reactive(None)
-
async def watch_highlight_key(self, value) -> None:
"""If highlight key changes we need to regenerate the text."""
self._key_text = None
diff --git a/src/textual/widgets/_header.py b/src/textual/widgets/_header.py
index 8f107ba44..b2df426cc 100644
--- a/src/textual/widgets/_header.py
+++ b/src/textual/widgets/_header.py
@@ -100,10 +100,10 @@ class Header(Widget):
}
"""
- tall = Reactive(False)
-
DEFAULT_CLASSES = ""
+ tall = Reactive(False)
+
def __init__(
self,
show_clock: bool = False,
diff --git a/src/textual/widgets/_input.py b/src/textual/widgets/_input.py
index ba55f2cf8..b09b96310 100644
--- a/src/textual/widgets/_input.py
+++ b/src/textual/widgets/_input.py
@@ -1,4 +1,5 @@
from __future__ import annotations
+from typing import ClassVar
import re
@@ -10,7 +11,7 @@ from rich.text import Text
from .. import events
from .._segment_tools import line_crop
-from ..binding import Binding
+from ..binding import Binding, BindingType
from ..geometry import Size
from ..message import Message
from ..reactive import reactive
@@ -55,6 +56,51 @@ class _InputRenderable:
class Input(Widget, can_focus=True):
"""A text input widget."""
+ BINDINGS: ClassVar[list[BindingType]] = [
+ Binding("left", "cursor_left", "cursor left", show=False),
+ Binding("ctrl+left", "cursor_left_word", "cursor left word", show=False),
+ Binding("right", "cursor_right", "cursor right", show=False),
+ Binding("ctrl+right", "cursor_right_word", "cursor right word", show=False),
+ Binding("backspace", "delete_left", "delete left", show=False),
+ Binding("home,ctrl+a", "home", "home", show=False),
+ Binding("end,ctrl+e", "end", "end", show=False),
+ Binding("delete,ctrl+d", "delete_right", "delete right", show=False),
+ Binding("enter", "submit", "submit", show=False),
+ Binding(
+ "ctrl+w", "delete_left_word", "delete left to start of word", show=False
+ ),
+ Binding("ctrl+u", "delete_left_all", "delete all to the left", show=False),
+ Binding(
+ "ctrl+f", "delete_right_word", "delete right to start of word", show=False
+ ),
+ Binding("ctrl+k", "delete_right_all", "delete all to the right", show=False),
+ ]
+ """
+ | Key(s) | Description |
+ | :- | :- |
+ | left | Move the cursor left. |
+ | ctrl+left | Move the cursor one word to the left. |
+ | right | Move the cursor right. |
+ | ctrl+right | Move the cursor one word to the right. |
+ | backspace | Delete the character to the left of the cursor. |
+ | home,ctrl+a | Go to the beginning of the input. |
+ | end,ctrl+e | Go to the end of the input. |
+ | delete,ctrl+d | Delete the character to the right of the cursor. |
+ | enter | Submit the current value of the input. |
+ | ctrl+w | Delete the word to the left of the cursor. |
+ | ctrl+u | Delete everything to the left of the cursor. |
+ | ctrl+f | Delete the word to the right of the cursor. |
+ | ctrl+k | Delete everything to the right of the cursor. |
+ """
+
+ COMPONENT_CLASSES: ClassVar[set[str]] = {"input--cursor", "input--placeholder"}
+ """
+ | Class | Description |
+ | :- | :- |
+ | `input--cursor` | Target the cursor. |
+ | `input--placeholder` | Target the placeholder text (when it exists). |
+ """
+
DEFAULT_CSS = """
Input {
background: $boost;
@@ -81,28 +127,6 @@ class Input(Widget, can_focus=True):
}
"""
- BINDINGS = [
- Binding("left", "cursor_left", "cursor left", show=False),
- Binding("ctrl+left", "cursor_left_word", "cursor left word", show=False),
- Binding("right", "cursor_right", "cursor right", show=False),
- Binding("ctrl+right", "cursor_right_word", "cursor right word", show=False),
- Binding("home,ctrl+a", "home", "home", show=False),
- Binding("end,ctrl+e", "end", "end", show=False),
- Binding("enter", "submit", "submit", show=False),
- Binding("backspace", "delete_left", "delete left", show=False),
- Binding(
- "ctrl+w", "delete_left_word", "delete left to start of word", show=False
- ),
- Binding("ctrl+u", "delete_left_all", "delete all to the left", show=False),
- Binding("delete,ctrl+d", "delete_right", "delete right", show=False),
- Binding(
- "ctrl+f", "delete_right_word", "delete right to start of word", show=False
- ),
- Binding("ctrl+k", "delete_right_all", "delete all to the right", show=False),
- ]
-
- COMPONENT_CLASSES = {"input--cursor", "input--placeholder"}
-
cursor_blink = reactive(True)
value = reactive("", layout=True, init=False)
input_scroll_offset = reactive(0)
@@ -115,6 +139,38 @@ class Input(Widget, can_focus=True):
password = reactive(False)
max_size: reactive[int | None] = reactive(None)
+ class Changed(Message, bubble=True):
+ """Emitted when the value changes.
+
+ Can be handled using `on_input_changed` in a subclass of `Input` or in a parent
+ widget in the DOM.
+
+ Attributes:
+ value: The value that the input was changed to.
+ input: The `Input` widget that was changed.
+ """
+
+ def __init__(self, sender: Input, value: str) -> None:
+ super().__init__(sender)
+ self.value: str = value
+ self.input: Input = sender
+
+ class Submitted(Message, bubble=True):
+ """Emitted when the enter key is pressed within an `Input`.
+
+ Can be handled using `on_input_submitted` in a subclass of `Input` or in a
+ parent widget in the DOM.
+
+ Attributes:
+ value: The value of the `Input` being submitted.
+ input: The `Input` widget that is being submitted.
+ """
+
+ def __init__(self, sender: Input, value: str) -> None:
+ super().__init__(sender)
+ self.value: str = value
+ self.input: Input = sender
+
def __init__(
self,
value: str | None = None,
@@ -398,29 +454,3 @@ class Input(Widget, can_focus=True):
async def action_submit(self) -> None:
await self.emit(self.Submitted(self, self.value))
-
- class Changed(Message, bubble=True):
- """Value was changed.
-
- Attributes:
- value: The value that the input was changed to.
- input: The `Input` widget that was changed.
- """
-
- def __init__(self, sender: Input, value: str) -> None:
- super().__init__(sender)
- self.value: str = value
- self.input: Input = sender
-
- class Submitted(Message, bubble=True):
- """Sent when the enter key is pressed within an `Input`.
-
- Attributes:
- value: The value of the `Input` being submitted..
- input: The `Input` widget that is being submitted.
- """
-
- def __init__(self, sender: Input, value: str) -> None:
- super().__init__(sender)
- self.value: str = value
- self.input: Input = sender
diff --git a/src/textual/widgets/_label.py b/src/textual/widgets/_label.py
index 344c37013..d890d333b 100644
--- a/src/textual/widgets/_label.py
+++ b/src/textual/widgets/_label.py
@@ -12,4 +12,3 @@ class Label(Static):
height: auto;
}
"""
- """str: The default styling of a `Label`."""
diff --git a/src/textual/widgets/_list_item.py b/src/textual/widgets/_list_item.py
index 1100621c6..f1af8c416 100644
--- a/src/textual/widgets/_list_item.py
+++ b/src/textual/widgets/_list_item.py
@@ -25,15 +25,16 @@ class ListItem(Widget, can_focus=False):
height: auto;
}
"""
+
highlighted = reactive(False)
+ class _ChildClicked(Message):
+ """For informing with the parent ListView that we were clicked"""
+
+ pass
+
def on_click(self, event: events.Click) -> None:
self.emit_no_wait(self._ChildClicked(self))
def watch_highlighted(self, value: bool) -> None:
self.set_class(value, "--highlight")
-
- class _ChildClicked(Message):
- """For informing with the parent ListView that we were clicked"""
-
- pass
diff --git a/src/textual/widgets/_list_view.py b/src/textual/widgets/_list_view.py
index 3cf65d076..87675ec47 100644
--- a/src/textual/widgets/_list_view.py
+++ b/src/textual/widgets/_list_view.py
@@ -1,8 +1,9 @@
from __future__ import annotations
+from typing import ClassVar
from textual import events
from textual.await_remove import AwaitRemove
-from textual.binding import Binding
+from textual.binding import Binding, BindingType
from textual.containers import Vertical
from textual.geometry import clamp
from textual.message import Message
@@ -19,14 +20,50 @@ class ListView(Vertical, can_focus=True, can_focus_children=False):
index: The index in the list that's currently highlighted.
"""
- BINDINGS = [
+ BINDINGS: ClassVar[list[BindingType]] = [
Binding("enter", "select_cursor", "Select", show=False),
Binding("up", "cursor_up", "Cursor Up", show=False),
Binding("down", "cursor_down", "Cursor Down", show=False),
]
+ """
+ | Key(s) | Description |
+ | :- | :- |
+ | enter | Select the current item. |
+ | up | Move the cursor up. |
+ | down | Move the cursor down. |
+ """
index = reactive(0, always_update=True)
+ class Highlighted(Message, bubble=True):
+ """Emitted when the highlighted item changes.
+
+ Highlighted item is controlled using up/down keys.
+ Can be handled using `on_list_view_highlighted` in a subclass of `ListView`
+ or in a parent widget in the DOM.
+
+ Attributes:
+ item: The highlighted item, if there is one highlighted.
+ """
+
+ def __init__(self, sender: ListView, item: ListItem | None) -> None:
+ super().__init__(sender)
+ self.item: ListItem | None = item
+
+ class Selected(Message, bubble=True):
+ """Emitted when a list item is selected, e.g. when you press the enter key on it.
+
+ Can be handled using `on_list_view_selected` in a subclass of `ListView` or in
+ a parent widget in the DOM.
+
+ Attributes:
+ item: The selected item.
+ """
+
+ def __init__(self, sender: ListView, item: ListItem) -> None:
+ super().__init__(sender)
+ self.item: ListItem = item
+
def __init__(
self,
*children: ListItem,
@@ -139,25 +176,3 @@ class ListView(Vertical, can_focus=True, can_focus_children=False):
def __len__(self):
return len(self.children)
-
- class Highlighted(Message, bubble=True):
- """Emitted when the highlighted item changes. Highlighted item is controlled using up/down keys.
-
- Attributes:
- item: The highlighted item, if there is one highlighted.
- """
-
- def __init__(self, sender: ListView, item: ListItem | None) -> None:
- super().__init__(sender)
- self.item: ListItem | None = item
-
- class Selected(Message, bubble=True):
- """Emitted when a list item is selected, e.g. when you press the enter key on it
-
- Attributes:
- item: The selected item.
- """
-
- def __init__(self, sender: ListView, item: ListItem) -> None:
- super().__init__(sender)
- self.item: ListItem = item
diff --git a/src/textual/widgets/_tree.py b/src/textual/widgets/_tree.py
index b26ccd1c7..64e40ebe2 100644
--- a/src/textual/widgets/_tree.py
+++ b/src/textual/widgets/_tree.py
@@ -14,7 +14,7 @@ from .._segment_tools import line_pad
from .._types import MessageTarget
from .._typing import TypeAlias
from .._immutable_sequence_view import ImmutableSequenceView
-from ..binding import Binding
+from ..binding import Binding, BindingType
from ..geometry import Region, Size, clamp
from ..message import Message
from ..reactive import reactive, var
@@ -282,11 +282,39 @@ class TreeNode(Generic[TreeDataType]):
class Tree(Generic[TreeDataType], ScrollView, can_focus=True):
- BINDINGS = [
+ BINDINGS: ClassVar[list[BindingType]] = [
Binding("enter", "select_cursor", "Select", show=False),
Binding("up", "cursor_up", "Cursor Up", show=False),
Binding("down", "cursor_down", "Cursor Down", show=False),
]
+ """
+ | Key(s) | Description |
+ | :- | :- |
+ | enter | Select the current item. |
+ | up | Move the cursor up. |
+ | down | Move the cursor down. |
+ """
+
+ COMPONENT_CLASSES: ClassVar[set[str]] = {
+ "tree--label",
+ "tree--guides",
+ "tree--guides-hover",
+ "tree--guides-selected",
+ "tree--cursor",
+ "tree--highlight",
+ "tree--highlight-line",
+ }
+ """
+ | Class | Description |
+ | :- | :- |
+ | `tree--cursor` | Targets the cursor. |
+ | `tree--guides` | Targets the indentation guides. |
+ | `tree--guides-hover` | Targets the indentation guides under the cursor. |
+ | `tree--guides-selected` | Targets the indentation guides that are selected. |
+ | `tree--highlight` | Targets the highlighted items. |
+ | `tree--highlight-line` | Targets the lines under the cursor. |
+ | `tree--label` | Targets the (text) labels of the items. |
+ """
DEFAULT_CSS = """
Tree {
@@ -326,16 +354,6 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True):
"""
- COMPONENT_CLASSES: ClassVar[set[str]] = {
- "tree--label",
- "tree--guides",
- "tree--guides-hover",
- "tree--guides-selected",
- "tree--cursor",
- "tree--highlight",
- "tree--highlight-line",
- }
-
show_root = reactive(True)
"""bool: Show the root of the tree."""
hover_line = var(-1)
@@ -370,35 +388,12 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True):
),
}
- class NodeSelected(Generic[EventTreeDataType], Message, bubble=True):
- """Event sent when a node is selected.
-
- Attributes:
- node: The node that was selected.
- """
-
- def __init__(
- self, sender: MessageTarget, node: TreeNode[EventTreeDataType]
- ) -> None:
- self.node: TreeNode[EventTreeDataType] = node
- super().__init__(sender)
-
- class NodeExpanded(Generic[EventTreeDataType], Message, bubble=True):
- """Event sent when a node is expanded.
-
- Attributes:
- node: The node that was expanded.
- """
-
- def __init__(
- self, sender: MessageTarget, node: TreeNode[EventTreeDataType]
- ) -> None:
- self.node: TreeNode[EventTreeDataType] = node
- super().__init__(sender)
-
class NodeCollapsed(Generic[EventTreeDataType], Message, bubble=True):
"""Event sent when a node is collapsed.
+ Can be handled using `on_tree_node_collapsed` in a subclass of `Tree` or in a
+ parent node in the DOM.
+
Attributes:
node: The node that was collapsed.
"""
@@ -409,9 +404,28 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True):
self.node: TreeNode[EventTreeDataType] = node
super().__init__(sender)
+ class NodeExpanded(Generic[EventTreeDataType], Message, bubble=True):
+ """Event sent when a node is expanded.
+
+ Can be handled using `on_tree_node_expanded` in a subclass of `Tree` or in a
+ parent node in the DOM.
+
+ Attributes:
+ node: The node that was expanded.
+ """
+
+ def __init__(
+ self, sender: MessageTarget, node: TreeNode[EventTreeDataType]
+ ) -> None:
+ self.node: TreeNode[EventTreeDataType] = node
+ super().__init__(sender)
+
class NodeHighlighted(Generic[EventTreeDataType], Message, bubble=True):
"""Event sent when a node is highlighted.
+ Can be handled using `on_tree_node_highlighted` in a subclass of `Tree` or in a
+ parent node in the DOM.
+
Attributes:
node: The node that was highlighted.
"""
@@ -422,6 +436,22 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True):
self.node: TreeNode[EventTreeDataType] = node
super().__init__(sender)
+ class NodeSelected(Generic[EventTreeDataType], Message, bubble=True):
+ """Event sent when a node is selected.
+
+ Can be handled using `on_tree_node_selected` in a subclass of `Tree` or in a
+ parent node in the DOM.
+
+ Attributes:
+ node: The node that was selected.
+ """
+
+ def __init__(
+ self, sender: MessageTarget, node: TreeNode[EventTreeDataType]
+ ) -> None:
+ self.node: TreeNode[EventTreeDataType] = node
+ super().__init__(sender)
+
def __init__(
self,
label: TextType,
diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr
index d2e876605..ee111dbd1 100644
--- a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr
+++ b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr
@@ -12380,6 +12380,164 @@
'''
# ---
+# name: test_label_widths
+ '''
+