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 + ''' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LabelWrap + + + + + + + + + + + + + + + + Apple Banana Cherry Mango Fig Guava Pineapple:Dragon Unicorn Centaur Phoenix Ch + + + Apple Banana Cherry Mango Fig Guava Pineapple:Dragon Unicorn Centaur Phoenix  + Chimera Castle + + + โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ + โ”‚Apple Banana Cherry Mango Fig Guava Pineapple:Dragon Unicorn Centaur โ”‚ + โ”‚Phoenix Chimera Castleโ”‚ + โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + + + + + + + + + + + + ''' +# --- # name: test_layers ''' diff --git a/tests/snapshot_tests/snapshot_apps/label_widths.py b/tests/snapshot_tests/snapshot_apps/label_widths.py new file mode 100644 index 000000000..2cc49d2f9 --- /dev/null +++ b/tests/snapshot_tests/snapshot_apps/label_widths.py @@ -0,0 +1,45 @@ +from textual.app import App +from textual.widgets import Label, Static +from rich.panel import Panel + + +class LabelWrap(App): + CSS = """Screen { + align: center middle; + } + + #l_data { + border: blank; + background: lightgray; + } + + #s_data { + border: blank; + background: lightgreen; + } + + #p_data { + border: blank; + background: lightgray; + }""" + + def __init__(self): + super().__init__() + + self.data = ( + "Apple Banana Cherry Mango Fig Guava Pineapple:" + "Dragon Unicorn Centaur Phoenix Chimera Castle" + ) + + def compose(self): + yield Label(self.data, id="l_data") + yield Static(self.data, id="s_data") + yield Label(Panel(self.data), id="p_data") + + def on_mount(self): + self.dark = False + + +if __name__ == "__main__": + app = LabelWrap() + app.run() diff --git a/tests/snapshot_tests/test_snapshots.py b/tests/snapshot_tests/test_snapshots.py index 8aa2b6514..bdad3bf53 100644 --- a/tests/snapshot_tests/test_snapshots.py +++ b/tests/snapshot_tests/test_snapshots.py @@ -193,3 +193,8 @@ def test_demo(snap_compare): press=["down", "down", "down"], terminal_size=(100, 30), ) + + +def test_label_widths(snap_compare): + """Test renderable widths are calculate correctly.""" + assert snap_compare(SNAPSHOT_APPS_DIR / "label_widths.py") diff --git a/tests/test_animation.py b/tests/test_animation.py index 8aa1615a2..20805ae9f 100644 --- a/tests/test_animation.py +++ b/tests/test_animation.py @@ -153,8 +153,8 @@ async def test_schedule_reverse_animations() -> None: assert styles.background.rgb == (0, 0, 0) # Now, the actual test is to make sure we go back to black if scheduling both at once. - styles.animate("background", "white", delay=0.01, duration=0.01) - await pilot.pause(0.005) - styles.animate("background", "black", delay=0.01, duration=0.01) + styles.animate("background", "white", delay=0.05, duration=0.01) + await pilot.pause() + styles.animate("background", "black", delay=0.05, duration=0.01) await pilot.wait_for_scheduled_animations() assert styles.background.rgb == (0, 0, 0) diff --git a/tests/test_paste.py b/tests/test_paste.py new file mode 100644 index 000000000..58c5da41d --- /dev/null +++ b/tests/test_paste.py @@ -0,0 +1,18 @@ +from textual.app import App +from textual import events + + +async def test_paste_app(): + paste_events = [] + + class PasteApp(App): + def on_paste(self, event): + paste_events.append(event) + + app = PasteApp() + async with app.run_test() as pilot: + await app.post_message(events.Paste(sender=app, text="Hello")) + await pilot.pause(0) + + assert len(paste_events) == 1 + assert paste_events[0].text == "Hello" diff --git a/tools/widget_documentation.py b/tools/widget_documentation.py new file mode 100644 index 000000000..04f3de86b --- /dev/null +++ b/tools/widget_documentation.py @@ -0,0 +1,79 @@ +""" +Helper script to help document all widgets. + +This goes through the widgets listed in textual.widgets and prints the scaffolding +for the tables that are used to document the classvars BINDINGS and COMPONENT_CLASSES. +""" +from __future__ import annotations + +from typing import TYPE_CHECKING + +import textual.widgets + +if TYPE_CHECKING: + from textual.binding import Binding + + +def print_bindings(widget: str, bindings: list[Binding]) -> None: + """Print a table summarising the bindings. + + The table contains columns for the key(s) that trigger the binding, + the method that it calls (and tries to link it to the widget itself), + and the description of the binding. + """ + if bindings: + print("BINDINGS") + print('"""') + print("| Key(s) | Description |") + print("| :- | :- |") + + for binding in bindings: + print(f"| {binding.key} | {binding.description} |") + + if bindings: + print('"""') + + +def print_component_classes(classes: set[str]) -> None: + """Print a table to document these component classes. + + The table contains two columns, one with the component class name and another + for the description of what the component class is for. + The second column is always empty. + """ + if classes: + print("COMPONENT_CLASSES") + print('"""') + print("| Class | Description |") + print("| :- | :- |") + + for cls in sorted(classes): + print(f"| `{cls}` | XXX |") + + if classes: + print('"""') + + +def main() -> None: + """Main entrypoint. + + Iterates over all widgets and prints docs tables. + """ + + widgets: list[str] = textual.widgets.__all__ + + for widget in widgets: + w = getattr(textual.widgets, widget) + bindings: list[Binding] = w.__dict__.get("BINDINGS", []) + component_classes: set[str] = getattr(w, "COMPONENT_CLASSES", set()) + + if bindings or component_classes: + print(widget) + print() + print_bindings(widget, bindings) + print_component_classes(component_classes) + print() + + +if __name__ == "__main__": + main()