mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Merge branch 'vertical-layout' into horizontal-layout
This commit is contained in:
11
CHANGELOG.md
11
CHANGELOG.md
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
## [1.1.15] - 2022-01-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added Windows Driver
|
||||||
|
|
||||||
|
## [1.1.14] - 2022-01-09
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Updated Rich dependency to 11.X
|
||||||
|
|
||||||
## [0.1.13] - 2022-01-01
|
## [0.1.13] - 2022-01-01
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,11 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
Textual is a TUI (Text User Interface) framework for Python inspired by modern web development.
|
Textual is a TUI (Text User Interface) framework for Python inspired by modern web development. Currently a **Work in Progress**.
|
||||||
|
|
||||||
|
|
||||||
|
> ⚠ **NOTE:** We ([Textualize.io](https://www.textualize.io)) are hard at work on the **css** branch. We will be maintain the 0.1.0 branch for the near future but may not be able to accept API changes. If you would like to contribute code via a PR, please raise a discussion first, to avoid disapointment.
|
||||||
|
|
||||||
**NOTE:** This project is currently a work in progress, but usable by brave souls who don't mind some API instability between updates.
|
|
||||||
|
|
||||||
Follow [@willmcgugan](https://twitter.com/willmcgugan) for progress updates, or post in Discussions if you have any requests / suggestions.
|
Follow [@willmcgugan](https://twitter.com/willmcgugan) for progress updates, or post in Discussions if you have any requests / suggestions.
|
||||||
|
|
||||||
@@ -12,7 +14,7 @@ Follow [@willmcgugan](https://twitter.com/willmcgugan) for progress updates, or
|
|||||||
|
|
||||||
## Compatibility
|
## Compatibility
|
||||||
|
|
||||||
Textual currently runs on **MacOS / Linux only**. Windows support is in the pipeline.
|
Textual currently runs on **MacOS / Linux / Window**.
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
|
|||||||
@@ -32,5 +32,7 @@ class SmoothApp(App):
|
|||||||
|
|
||||||
self.bar.layout_offset_x = -40
|
self.bar.layout_offset_x = -40
|
||||||
|
|
||||||
|
# self.set_timer(10, lambda: self.action("quit"))
|
||||||
|
|
||||||
SmoothApp.run(log="textual.log")
|
|
||||||
|
SmoothApp.run(log="textual.log", log_verbosity=2)
|
||||||
|
|||||||
424
poetry.lock
generated
424
poetry.lock
generated
@@ -19,32 +19,17 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "attrs"
|
name = "attrs"
|
||||||
version = "21.2.0"
|
version = "21.4.0"
|
||||||
description = "Classes Without Boilerplate"
|
description = "Classes Without Boilerplate"
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"]
|
dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"]
|
||||||
docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
|
docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
|
||||||
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"]
|
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"]
|
||||||
tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"]
|
tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "backports.entry-points-selectable"
|
|
||||||
version = "1.1.0"
|
|
||||||
description = "Compatibility shim providing selectable entry points for older implementations"
|
|
||||||
category = "dev"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
|
|
||||||
testing = ["pytest (>=4.6)", "pytest-flake8", "pytest-cov", "pytest-black (>=0.3.7)", "pytest-mypy", "pytest-checkdocs (>=2.4)", "pytest-enabler (>=1.0.1)"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "black"
|
name = "black"
|
||||||
@@ -91,7 +76,7 @@ python-versions = ">=3.6.1"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "click"
|
name = "click"
|
||||||
version = "8.0.1"
|
version = "8.0.3"
|
||||||
description = "Composable command line interface toolkit"
|
description = "Composable command line interface toolkit"
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
@@ -122,18 +107,18 @@ test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "coverage"
|
name = "coverage"
|
||||||
version = "5.5"
|
version = "6.3"
|
||||||
description = "Code coverage measurement for Python"
|
description = "Code coverage measurement for Python"
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
toml = ["toml"]
|
toml = ["tomli"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "distlib"
|
name = "distlib"
|
||||||
version = "0.3.2"
|
version = "0.3.4"
|
||||||
description = "Distribution utilities"
|
description = "Distribution utilities"
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
@@ -141,15 +126,19 @@ python-versions = "*"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "filelock"
|
name = "filelock"
|
||||||
version = "3.0.12"
|
version = "3.4.2"
|
||||||
description = "A platform independent file lock."
|
description = "A platform independent file lock."
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"]
|
||||||
|
testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-cov", "pytest-timeout (>=1.4.2)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ghp-import"
|
name = "ghp-import"
|
||||||
version = "2.0.1"
|
version = "2.0.2"
|
||||||
description = "Copy your docs directly to the gh-pages branch."
|
description = "Copy your docs directly to the gh-pages branch."
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
@@ -159,26 +148,26 @@ python-versions = "*"
|
|||||||
python-dateutil = ">=2.8.1"
|
python-dateutil = ">=2.8.1"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
dev = ["twine", "markdown", "flake8"]
|
dev = ["twine", "markdown", "flake8", "wheel"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "identify"
|
name = "identify"
|
||||||
version = "2.2.13"
|
version = "2.4.6"
|
||||||
description = "File identification library for Python"
|
description = "File identification library for Python"
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6.1"
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
license = ["editdistance-s"]
|
license = ["ukkonen"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "importlib-metadata"
|
name = "importlib-metadata"
|
||||||
version = "4.6.4"
|
version = "4.10.1"
|
||||||
description = "Read metadata from Python packages"
|
description = "Read metadata from Python packages"
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
|
typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
|
||||||
@@ -187,7 +176,7 @@ zipp = ">=0.5"
|
|||||||
[package.extras]
|
[package.extras]
|
||||||
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
|
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
|
||||||
perf = ["ipython"]
|
perf = ["ipython"]
|
||||||
testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
|
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iniconfig"
|
name = "iniconfig"
|
||||||
@@ -199,7 +188,7 @@ python-versions = "*"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jinja2"
|
name = "jinja2"
|
||||||
version = "3.0.1"
|
version = "3.0.3"
|
||||||
description = "A very fast and expressive template engine."
|
description = "A very fast and expressive template engine."
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
@@ -213,14 +202,14 @@ i18n = ["Babel (>=2.7)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "markdown"
|
name = "markdown"
|
||||||
version = "3.3.4"
|
version = "3.3.6"
|
||||||
description = "Python implementation of Markdown."
|
description = "Python implementation of Markdown."
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
|
importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""}
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
testing = ["coverage", "pyyaml"]
|
testing = ["coverage", "pyyaml"]
|
||||||
@@ -278,7 +267,7 @@ mkdocs = ">=1.1,<2.0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mkdocs-material"
|
name = "mkdocs-material"
|
||||||
version = "7.2.5"
|
version = "7.3.0"
|
||||||
description = "A Material Design theme for MkDocs"
|
description = "A Material Design theme for MkDocs"
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
@@ -293,14 +282,11 @@ pymdown-extensions = ">=7.0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mkdocs-material-extensions"
|
name = "mkdocs-material-extensions"
|
||||||
version = "1.0.1"
|
version = "1.0.3"
|
||||||
description = "Extension pack for Python Markdown."
|
description = "Extension pack for Python Markdown."
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.5"
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
mkdocs-material = ">=5.0.0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mkdocstrings"
|
name = "mkdocstrings"
|
||||||
@@ -355,14 +341,14 @@ python-versions = "*"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "packaging"
|
name = "packaging"
|
||||||
version = "21.0"
|
version = "21.3"
|
||||||
description = "Core utilities for Python packages"
|
description = "Core utilities for Python packages"
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
pyparsing = ">=2.0.2"
|
pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pathspec"
|
name = "pathspec"
|
||||||
@@ -374,11 +360,11 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "platformdirs"
|
name = "platformdirs"
|
||||||
version = "2.2.0"
|
version = "2.4.1"
|
||||||
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"]
|
docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"]
|
||||||
@@ -386,21 +372,22 @@ test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pluggy"
|
name = "pluggy"
|
||||||
version = "0.13.1"
|
version = "1.0.0"
|
||||||
description = "plugin and hook calling mechanisms for python"
|
description = "plugin and hook calling mechanisms for python"
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
|
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
dev = ["pre-commit", "tox"]
|
dev = ["pre-commit", "tox"]
|
||||||
|
testing = ["pytest", "pytest-benchmark"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pre-commit"
|
name = "pre-commit"
|
||||||
version = "2.14.0"
|
version = "2.17.0"
|
||||||
description = "A framework for managing and maintaining multi-language pre-commit hooks."
|
description = "A framework for managing and maintaining multi-language pre-commit hooks."
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
@@ -417,15 +404,15 @@ virtualenv = ">=20.0.8"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "py"
|
name = "py"
|
||||||
version = "1.10.0"
|
version = "1.11.0"
|
||||||
description = "library with cross-python path, ini-parsing, io, code, log facilities"
|
description = "library with cross-python path, ini-parsing, io, code, log facilities"
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pygments"
|
name = "pygments"
|
||||||
version = "2.10.0"
|
version = "2.11.2"
|
||||||
description = "Pygments is a syntax highlighting package written in Python."
|
description = "Pygments is a syntax highlighting package written in Python."
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
@@ -444,15 +431,18 @@ Markdown = ">=3.2"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyparsing"
|
name = "pyparsing"
|
||||||
version = "2.4.7"
|
version = "3.0.7"
|
||||||
description = "Python parsing module"
|
description = "Python parsing module"
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
diagrams = ["jinja2", "railroad-diagrams"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pytest"
|
name = "pytest"
|
||||||
version = "6.2.4"
|
version = "6.2.5"
|
||||||
description = "pytest: simple powerful testing with Python"
|
description = "pytest: simple powerful testing with Python"
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
@@ -465,7 +455,7 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
|||||||
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
|
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
|
||||||
iniconfig = "*"
|
iniconfig = "*"
|
||||||
packaging = "*"
|
packaging = "*"
|
||||||
pluggy = ">=0.12,<1.0.0a1"
|
pluggy = ">=0.12,<2.0"
|
||||||
py = ">=1.8.2"
|
py = ">=1.8.2"
|
||||||
toml = "*"
|
toml = "*"
|
||||||
|
|
||||||
@@ -517,11 +507,11 @@ numpy-style = ["docstring_parser (>=0.7.3,<0.8.0)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyyaml"
|
name = "pyyaml"
|
||||||
version = "5.4.1"
|
version = "6.0"
|
||||||
description = "YAML parser and emitter for Python"
|
description = "YAML parser and emitter for Python"
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyyaml-env-tag"
|
name = "pyyaml-env-tag"
|
||||||
@@ -536,7 +526,7 @@ pyyaml = "*"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rich"
|
name = "rich"
|
||||||
version = "10.16.1"
|
version = "11.1.0"
|
||||||
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
|
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
@@ -593,51 +583,50 @@ python-versions = "*"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "virtualenv"
|
name = "virtualenv"
|
||||||
version = "20.7.2"
|
version = "20.13.0"
|
||||||
description = "Virtual Python Environment builder"
|
description = "Virtual Python Environment builder"
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
"backports.entry-points-selectable" = ">=1.0.4"
|
|
||||||
distlib = ">=0.3.1,<1"
|
distlib = ">=0.3.1,<1"
|
||||||
filelock = ">=3.0.0,<4"
|
filelock = ">=3.2,<4"
|
||||||
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
|
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
|
||||||
platformdirs = ">=2,<3"
|
platformdirs = ">=2,<3"
|
||||||
six = ">=1.9.0,<2"
|
six = ">=1.9.0,<2"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)"]
|
docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=21.3)"]
|
||||||
testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)"]
|
testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "watchdog"
|
name = "watchdog"
|
||||||
version = "2.1.5"
|
version = "2.1.6"
|
||||||
description = "Filesystem events monitoring"
|
description = "Filesystem events monitoring"
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
watchmedo = ["PyYAML (>=3.10)", "argh (>=0.24.1)"]
|
watchmedo = ["PyYAML (>=3.10)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zipp"
|
name = "zipp"
|
||||||
version = "3.5.0"
|
version = "3.7.0"
|
||||||
description = "Backport of pathlib-compatible object wrapper for zip files"
|
description = "Backport of pathlib-compatible object wrapper for zip files"
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
|
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
|
||||||
testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
|
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "1.1"
|
lock-version = "1.1"
|
||||||
python-versions = "^3.7"
|
python-versions = "^3.7"
|
||||||
content-hash = "d9fa84daf9d3ae9839ebb6e846b73749c4c7737bdcf1160257e3b6ecf7086160"
|
content-hash = "cdb4f091bb4090e971acb3f64c73ee65d099ea7cbf76455ac6e7a99cf6552190"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
astunparse = [
|
astunparse = [
|
||||||
@@ -649,12 +638,8 @@ atomicwrites = [
|
|||||||
{file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
|
{file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
|
||||||
]
|
]
|
||||||
attrs = [
|
attrs = [
|
||||||
{file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"},
|
{file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
|
||||||
{file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"},
|
{file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
|
||||||
]
|
|
||||||
"backports.entry-points-selectable" = [
|
|
||||||
{file = "backports.entry_points_selectable-1.1.0-py2.py3-none-any.whl", hash = "sha256:a6d9a871cde5e15b4c4a53e3d43ba890cc6861ec1332c9c2428c92f977192acc"},
|
|
||||||
{file = "backports.entry_points_selectable-1.1.0.tar.gz", hash = "sha256:988468260ec1c196dab6ae1149260e2f5472c9110334e5d51adcb77867361f6a"},
|
|
||||||
]
|
]
|
||||||
black = [
|
black = [
|
||||||
{file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"},
|
{file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"},
|
||||||
@@ -669,8 +654,8 @@ cfgv = [
|
|||||||
{file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"},
|
{file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"},
|
||||||
]
|
]
|
||||||
click = [
|
click = [
|
||||||
{file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"},
|
{file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"},
|
||||||
{file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"},
|
{file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"},
|
||||||
]
|
]
|
||||||
colorama = [
|
colorama = [
|
||||||
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
|
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
|
||||||
@@ -681,89 +666,82 @@ commonmark = [
|
|||||||
{file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"},
|
{file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"},
|
||||||
]
|
]
|
||||||
coverage = [
|
coverage = [
|
||||||
{file = "coverage-5.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf"},
|
{file = "coverage-6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e8071e7d9ba9f457fc674afc3de054450be2c9b195c470147fbbc082468d8ff7"},
|
||||||
{file = "coverage-5.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b"},
|
{file = "coverage-6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:86c91c511853dfda81c2cf2360502cb72783f4b7cebabef27869f00cbe1db07d"},
|
||||||
{file = "coverage-5.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:c2723d347ab06e7ddad1a58b2a821218239249a9e4365eaff6649d31180c1669"},
|
{file = "coverage-6.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c4ce3b647bd1792d4394f5690d9df6dc035b00bcdbc5595099c01282a59ae01"},
|
||||||
{file = "coverage-5.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:900fbf7759501bc7807fd6638c947d7a831fc9fdf742dc10f02956ff7220fa90"},
|
{file = "coverage-6.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a491e159294d756e7fc8462f98175e2d2225e4dbe062cca7d3e0d5a75ba6260"},
|
||||||
{file = "coverage-5.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:004d1880bed2d97151facef49f08e255a20ceb6f9432df75f4eef018fdd5a78c"},
|
{file = "coverage-6.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d008e0f67ac800b0ca04d7914b8501312c8c6c00ad8c7ba17754609fae1231a"},
|
||||||
{file = "coverage-5.5-cp27-cp27m-win32.whl", hash = "sha256:06191eb60f8d8a5bc046f3799f8a07a2d7aefb9504b0209aff0b47298333302a"},
|
{file = "coverage-6.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4578728c36de2801c1deb1c6b760d31883e62e33f33c7ba8f982e609dc95167d"},
|
||||||
{file = "coverage-5.5-cp27-cp27m-win_amd64.whl", hash = "sha256:7501140f755b725495941b43347ba8a2777407fc7f250d4f5a7d2a1050ba8e82"},
|
{file = "coverage-6.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7ee317486593193e066fc5e98ac0ce712178c21529a85c07b7cb978171f25d53"},
|
||||||
{file = "coverage-5.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:372da284cfd642d8e08ef606917846fa2ee350f64994bebfbd3afb0040436905"},
|
{file = "coverage-6.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2bc85664b06ba42d14bb74d6ddf19d8bfc520cb660561d2d9ce5786ae72f71b5"},
|
||||||
{file = "coverage-5.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:8963a499849a1fc54b35b1c9f162f4108017b2e6db2c46c1bed93a72262ed083"},
|
{file = "coverage-6.3-cp310-cp310-win32.whl", hash = "sha256:27a94db5dc098c25048b0aca155f5fac674f2cf1b1736c5272ba28ead2fc267e"},
|
||||||
{file = "coverage-5.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:869a64f53488f40fa5b5b9dcb9e9b2962a66a87dab37790f3fcfb5144b996ef5"},
|
{file = "coverage-6.3-cp310-cp310-win_amd64.whl", hash = "sha256:bde4aeabc0d1b2e52c4036c54440b1ad05beeca8113f47aceb4998bb7471e2c2"},
|
||||||
{file = "coverage-5.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4a7697d8cb0f27399b0e393c0b90f0f1e40c82023ea4d45d22bce7032a5d7b81"},
|
{file = "coverage-6.3-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:509c68c3e2015022aeda03b003dd68fa19987cdcf64e9d4edc98db41cfc45d30"},
|
||||||
{file = "coverage-5.5-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:8d0a0725ad7c1a0bcd8d1b437e191107d457e2ec1084b9f190630a4fb1af78e6"},
|
{file = "coverage-6.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e4ff163602c5c77e7bb4ea81ba5d3b793b4419f8acd296aae149370902cf4e92"},
|
||||||
{file = "coverage-5.5-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:51cb9476a3987c8967ebab3f0fe144819781fca264f57f89760037a2ea191cb0"},
|
{file = "coverage-6.3-cp311-cp311-win_amd64.whl", hash = "sha256:d1675db48490e5fa0b300f6329ecb8a9a37c29b9ab64fa9c964d34111788ca2d"},
|
||||||
{file = "coverage-5.5-cp310-cp310-win_amd64.whl", hash = "sha256:c0891a6a97b09c1f3e073a890514d5012eb256845c451bd48f7968ef939bf4ae"},
|
{file = "coverage-6.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7eed8459a2b81848cafb3280b39d7d49950d5f98e403677941c752e7e7ee47cb"},
|
||||||
{file = "coverage-5.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:3487286bc29a5aa4b93a072e9592f22254291ce96a9fbc5251f566b6b7343cdb"},
|
{file = "coverage-6.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b4285fde5286b946835a1a53bba3ad41ef74285ba9e8013e14b5ea93deaeafc"},
|
||||||
{file = "coverage-5.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:deee1077aae10d8fa88cb02c845cfba9b62c55e1183f52f6ae6a2df6a2187160"},
|
{file = "coverage-6.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4748349734110fd32d46ff8897b561e6300d8989a494ad5a0a2e4f0ca974fc7"},
|
||||||
{file = "coverage-5.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f11642dddbb0253cc8853254301b51390ba0081750a8ac03f20ea8103f0c56b6"},
|
{file = "coverage-6.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:823f9325283dc9565ba0aa2d240471a93ca8999861779b2b6c7aded45b58ee0f"},
|
||||||
{file = "coverage-5.5-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:6c90e11318f0d3c436a42409f2749ee1a115cd8b067d7f14c148f1ce5574d701"},
|
{file = "coverage-6.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:fff16a30fdf57b214778eff86391301c4509e327a65b877862f7c929f10a4253"},
|
||||||
{file = "coverage-5.5-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:30c77c1dc9f253283e34c27935fded5015f7d1abe83bc7821680ac444eaf7793"},
|
{file = "coverage-6.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:da1a428bdbe71f9a8c270c7baab29e9552ac9d0e0cba5e7e9a4c9ee6465d258d"},
|
||||||
{file = "coverage-5.5-cp35-cp35m-win32.whl", hash = "sha256:9a1ef3b66e38ef8618ce5fdc7bea3d9f45f3624e2a66295eea5e57966c85909e"},
|
{file = "coverage-6.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7d82c610a2e10372e128023c5baf9ce3d270f3029fe7274ff5bc2897c68f1318"},
|
||||||
{file = "coverage-5.5-cp35-cp35m-win_amd64.whl", hash = "sha256:972c85d205b51e30e59525694670de6a8a89691186012535f9d7dbaa230e42c3"},
|
{file = "coverage-6.3-cp37-cp37m-win32.whl", hash = "sha256:11e61c5548ecf74ea1f8b059730b049871f0e32b74f88bd0d670c20c819ad749"},
|
||||||
{file = "coverage-5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:af0e781009aaf59e25c5a678122391cb0f345ac0ec272c7961dc5455e1c40066"},
|
{file = "coverage-6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:8e0c3525b1a182c8ffc9bca7e56b521e0c2b8b3e82f033c8e16d6d721f1b54d6"},
|
||||||
{file = "coverage-5.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:74d881fc777ebb11c63736622b60cb9e4aee5cace591ce274fb69e582a12a61a"},
|
{file = "coverage-6.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a189036c50dcd56100746139a459f0d27540fef95b09aba03e786540b8feaa5f"},
|
||||||
{file = "coverage-5.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:92b017ce34b68a7d67bd6d117e6d443a9bf63a2ecf8567bb3d8c6c7bc5014465"},
|
{file = "coverage-6.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:32168001f33025fd756884d56d01adebb34e6c8c0b3395ca8584cdcee9c7c9d2"},
|
||||||
{file = "coverage-5.5-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d636598c8305e1f90b439dbf4f66437de4a5e3c31fdf47ad29542478c8508bbb"},
|
{file = "coverage-6.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5d79c9af3f410a2b5acad91258b4ae179ee9c83897eb9de69151b179b0227f5"},
|
||||||
{file = "coverage-5.5-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:41179b8a845742d1eb60449bdb2992196e211341818565abded11cfa90efb821"},
|
{file = "coverage-6.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:85c5fc9029043cf8b07f73fbb0a7ab6d3b717510c3b5642b77058ea55d7cacde"},
|
||||||
{file = "coverage-5.5-cp36-cp36m-win32.whl", hash = "sha256:040af6c32813fa3eae5305d53f18875bedd079960822ef8ec067a66dd8afcd45"},
|
{file = "coverage-6.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7596aa2f2b8fa5604129cfc9a27ad9beec0a96f18078cb424d029fdd707468d"},
|
||||||
{file = "coverage-5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:5fec2d43a2cc6965edc0bb9e83e1e4b557f76f843a77a2496cbe719583ce8184"},
|
{file = "coverage-6.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ce443a3e6df90d692c38762f108fc4c88314bf477689f04de76b3f252e7a351c"},
|
||||||
{file = "coverage-5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:18ba8bbede96a2c3dde7b868de9dcbd55670690af0988713f0603f037848418a"},
|
{file = "coverage-6.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:012157499ec4f135fc36cd2177e3d1a1840af9b236cbe80e9a5ccfc83d912a69"},
|
||||||
{file = "coverage-5.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2910f4d36a6a9b4214bb7038d537f015346f413a975d57ca6b43bf23d6563b53"},
|
{file = "coverage-6.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0a34d313105cdd0d3644c56df2d743fe467270d6ab93b5d4a347eb9fec8924d6"},
|
||||||
{file = "coverage-5.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:f0b278ce10936db1a37e6954e15a3730bea96a0997c26d7fee88e6c396c2086d"},
|
{file = "coverage-6.3-cp38-cp38-win32.whl", hash = "sha256:6e78b1e25e5c5695dea012be473e442f7094d066925604be20b30713dbd47f89"},
|
||||||
{file = "coverage-5.5-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:796c9c3c79747146ebd278dbe1e5c5c05dd6b10cc3bcb8389dfdf844f3ead638"},
|
{file = "coverage-6.3-cp38-cp38-win_amd64.whl", hash = "sha256:433b99f7b0613bdcdc0b00cc3d39ed6d756797e3b078d2c43f8a38288520aec6"},
|
||||||
{file = "coverage-5.5-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:53194af30d5bad77fcba80e23a1441c71abfb3e01192034f8246e0d8f99528f3"},
|
{file = "coverage-6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9ed3244b415725f08ca3bdf02ed681089fd95e9465099a21c8e2d9c5d6ca2606"},
|
||||||
{file = "coverage-5.5-cp37-cp37m-win32.whl", hash = "sha256:184a47bbe0aa6400ed2d41d8e9ed868b8205046518c52464fde713ea06e3a74a"},
|
{file = "coverage-6.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab4fc4b866b279740e0d917402f0e9a08683e002f43fa408e9655818ed392196"},
|
||||||
{file = "coverage-5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:2949cad1c5208b8298d5686d5a85b66aae46d73eec2c3e08c817dd3513e5848a"},
|
{file = "coverage-6.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8582e9280f8d0f38114fe95a92ae8d0790b56b099d728cc4f8a2e14b1c4a18c"},
|
||||||
{file = "coverage-5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:217658ec7187497e3f3ebd901afdca1af062b42cfe3e0dafea4cced3983739f6"},
|
{file = "coverage-6.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c72bb4679283c6737f452eeb9b2a0e570acaef2197ad255fb20162adc80bea76"},
|
||||||
{file = "coverage-5.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1aa846f56c3d49205c952d8318e76ccc2ae23303351d9270ab220004c580cfe2"},
|
{file = "coverage-6.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca29c352389ea27a24c79acd117abdd8a865c6eb01576b6f0990cd9a4e9c9f48"},
|
||||||
{file = "coverage-5.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:24d4a7de75446be83244eabbff746d66b9240ae020ced65d060815fac3423759"},
|
{file = "coverage-6.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:152cc2624381df4e4e604e21bd8e95eb8059535f7b768c1fb8b8ae0b26f47ab0"},
|
||||||
{file = "coverage-5.5-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1f8bf7b90ba55699b3a5e44930e93ff0189aa27186e96071fac7dd0d06a1873"},
|
{file = "coverage-6.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:51372e24b1f7143ee2df6b45cff6a721f3abe93b1e506196f3ffa4155c2497f7"},
|
||||||
{file = "coverage-5.5-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:970284a88b99673ccb2e4e334cfb38a10aab7cd44f7457564d11898a74b62d0a"},
|
{file = "coverage-6.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:72d9d186508325a456475dd05b1756f9a204c7086b07fffb227ef8cee03b1dc2"},
|
||||||
{file = "coverage-5.5-cp38-cp38-win32.whl", hash = "sha256:01d84219b5cdbfc8122223b39a954820929497a1cb1422824bb86b07b74594b6"},
|
{file = "coverage-6.3-cp39-cp39-win32.whl", hash = "sha256:649df3641eb351cdfd0d5533c92fc9df507b6b2bf48a7ef8c71ab63cbc7b5c3c"},
|
||||||
{file = "coverage-5.5-cp38-cp38-win_amd64.whl", hash = "sha256:2e0d881ad471768bf6e6c2bf905d183543f10098e3b3640fc029509530091502"},
|
{file = "coverage-6.3-cp39-cp39-win_amd64.whl", hash = "sha256:e67ccd53da5958ea1ec833a160b96357f90859c220a00150de011b787c27b98d"},
|
||||||
{file = "coverage-5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d1f9ce122f83b2305592c11d64f181b87153fc2c2bbd3bb4a3dde8303cfb1a6b"},
|
{file = "coverage-6.3-pp36.pp37.pp38-none-any.whl", hash = "sha256:27ac7cb84538e278e07569ceaaa6f807a029dc194b1c819a9820b9bb5dbf63ab"},
|
||||||
{file = "coverage-5.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:13c4ee887eca0f4c5a247b75398d4114c37882658300e153113dafb1d76de529"},
|
{file = "coverage-6.3.tar.gz", hash = "sha256:987a84ff98a309994ca77ed3cc4b92424f824278e48e4bf7d1bb79a63cfe2099"},
|
||||||
{file = "coverage-5.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:52596d3d0e8bdf3af43db3e9ba8dcdaac724ba7b5ca3f6358529d56f7a166f8b"},
|
|
||||||
{file = "coverage-5.5-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2cafbbb3af0733db200c9b5f798d18953b1a304d3f86a938367de1567f4b5bff"},
|
|
||||||
{file = "coverage-5.5-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:44d654437b8ddd9eee7d1eaee28b7219bec228520ff809af170488fd2fed3e2b"},
|
|
||||||
{file = "coverage-5.5-cp39-cp39-win32.whl", hash = "sha256:d314ed732c25d29775e84a960c3c60808b682c08d86602ec2c3008e1202e3bb6"},
|
|
||||||
{file = "coverage-5.5-cp39-cp39-win_amd64.whl", hash = "sha256:13034c4409db851670bc9acd836243aeee299949bd5673e11844befcb0149f03"},
|
|
||||||
{file = "coverage-5.5-pp36-none-any.whl", hash = "sha256:f030f8873312a16414c0d8e1a1ddff2d3235655a2174e3648b4fa66b3f2f1079"},
|
|
||||||
{file = "coverage-5.5-pp37-none-any.whl", hash = "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4"},
|
|
||||||
{file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"},
|
|
||||||
]
|
]
|
||||||
distlib = [
|
distlib = [
|
||||||
{file = "distlib-0.3.2-py2.py3-none-any.whl", hash = "sha256:23e223426b28491b1ced97dc3bbe183027419dfc7982b4fa2f05d5f3ff10711c"},
|
{file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"},
|
||||||
{file = "distlib-0.3.2.zip", hash = "sha256:106fef6dc37dd8c0e2c0a60d3fca3e77460a48907f335fa28420463a6f799736"},
|
{file = "distlib-0.3.4.zip", hash = "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"},
|
||||||
]
|
]
|
||||||
filelock = [
|
filelock = [
|
||||||
{file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"},
|
{file = "filelock-3.4.2-py3-none-any.whl", hash = "sha256:cf0fc6a2f8d26bd900f19bf33915ca70ba4dd8c56903eeb14e1e7a2fd7590146"},
|
||||||
{file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"},
|
{file = "filelock-3.4.2.tar.gz", hash = "sha256:38b4f4c989f9d06d44524df1b24bd19e167d851f19b50bf3e3559952dddc5b80"},
|
||||||
]
|
]
|
||||||
ghp-import = [
|
ghp-import = [
|
||||||
{file = "ghp-import-2.0.1.tar.gz", hash = "sha256:753de2eace6e0f7d4edfb3cce5e3c3b98cd52aadb80163303d1d036bda7b4483"},
|
{file = "ghp-import-2.0.2.tar.gz", hash = "sha256:947b3771f11be850c852c64b561c600fdddf794bab363060854c1ee7ad05e071"},
|
||||||
|
{file = "ghp_import-2.0.2-py3-none-any.whl", hash = "sha256:5f8962b30b20652cdffa9c5a9812f7de6bcb56ec475acac579807719bf242c46"},
|
||||||
]
|
]
|
||||||
identify = [
|
identify = [
|
||||||
{file = "identify-2.2.13-py2.py3-none-any.whl", hash = "sha256:7199679b5be13a6b40e6e19ea473e789b11b4e3b60986499b1f589ffb03c217c"},
|
{file = "identify-2.4.6-py2.py3-none-any.whl", hash = "sha256:cf06b1639e0dca0c184b1504d8b73448c99a68e004a80524c7923b95f7b6837c"},
|
||||||
{file = "identify-2.2.13.tar.gz", hash = "sha256:7bc6e829392bd017236531963d2d937d66fc27cadc643ac0aba2ce9f26157c79"},
|
{file = "identify-2.4.6.tar.gz", hash = "sha256:233679e3f61a02015d4293dbccf16aa0e4996f868bd114688b8c124f18826706"},
|
||||||
]
|
]
|
||||||
importlib-metadata = [
|
importlib-metadata = [
|
||||||
{file = "importlib_metadata-4.6.4-py3-none-any.whl", hash = "sha256:ed5157fef23a4bc4594615a0dd8eba94b2bb36bf2a343fa3d8bb2fa0a62a99d5"},
|
{file = "importlib_metadata-4.10.1-py3-none-any.whl", hash = "sha256:899e2a40a8c4a1aec681feef45733de8a6c58f3f6a0dbed2eb6574b4387a77b6"},
|
||||||
{file = "importlib_metadata-4.6.4.tar.gz", hash = "sha256:7b30a78db2922d78a6f47fb30683156a14f3c6aa5cc23f77cc8967e9ab2d002f"},
|
{file = "importlib_metadata-4.10.1.tar.gz", hash = "sha256:951f0d8a5b7260e9db5e41d429285b5f451e928479f19d80818878527d36e95e"},
|
||||||
]
|
]
|
||||||
iniconfig = [
|
iniconfig = [
|
||||||
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
|
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
|
||||||
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
|
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
|
||||||
]
|
]
|
||||||
jinja2 = [
|
jinja2 = [
|
||||||
{file = "Jinja2-3.0.1-py3-none-any.whl", hash = "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4"},
|
{file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"},
|
||||||
{file = "Jinja2-3.0.1.tar.gz", hash = "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"},
|
{file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"},
|
||||||
]
|
]
|
||||||
markdown = [
|
markdown = [
|
||||||
{file = "Markdown-3.3.4-py3-none-any.whl", hash = "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c"},
|
{file = "Markdown-3.3.6-py3-none-any.whl", hash = "sha256:9923332318f843411e9932237530df53162e29dc7a4e2b91e35764583c46c9a3"},
|
||||||
{file = "Markdown-3.3.4.tar.gz", hash = "sha256:31b5b491868dcc87d6c24b7e3d19a0d730d59d3e46f4eea6430a321bed387a49"},
|
{file = "Markdown-3.3.6.tar.gz", hash = "sha256:76df8ae32294ec39dcf89340382882dfa12975f87f45c3ed1ecdb1e8cefc7006"},
|
||||||
]
|
]
|
||||||
markupsafe = [
|
markupsafe = [
|
||||||
{file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"},
|
{file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"},
|
||||||
@@ -814,12 +792,12 @@ mkdocs-autorefs = [
|
|||||||
{file = "mkdocs_autorefs-0.2.1-py3-none-any.whl", hash = "sha256:f301b983a34259df90b3fcf7edc234b5e6c7065bd578781e66fd90b8cfbe76be"},
|
{file = "mkdocs_autorefs-0.2.1-py3-none-any.whl", hash = "sha256:f301b983a34259df90b3fcf7edc234b5e6c7065bd578781e66fd90b8cfbe76be"},
|
||||||
]
|
]
|
||||||
mkdocs-material = [
|
mkdocs-material = [
|
||||||
{file = "mkdocs-material-7.2.5.tar.gz", hash = "sha256:e2a3aa5e20fbdb260d22ec56c01247896c6ae743702e1cd9023fd149a4ae9890"},
|
{file = "mkdocs-material-7.3.0.tar.gz", hash = "sha256:07db0580fa96c3473aee99ec3fb4606a1a5a1e4f4467e64c0cd1ba8da5b6476e"},
|
||||||
{file = "mkdocs_material-7.2.5-py2.py3-none-any.whl", hash = "sha256:332bafc1584d2d229aa05f7894b4b0f62055fc0d05c96e6ef1785c86ef6e8f91"},
|
{file = "mkdocs_material-7.3.0-py2.py3-none-any.whl", hash = "sha256:b183c27dc0f44e631bbc32c51057f61a3e2ba8b3c1080e59f944167eeba9ff1d"},
|
||||||
]
|
]
|
||||||
mkdocs-material-extensions = [
|
mkdocs-material-extensions = [
|
||||||
{file = "mkdocs-material-extensions-1.0.1.tar.gz", hash = "sha256:6947fb7f5e4291e3c61405bad3539d81e0b3cd62ae0d66ced018128af509c68f"},
|
{file = "mkdocs-material-extensions-1.0.3.tar.gz", hash = "sha256:bfd24dfdef7b41c312ede42648f9eb83476ea168ec163b613f9abd12bbfddba2"},
|
||||||
{file = "mkdocs_material_extensions-1.0.1-py3-none-any.whl", hash = "sha256:d90c807a88348aa6d1805657ec5c0b2d8d609c110e62b9dce4daf7fa981fa338"},
|
{file = "mkdocs_material_extensions-1.0.3-py3-none-any.whl", hash = "sha256:a82b70e533ce060b2a5d9eb2bc2e1be201cf61f901f93704b4acf6e3d5983a44"},
|
||||||
]
|
]
|
||||||
mkdocstrings = [
|
mkdocstrings = [
|
||||||
{file = "mkdocstrings-0.15.2-py3-none-any.whl", hash = "sha256:8d6cbe64c07ae66739010979ca01d49dd2f64d1a45009f089d217b9cd2a65e36"},
|
{file = "mkdocstrings-0.15.2-py3-none-any.whl", hash = "sha256:8d6cbe64c07ae66739010979ca01d49dd2f64d1a45009f089d217b9cd2a65e36"},
|
||||||
@@ -859,44 +837,44 @@ nodeenv = [
|
|||||||
{file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"},
|
{file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"},
|
||||||
]
|
]
|
||||||
packaging = [
|
packaging = [
|
||||||
{file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"},
|
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
|
||||||
{file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"},
|
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
|
||||||
]
|
]
|
||||||
pathspec = [
|
pathspec = [
|
||||||
{file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"},
|
{file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"},
|
||||||
{file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
|
{file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
|
||||||
]
|
]
|
||||||
platformdirs = [
|
platformdirs = [
|
||||||
{file = "platformdirs-2.2.0-py3-none-any.whl", hash = "sha256:4666d822218db6a262bdfdc9c39d21f23b4cfdb08af331a81e92751daf6c866c"},
|
{file = "platformdirs-2.4.1-py3-none-any.whl", hash = "sha256:1d7385c7db91728b83efd0ca99a5afb296cab9d0ed8313a45ed8ba17967ecfca"},
|
||||||
{file = "platformdirs-2.2.0.tar.gz", hash = "sha256:632daad3ab546bd8e6af0537d09805cec458dce201bccfe23012df73332e181e"},
|
{file = "platformdirs-2.4.1.tar.gz", hash = "sha256:440633ddfebcc36264232365d7840a970e75e1018d15b4327d11f91909045fda"},
|
||||||
]
|
]
|
||||||
pluggy = [
|
pluggy = [
|
||||||
{file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
|
{file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
|
||||||
{file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
|
{file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
|
||||||
]
|
]
|
||||||
pre-commit = [
|
pre-commit = [
|
||||||
{file = "pre_commit-2.14.0-py2.py3-none-any.whl", hash = "sha256:ec3045ae62e1aa2eecfb8e86fa3025c2e3698f77394ef8d2011ce0aedd85b2d4"},
|
{file = "pre_commit-2.17.0-py2.py3-none-any.whl", hash = "sha256:725fa7459782d7bec5ead072810e47351de01709be838c2ce1726b9591dad616"},
|
||||||
{file = "pre_commit-2.14.0.tar.gz", hash = "sha256:2386eeb4cf6633712c7cc9ede83684d53c8cafca6b59f79c738098b51c6d206c"},
|
{file = "pre_commit-2.17.0.tar.gz", hash = "sha256:c1a8040ff15ad3d648c70cc3e55b93e4d2d5b687320955505587fd79bbaed06a"},
|
||||||
]
|
]
|
||||||
py = [
|
py = [
|
||||||
{file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"},
|
{file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
|
||||||
{file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"},
|
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
|
||||||
]
|
]
|
||||||
pygments = [
|
pygments = [
|
||||||
{file = "Pygments-2.10.0-py3-none-any.whl", hash = "sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380"},
|
{file = "Pygments-2.11.2-py3-none-any.whl", hash = "sha256:44238f1b60a76d78fc8ca0528ee429702aae011c265fe6a8dd8b63049ae41c65"},
|
||||||
{file = "Pygments-2.10.0.tar.gz", hash = "sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6"},
|
{file = "Pygments-2.11.2.tar.gz", hash = "sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a"},
|
||||||
]
|
]
|
||||||
pymdown-extensions = [
|
pymdown-extensions = [
|
||||||
{file = "pymdown-extensions-8.2.tar.gz", hash = "sha256:b6daa94aad9e1310f9c64c8b1f01e4ce82937ab7eb53bfc92876a97aca02a6f4"},
|
{file = "pymdown-extensions-8.2.tar.gz", hash = "sha256:b6daa94aad9e1310f9c64c8b1f01e4ce82937ab7eb53bfc92876a97aca02a6f4"},
|
||||||
{file = "pymdown_extensions-8.2-py3-none-any.whl", hash = "sha256:141452d8ed61165518f2c923454bf054866b85cf466feedb0eb68f04acdc2560"},
|
{file = "pymdown_extensions-8.2-py3-none-any.whl", hash = "sha256:141452d8ed61165518f2c923454bf054866b85cf466feedb0eb68f04acdc2560"},
|
||||||
]
|
]
|
||||||
pyparsing = [
|
pyparsing = [
|
||||||
{file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
|
{file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"},
|
||||||
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
|
{file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"},
|
||||||
]
|
]
|
||||||
pytest = [
|
pytest = [
|
||||||
{file = "pytest-6.2.4-py3-none-any.whl", hash = "sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890"},
|
{file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"},
|
||||||
{file = "pytest-6.2.4.tar.gz", hash = "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b"},
|
{file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"},
|
||||||
]
|
]
|
||||||
pytest-cov = [
|
pytest-cov = [
|
||||||
{file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"},
|
{file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"},
|
||||||
@@ -911,43 +889,47 @@ pytkdocs = [
|
|||||||
{file = "pytkdocs-0.11.1.tar.gz", hash = "sha256:1ec7e028fe8361acc1ce909ada4e6beabec28ef31e629618549109e1d58549f0"},
|
{file = "pytkdocs-0.11.1.tar.gz", hash = "sha256:1ec7e028fe8361acc1ce909ada4e6beabec28ef31e629618549109e1d58549f0"},
|
||||||
]
|
]
|
||||||
pyyaml = [
|
pyyaml = [
|
||||||
{file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"},
|
{file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
|
||||||
{file = "PyYAML-5.4.1-cp27-cp27m-win32.whl", hash = "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393"},
|
{file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"},
|
||||||
{file = "PyYAML-5.4.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8"},
|
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"},
|
||||||
{file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"},
|
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"},
|
||||||
{file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"},
|
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"},
|
||||||
{file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"},
|
{file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"},
|
||||||
{file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347"},
|
{file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"},
|
||||||
{file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541"},
|
{file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"},
|
||||||
{file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"},
|
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"},
|
||||||
{file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"},
|
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"},
|
||||||
{file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"},
|
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"},
|
||||||
{file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"},
|
{file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"},
|
||||||
{file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa"},
|
{file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"},
|
||||||
{file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"},
|
{file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"},
|
||||||
{file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"},
|
{file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"},
|
||||||
{file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"},
|
{file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"},
|
||||||
{file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"},
|
{file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"},
|
||||||
{file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"},
|
{file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"},
|
||||||
{file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247"},
|
{file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"},
|
||||||
{file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc"},
|
{file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"},
|
||||||
{file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"},
|
{file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"},
|
||||||
{file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"},
|
{file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"},
|
||||||
{file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"},
|
{file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"},
|
||||||
{file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"},
|
{file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"},
|
||||||
{file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122"},
|
{file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"},
|
||||||
{file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6"},
|
{file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"},
|
||||||
{file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"},
|
{file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"},
|
||||||
{file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"},
|
{file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"},
|
||||||
{file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"},
|
{file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"},
|
||||||
|
{file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"},
|
||||||
|
{file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"},
|
||||||
|
{file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"},
|
||||||
|
{file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
|
||||||
]
|
]
|
||||||
pyyaml-env-tag = [
|
pyyaml-env-tag = [
|
||||||
{file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"},
|
{file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"},
|
||||||
{file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"},
|
{file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"},
|
||||||
]
|
]
|
||||||
rich = [
|
rich = [
|
||||||
{file = "rich-10.16.1-py3-none-any.whl", hash = "sha256:bbe04dd6ac09e4b00d22cb1051aa127beaf6e16c3d8687b026e96d3fca6aad52"},
|
{file = "rich-11.1.0-py3-none-any.whl", hash = "sha256:365ebcdbfb3aa8d4b0ed2490e0fbf7b886a39d14eb7ea5fb7aece950835e1eed"},
|
||||||
{file = "rich-10.16.1.tar.gz", hash = "sha256:4949e73de321784ef6664ebbc854ac82b20ff60b2865097b93f3b9b41e30da27"},
|
{file = "rich-11.1.0.tar.gz", hash = "sha256:43e03d8eec12e21beaecc22c828a41c4247356414a12d5879834863d4ad53816"},
|
||||||
]
|
]
|
||||||
six = [
|
six = [
|
||||||
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
||||||
@@ -999,35 +981,35 @@ typing-extensions = [
|
|||||||
{file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"},
|
{file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"},
|
||||||
]
|
]
|
||||||
virtualenv = [
|
virtualenv = [
|
||||||
{file = "virtualenv-20.7.2-py2.py3-none-any.whl", hash = "sha256:e4670891b3a03eb071748c569a87cceaefbf643c5bac46d996c5a45c34aa0f06"},
|
{file = "virtualenv-20.13.0-py2.py3-none-any.whl", hash = "sha256:339f16c4a86b44240ba7223d0f93a7887c3ca04b5f9c8129da7958447d079b09"},
|
||||||
{file = "virtualenv-20.7.2.tar.gz", hash = "sha256:9ef4e8ee4710826e98ff3075c9a4739e2cb1040de6a2a8d35db0055840dc96a0"},
|
{file = "virtualenv-20.13.0.tar.gz", hash = "sha256:d8458cf8d59d0ea495ad9b34c2599487f8a7772d796f9910858376d1600dd2dd"},
|
||||||
]
|
]
|
||||||
watchdog = [
|
watchdog = [
|
||||||
{file = "watchdog-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5f57ce4f7e498278fb2a091f39359930144a0f2f90ea8cbf4523c4e25de34028"},
|
{file = "watchdog-2.1.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9693f35162dc6208d10b10ddf0458cc09ad70c30ba689d9206e02cd836ce28a3"},
|
||||||
{file = "watchdog-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8b74d0d92a69a7ab5f101f9fe74e44ba017be269efa824337366ccbb4effde85"},
|
{file = "watchdog-2.1.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:aba5c812f8ee8a3ff3be51887ca2d55fb8e268439ed44110d3846e4229eb0e8b"},
|
||||||
{file = "watchdog-2.1.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:59767f476cd1f48531bf378f0300565d879688c82da8369ca8c52f633299523c"},
|
{file = "watchdog-2.1.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4ae38bf8ba6f39d5b83f78661273216e7db5b00f08be7592062cb1fc8b8ba542"},
|
||||||
{file = "watchdog-2.1.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:814d396859c95598f7576d15bc257c3bd3ba61fa4bc1db7dfc18f09070ded7da"},
|
{file = "watchdog-2.1.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ad6f1796e37db2223d2a3f302f586f74c72c630b48a9872c1e7ae8e92e0ab669"},
|
||||||
{file = "watchdog-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:28777dbed3bbd95f9c70f461443990a36c07dbf49ae7cd69932cdd1b8fb2850c"},
|
{file = "watchdog-2.1.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:922a69fa533cb0c793b483becaaa0845f655151e7256ec73630a1b2e9ebcb660"},
|
||||||
{file = "watchdog-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5cf78f794c9d7bc64a626ef4f71aff88f57a7ae288e0b359a9c6ea711a41395f"},
|
{file = "watchdog-2.1.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b2fcf9402fde2672545b139694284dc3b665fd1be660d73eca6805197ef776a3"},
|
||||||
{file = "watchdog-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:43bf728eb7830559f329864ab5da2302c15b2efbac24ad84ccc09949ba753c40"},
|
{file = "watchdog-2.1.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3386b367e950a11b0568062b70cc026c6f645428a698d33d39e013aaeda4cc04"},
|
||||||
{file = "watchdog-2.1.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a7053d4d22dc95c5e0c90aeeae1e4ed5269d2f04001798eec43a654a03008d22"},
|
{file = "watchdog-2.1.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8f1c00aa35f504197561060ca4c21d3cc079ba29cf6dd2fe61024c70160c990b"},
|
||||||
{file = "watchdog-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6f3ad1d973fe8fc8fe64ba38f6a934b74346342fa98ef08ad5da361a05d46044"},
|
{file = "watchdog-2.1.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b52b88021b9541a60531142b0a451baca08d28b74a723d0c99b13c8c8d48d604"},
|
||||||
{file = "watchdog-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:41d44ef21a77a32b55ce9bf59b75777063751f688de51098859b7c7f6466589a"},
|
{file = "watchdog-2.1.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8047da932432aa32c515ec1447ea79ce578d0559362ca3605f8e9568f844e3c6"},
|
||||||
{file = "watchdog-2.1.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ed4ca4351cd2bb0d863ee737a2011ca44d8d8be19b43509bd4507f8a449b376b"},
|
{file = "watchdog-2.1.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e92c2d33858c8f560671b448205a268096e17870dcf60a9bb3ac7bfbafb7f5f9"},
|
||||||
{file = "watchdog-2.1.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8874d5ad6b7f43b18935d9b0183e29727a623a216693d6938d07dfd411ba462f"},
|
{file = "watchdog-2.1.6-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b7d336912853d7b77f9b2c24eeed6a5065d0a0cc0d3b6a5a45ad6d1d05fb8cd8"},
|
||||||
{file = "watchdog-2.1.5-py3-none-manylinux2014_aarch64.whl", hash = "sha256:50a7f81f99d238f72185f481b493f9de80096e046935b60ea78e1276f3d76960"},
|
{file = "watchdog-2.1.6-py3-none-manylinux2014_aarch64.whl", hash = "sha256:cca7741c0fcc765568350cb139e92b7f9f3c9a08c4f32591d18ab0a6ac9e71b6"},
|
||||||
{file = "watchdog-2.1.5-py3-none-manylinux2014_armv7l.whl", hash = "sha256:e40e33a4889382824846b4baa05634e1365b47c6fa40071dc2d06b4d7c715fc1"},
|
{file = "watchdog-2.1.6-py3-none-manylinux2014_armv7l.whl", hash = "sha256:25fb5240b195d17de949588628fdf93032ebf163524ef08933db0ea1f99bd685"},
|
||||||
{file = "watchdog-2.1.5-py3-none-manylinux2014_i686.whl", hash = "sha256:78b1514067ff4089f4dac930b043a142997a5b98553120919005e97fbaba6546"},
|
{file = "watchdog-2.1.6-py3-none-manylinux2014_i686.whl", hash = "sha256:be9be735f827820a06340dff2ddea1fb7234561fa5e6300a62fe7f54d40546a0"},
|
||||||
{file = "watchdog-2.1.5-py3-none-manylinux2014_ppc64.whl", hash = "sha256:58ae842300cbfe5e62fb068c83901abe76e4f413234b7bec5446e4275eb1f9cb"},
|
{file = "watchdog-2.1.6-py3-none-manylinux2014_ppc64.whl", hash = "sha256:d0d19fb2441947b58fbf91336638c2b9f4cc98e05e1045404d7a4cb7cddc7a65"},
|
||||||
{file = "watchdog-2.1.5-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:b0cc7d8b7d60da6c313779d85903ce39a63d89d866014b085f720a083d5f3e9a"},
|
{file = "watchdog-2.1.6-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:3becdb380d8916c873ad512f1701f8a92ce79ec6978ffde92919fd18d41da7fb"},
|
||||||
{file = "watchdog-2.1.5-py3-none-manylinux2014_s390x.whl", hash = "sha256:e60d3bb7166b7cb830b86938d1eb0e6cfe23dfd634cce05c128f8f9967895193"},
|
{file = "watchdog-2.1.6-py3-none-manylinux2014_s390x.whl", hash = "sha256:ae67501c95606072aafa865b6ed47343ac6484472a2f95490ba151f6347acfc2"},
|
||||||
{file = "watchdog-2.1.5-py3-none-manylinux2014_x86_64.whl", hash = "sha256:51af09ae937ada0e9a10cc16988ec03c649754a91526170b6839b89fc56d6acb"},
|
{file = "watchdog-2.1.6-py3-none-manylinux2014_x86_64.whl", hash = "sha256:e0f30db709c939cabf64a6dc5babb276e6d823fd84464ab916f9b9ba5623ca15"},
|
||||||
{file = "watchdog-2.1.5-py3-none-win32.whl", hash = "sha256:9391003635aa783957b9b11175d9802d3272ed67e69ef2e3394c0b6d9d24fa9a"},
|
{file = "watchdog-2.1.6-py3-none-win32.whl", hash = "sha256:e02794ac791662a5eafc6ffeaf9bcc149035a0e48eb0a9d40a8feb4622605a3d"},
|
||||||
{file = "watchdog-2.1.5-py3-none-win_amd64.whl", hash = "sha256:eab14adfc417c2c983fbcb2c73ef3f28ba6990d1fff45d1180bf7e38bda0d98d"},
|
{file = "watchdog-2.1.6-py3-none-win_amd64.whl", hash = "sha256:bd9ba4f332cf57b2c1f698be0728c020399ef3040577cde2939f2e045b39c1e5"},
|
||||||
{file = "watchdog-2.1.5-py3-none-win_ia64.whl", hash = "sha256:a2888a788893c4ef7e562861ec5433875b7915f930a5a7ed3d32c048158f1be5"},
|
{file = "watchdog-2.1.6-py3-none-win_ia64.whl", hash = "sha256:a0f1c7edf116a12f7245be06120b1852275f9506a7d90227648b250755a03923"},
|
||||||
{file = "watchdog-2.1.5.tar.gz", hash = "sha256:5563b005907613430ef3d4aaac9c78600dd5704e84764cb6deda4b3d72807f09"},
|
{file = "watchdog-2.1.6.tar.gz", hash = "sha256:a36e75df6c767cbf46f61a91c70b3ba71811dfa0aca4a324d9407a06a8b7a2e7"},
|
||||||
]
|
]
|
||||||
zipp = [
|
zipp = [
|
||||||
{file = "zipp-3.5.0-py3-none-any.whl", hash = "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3"},
|
{file = "zipp-3.7.0-py3-none-any.whl", hash = "sha256:b47250dd24f92b7dd6a0a8fc5244da14608f3ca90a5efcd37a3b1642fac9a375"},
|
||||||
{file = "zipp-3.5.0.tar.gz", hash = "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4"},
|
{file = "zipp-3.7.0.tar.gz", hash = "sha256:9f50f446828eb9d45b267433fd3e9da8d801f614129124863f9c51ebceafb87d"},
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "textual"
|
name = "textual"
|
||||||
version = "0.1.13"
|
version = "0.1.15"
|
||||||
homepage = "https://github.com/willmcgugan/textual"
|
homepage = "https://github.com/willmcgugan/textual"
|
||||||
description = "Text User Interface using Rich"
|
description = "Text User Interface using Rich"
|
||||||
authors = ["Will McGugan <willmcgugan@gmail.com>"]
|
authors = ["Will McGugan <willmcgugan@gmail.com>"]
|
||||||
@@ -19,7 +19,8 @@ classifiers = [
|
|||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.7"
|
python = "^3.7"
|
||||||
rich = "^10.12.0"
|
rich = "^11.0.0"
|
||||||
|
|
||||||
#rich = {git = "git@github.com:willmcgugan/rich", rev = "link-id"}
|
#rich = {git = "git@github.com:willmcgugan/rich", rev = "link-id"}
|
||||||
typing-extensions = { version = "^3.10.0", python = "<3.8" }
|
typing-extensions = { version = "^3.10.0", python = "<3.8" }
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Literal
|
||||||
|
|
||||||
from rich.console import Console, ConsoleOptions, RenderResult, RenderableType
|
from rich.console import Console, ConsoleOptions, RenderResult, RenderableType
|
||||||
from rich.segment import Segment
|
from rich.segment import Segment
|
||||||
|
|
||||||
@@ -14,6 +16,8 @@ BOX_STYLES: dict[str, tuple[str, str, str]] = {
|
|||||||
"outer": ("▛▀▜", "▌ ▐", "▙▄▟"),
|
"outer": ("▛▀▜", "▌ ▐", "▙▄▟"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BoxType = Literal["", "rounded", "solid", "double", "dashed", "heavy", "inner", "outer"]
|
||||||
|
|
||||||
|
|
||||||
class Box:
|
class Box:
|
||||||
def __init__(
|
def __init__(
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import platform
|
||||||
import warnings
|
import warnings
|
||||||
from typing import Any, Callable, Iterable, Type, TypeVar
|
from typing import Any, Callable, Iterable, Type, TypeVar
|
||||||
|
|
||||||
@@ -21,7 +21,6 @@ from ._animator import Animator
|
|||||||
from ._callback import invoke
|
from ._callback import invoke
|
||||||
from ._context import active_app
|
from ._context import active_app
|
||||||
from ._event_broker import extract_handler_actions, NoHandler
|
from ._event_broker import extract_handler_actions, NoHandler
|
||||||
from ._linux_driver import LinuxDriver
|
|
||||||
from ._profile import timer
|
from ._profile import timer
|
||||||
from .binding import Bindings, NoBinding
|
from .binding import Bindings, NoBinding
|
||||||
from .css.stylesheet import Stylesheet, StylesheetParseError, StylesheetError
|
from .css.stylesheet import Stylesheet, StylesheetParseError, StylesheetError
|
||||||
@@ -36,6 +35,9 @@ from .view import View
|
|||||||
from .views import DockView
|
from .views import DockView
|
||||||
from .widget import Widget
|
from .widget import Widget
|
||||||
|
|
||||||
|
PLATFORM = platform.system()
|
||||||
|
WINDOWS = PLATFORM == "Windows"
|
||||||
|
|
||||||
# asyncio will warn against resources not being cleared
|
# asyncio will warn against resources not being cleared
|
||||||
warnings.simplefilter("always", ResourceWarning)
|
warnings.simplefilter("always", ResourceWarning)
|
||||||
|
|
||||||
@@ -67,7 +69,6 @@ class App(DOMNode):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
console: Console | None = None,
|
|
||||||
screen: bool = True,
|
screen: bool = True,
|
||||||
driver_class: Type[Driver] | None = None,
|
driver_class: Type[Driver] | None = None,
|
||||||
log: str = "",
|
log: str = "",
|
||||||
@@ -85,10 +86,10 @@ class App(DOMNode):
|
|||||||
driver_class (Type[Driver], optional): Driver class, or None to use default. Defaults to None.
|
driver_class (Type[Driver], optional): Driver class, or None to use default. Defaults to None.
|
||||||
title (str, optional): Title of the application. Defaults to "Textual Application".
|
title (str, optional): Title of the application. Defaults to "Textual Application".
|
||||||
"""
|
"""
|
||||||
self.console = console or Console()
|
self.console = Console()
|
||||||
self.error_console = Console(stderr=True)
|
self.error_console = Console(stderr=True)
|
||||||
self._screen = screen
|
self._screen = screen
|
||||||
self.driver_class = driver_class or LinuxDriver
|
self.driver_class = driver_class or self.get_driver_class()
|
||||||
self._title = title
|
self._title = title
|
||||||
self._view_stack: list[View] = []
|
self._view_stack: list[View] = []
|
||||||
|
|
||||||
@@ -131,6 +132,24 @@ class App(DOMNode):
|
|||||||
sub_title: Reactive[str] = Reactive("")
|
sub_title: Reactive[str] = Reactive("")
|
||||||
background: Reactive[str] = Reactive("black")
|
background: Reactive[str] = Reactive("black")
|
||||||
|
|
||||||
|
def get_driver_class(self) -> Type[Driver]:
|
||||||
|
"""Get a driver class for this platform.
|
||||||
|
|
||||||
|
Called by the constructor.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Driver: A Driver class which manages input and display.
|
||||||
|
"""
|
||||||
|
if WINDOWS:
|
||||||
|
from .drivers.windows_driver import WindowsDriver
|
||||||
|
|
||||||
|
driver_class = WindowsDriver
|
||||||
|
else:
|
||||||
|
from .drivers.linux_driver import LinuxDriver
|
||||||
|
|
||||||
|
driver_class = LinuxDriver
|
||||||
|
return driver_class
|
||||||
|
|
||||||
def __rich_repr__(self) -> rich.repr.Result:
|
def __rich_repr__(self) -> rich.repr.Result:
|
||||||
yield "title", self.title
|
yield "title", self.title
|
||||||
|
|
||||||
@@ -211,7 +230,7 @@ class App(DOMNode):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
async def run_app() -> None:
|
async def run_app() -> None:
|
||||||
app = cls(console=console, screen=screen, driver_class=driver, **kwargs)
|
app = cls(screen=screen, driver_class=driver, **kwargs)
|
||||||
await app.process_messages()
|
await app.process_messages()
|
||||||
|
|
||||||
asyncio.run(run_app())
|
asyncio.run(run_app())
|
||||||
@@ -359,6 +378,7 @@ class App(DOMNode):
|
|||||||
mount_event = events.Mount(sender=self)
|
mount_event = events.Mount(sender=self)
|
||||||
await self.dispatch_message(mount_event)
|
await self.dispatch_message(mount_event)
|
||||||
|
|
||||||
|
self.console = Console()
|
||||||
self.title = self._title
|
self.title = self._title
|
||||||
self.refresh()
|
self.refresh()
|
||||||
await self.animator.start()
|
await self.animator.start()
|
||||||
@@ -432,7 +452,9 @@ class App(DOMNode):
|
|||||||
await self.close_messages()
|
await self.close_messages()
|
||||||
|
|
||||||
def refresh(self) -> None:
|
def refresh(self) -> None:
|
||||||
sync_available = os.environ.get("TERM_PROGRAM", "") != "Apple_Terminal"
|
sync_available = (
|
||||||
|
os.environ.get("TERM_PROGRAM", "") != "Apple_Terminal" and not WINDOWS
|
||||||
|
)
|
||||||
if not self._closed:
|
if not self._closed:
|
||||||
console = self.console
|
console = self.console
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
Style properties are descriptors which allow the Styles object to accept different types when
|
Style properties are descriptors which allow the ``Styles`` object to accept different types when
|
||||||
setting attributes. This gives the developer more freedom in how to express style information.
|
setting attributes. This gives the developer more freedom in how to express style information.
|
||||||
|
|
||||||
Descriptors also play nicely with Mypy, which is aware that attributes can have different types
|
Descriptors also play nicely with Mypy, which is aware that attributes can have different types
|
||||||
@@ -33,10 +33,13 @@ if TYPE_CHECKING:
|
|||||||
from ..layout import Layout
|
from ..layout import Layout
|
||||||
from .styles import Styles
|
from .styles import Styles
|
||||||
from .styles import DockGroup
|
from .styles import DockGroup
|
||||||
|
from .._box import BoxType
|
||||||
from ..layouts.factory import LayoutName
|
from ..layouts.factory import LayoutName
|
||||||
|
|
||||||
|
|
||||||
class ScalarProperty:
|
class ScalarProperty:
|
||||||
|
"""Descriptor for getting and setting scalar properties. Scalars are numeric values with a unit, e.g. "50vh"."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, units: set[Unit] | None = None, percent_unit: Unit = Unit.WIDTH
|
self, units: set[Unit] | None = None, percent_unit: Unit = Unit.WIDTH
|
||||||
) -> None:
|
) -> None:
|
||||||
@@ -51,12 +54,34 @@ class ScalarProperty:
|
|||||||
def __get__(
|
def __get__(
|
||||||
self, obj: Styles, objtype: type[Styles] | None = None
|
self, obj: Styles, objtype: type[Styles] | None = None
|
||||||
) -> Scalar | None:
|
) -> Scalar | None:
|
||||||
|
"""Get the scalar property
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object
|
||||||
|
objtype (type[Styles]): The ``Styles`` class
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The Scalar object or ``None`` if it's not set.
|
||||||
|
"""
|
||||||
value = getattr(obj, self.internal_name)
|
value = getattr(obj, self.internal_name)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def __set__(
|
def __set__(self, obj: Styles, value: float | Scalar | str | None) -> None:
|
||||||
self, obj: Styles, value: float | Scalar | str | None
|
"""Set the scalar property
|
||||||
) -> float | Scalar | str | None:
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object.
|
||||||
|
value (float | Scalar | str | None): The value to set the scalar property to.
|
||||||
|
You can directly pass a float value, which will be interpreted with
|
||||||
|
a default unit of Cells. You may also provide a string such as ``"50%"``,
|
||||||
|
as you might do when writing CSS. If a string with no units is supplied,
|
||||||
|
Cells will be used as the unit. Alternatively, you can directly supply
|
||||||
|
a ``Scalar`` object.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
StyleValueError: If the value is of an invalid type, uses an invalid unit, or
|
||||||
|
cannot be parsed for any other reason.
|
||||||
|
"""
|
||||||
if value is None:
|
if value is None:
|
||||||
new_value = None
|
new_value = None
|
||||||
elif isinstance(value, float):
|
elif isinstance(value, float):
|
||||||
@@ -78,10 +103,13 @@ class ScalarProperty:
|
|||||||
new_value = Scalar(float(new_value.value), self.percent_unit, Unit.WIDTH)
|
new_value = Scalar(float(new_value.value), self.percent_unit, Unit.WIDTH)
|
||||||
setattr(obj, self.internal_name, new_value)
|
setattr(obj, self.internal_name, new_value)
|
||||||
obj.refresh()
|
obj.refresh()
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
class BoxProperty:
|
class BoxProperty:
|
||||||
|
"""Descriptor for getting and setting outlines and borders along a single edge.
|
||||||
|
For example "border-right", "outline-bottom", etc.
|
||||||
|
"""
|
||||||
|
|
||||||
DEFAULT = ("", Style())
|
DEFAULT = ("", Style())
|
||||||
|
|
||||||
def __set_name__(self, owner: Styles, name: str) -> None:
|
def __set_name__(self, owner: Styles, name: str) -> None:
|
||||||
@@ -92,13 +120,32 @@ class BoxProperty:
|
|||||||
|
|
||||||
def __get__(
|
def __get__(
|
||||||
self, obj: Styles, objtype: type[Styles] | None = None
|
self, obj: Styles, objtype: type[Styles] | None = None
|
||||||
) -> tuple[str, Style]:
|
) -> tuple[BoxType, Style]:
|
||||||
|
"""Get the box property
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object
|
||||||
|
objtype (type[Styles]): The ``Styles`` class
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A ``tuple[BoxType, Style]`` containing the string type of the box and
|
||||||
|
it's style. Example types are "rounded", "solid", and "dashed".
|
||||||
|
"""
|
||||||
value = getattr(obj, self.internal_name)
|
value = getattr(obj, self.internal_name)
|
||||||
return value or self.DEFAULT
|
return value or self.DEFAULT
|
||||||
|
|
||||||
def __set__(
|
def __set__(self, obj: Styles, border: tuple[BoxType, str | Color | Style] | None):
|
||||||
self, obj: Styles, border: tuple[str, str | Color | Style] | None
|
"""Set the box property
|
||||||
) -> tuple[str, str | Color | Style] | None:
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object.
|
||||||
|
value (tuple[BoxType, str | Color | Style], optional): A 2-tuple containing the type of box to use,
|
||||||
|
e.g. "dashed", and the ``Style`` to be used. You can supply the ``Style`` directly, or pass a
|
||||||
|
``str`` (e.g. ``"blue on #f0f0f0"`` ) or ``Color`` instead.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
StyleSyntaxError: If the string supplied for the color has invalid syntax.
|
||||||
|
"""
|
||||||
if border is None:
|
if border is None:
|
||||||
new_value = None
|
new_value = None
|
||||||
else:
|
else:
|
||||||
@@ -111,17 +158,16 @@ class BoxProperty:
|
|||||||
new_value = (_type, Style.from_color(Color.parse(color)))
|
new_value = (_type, Style.from_color(Color.parse(color)))
|
||||||
setattr(obj, self.internal_name, new_value)
|
setattr(obj, self.internal_name, new_value)
|
||||||
obj.refresh()
|
obj.refresh()
|
||||||
return border
|
|
||||||
|
|
||||||
|
|
||||||
@rich.repr.auto
|
@rich.repr.auto
|
||||||
class Edges(NamedTuple):
|
class Edges(NamedTuple):
|
||||||
"""Stores edges for border / outline."""
|
"""Stores edges for border / outline."""
|
||||||
|
|
||||||
top: tuple[str, Style]
|
top: tuple[BoxType, Style]
|
||||||
right: tuple[str, Style]
|
right: tuple[BoxType, Style]
|
||||||
bottom: tuple[str, Style]
|
bottom: tuple[BoxType, Style]
|
||||||
left: tuple[str, Style]
|
left: tuple[BoxType, Style]
|
||||||
|
|
||||||
def __rich_repr__(self) -> rich.repr.Result:
|
def __rich_repr__(self) -> rich.repr.Result:
|
||||||
top, right, bottom, left = self
|
top, right, bottom, left = self
|
||||||
@@ -150,6 +196,8 @@ class Edges(NamedTuple):
|
|||||||
|
|
||||||
|
|
||||||
class BorderProperty:
|
class BorderProperty:
|
||||||
|
"""Descriptor for getting and setting full borders and outlines."""
|
||||||
|
|
||||||
def __set_name__(self, owner: Styles, name: str) -> None:
|
def __set_name__(self, owner: Styles, name: str) -> None:
|
||||||
self._properties = (
|
self._properties = (
|
||||||
f"{name}_top",
|
f"{name}_top",
|
||||||
@@ -159,6 +207,15 @@ class BorderProperty:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> Edges:
|
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> Edges:
|
||||||
|
"""Get the border
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object
|
||||||
|
objtype (type[Styles]): The ``Styles`` class
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
An ``Edges`` object describing the type and style of each edge.
|
||||||
|
"""
|
||||||
top, right, bottom, left = self._properties
|
top, right, bottom, left = self._properties
|
||||||
border = Edges(
|
border = Edges(
|
||||||
getattr(obj, top),
|
getattr(obj, top),
|
||||||
@@ -171,10 +228,25 @@ class BorderProperty:
|
|||||||
def __set__(
|
def __set__(
|
||||||
self,
|
self,
|
||||||
obj: Styles,
|
obj: Styles,
|
||||||
border: Sequence[tuple[str, str | Color | Style] | None]
|
border: Sequence[tuple[BoxType, str | Color | Style] | None]
|
||||||
| tuple[str, str | Color | Style]
|
| tuple[BoxType, str | Color | Style]
|
||||||
| None,
|
| None,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
"""Set the border
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object.
|
||||||
|
border (Sequence[tuple[BoxType, str | Color | Style] | None] | tuple[BoxType, str | Color | Style] | None):
|
||||||
|
A ``tuple[BoxType, str | Color | Style]`` representing the type of box to use and the ``Style`` to apply
|
||||||
|
to the box.
|
||||||
|
Alternatively, you can supply a sequence of these tuples and they will be applied per-edge.
|
||||||
|
If the sequence is of length 1, all edges will be decorated according to the single element.
|
||||||
|
If the sequence is length 2, the first ``tuple`` will be applied to the top and bottom edges.
|
||||||
|
If the sequence is length 4, the tuples will be applied to the edges in the order: top, right, bottom, left.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
StyleValueError: When the supplied ``tuple`` is not of valid length (1, 2, or 4).
|
||||||
|
"""
|
||||||
top, right, bottom, left = self._properties
|
top, right, bottom, left = self._properties
|
||||||
obj.refresh()
|
obj.refresh()
|
||||||
if border is None:
|
if border is None:
|
||||||
@@ -213,16 +285,25 @@ class BorderProperty:
|
|||||||
|
|
||||||
|
|
||||||
class StyleProperty:
|
class StyleProperty:
|
||||||
|
"""Descriptor for getting and setting full borders and outlines."""
|
||||||
|
|
||||||
DEFAULT_STYLE = Style()
|
DEFAULT_STYLE = Style()
|
||||||
|
|
||||||
def __set_name__(self, owner: Styles, name: str) -> None:
|
def __set_name__(self, owner: Styles, name: str) -> None:
|
||||||
|
|
||||||
self._color_name = f"_rule_{name}_color"
|
self._color_name = f"_rule_{name}_color"
|
||||||
self._bgcolor_name = f"_rule_{name}_background"
|
self._bgcolor_name = f"_rule_{name}_background"
|
||||||
self._style_name = f"_rule_{name}_style"
|
self._style_name = f"_rule_{name}_style"
|
||||||
|
|
||||||
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> Style:
|
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> Style:
|
||||||
|
"""Get the Style
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object
|
||||||
|
objtype (type[Styles]): The ``Styles`` class
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A ``Style`` object.
|
||||||
|
"""
|
||||||
color = getattr(obj, self._color_name)
|
color = getattr(obj, self._color_name)
|
||||||
bgcolor = getattr(obj, self._bgcolor_name)
|
bgcolor = getattr(obj, self._bgcolor_name)
|
||||||
style = Style.from_color(color, bgcolor)
|
style = Style.from_color(color, bgcolor)
|
||||||
@@ -231,7 +312,17 @@ class StyleProperty:
|
|||||||
style += style_flags
|
style += style_flags
|
||||||
return style
|
return style
|
||||||
|
|
||||||
def __set__(self, obj: Styles, style: Style | str | None) -> Style | str | None:
|
def __set__(self, obj: Styles, style: Style | str | None):
|
||||||
|
"""Set the Style
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object.
|
||||||
|
style (Style | str, optional): You can supply the ``Style`` directly, or a
|
||||||
|
string (e.g. ``"blue on #f0f0f0"``).
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
StyleSyntaxError: When the supplied style string has invalid syntax.
|
||||||
|
"""
|
||||||
obj.refresh()
|
obj.refresh()
|
||||||
if style is None:
|
if style is None:
|
||||||
setattr(obj, self._color_name, None)
|
setattr(obj, self._color_name, None)
|
||||||
@@ -246,48 +337,104 @@ class StyleProperty:
|
|||||||
setattr(obj, self._color_name, new_style.color)
|
setattr(obj, self._color_name, new_style.color)
|
||||||
setattr(obj, self._bgcolor_name, new_style.bgcolor)
|
setattr(obj, self._bgcolor_name, new_style.bgcolor)
|
||||||
setattr(obj, self._style_name, new_style.without_color)
|
setattr(obj, self._style_name, new_style.without_color)
|
||||||
return style
|
|
||||||
|
|
||||||
|
|
||||||
class SpacingProperty:
|
class SpacingProperty:
|
||||||
|
"""Descriptor for getting and setting spacing properties (e.g. padding and margin)."""
|
||||||
|
|
||||||
def __set_name__(self, owner: Styles, name: str) -> None:
|
def __set_name__(self, owner: Styles, name: str) -> None:
|
||||||
self._internal_name = f"_rule_{name}"
|
self._internal_name = f"_rule_{name}"
|
||||||
|
|
||||||
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> Spacing:
|
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> Spacing:
|
||||||
|
"""Get the Spacing
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object
|
||||||
|
objtype (type[Styles]): The ``Styles`` class
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Spacing: The Spacing. If unset, returns the null spacing ``(0, 0, 0, 0)``.
|
||||||
|
"""
|
||||||
return getattr(obj, self._internal_name) or NULL_SPACING
|
return getattr(obj, self._internal_name) or NULL_SPACING
|
||||||
|
|
||||||
def __set__(self, obj: Styles, spacing: SpacingDimensions) -> Spacing:
|
def __set__(self, obj: Styles, spacing: SpacingDimensions):
|
||||||
|
"""Set the Spacing
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object.
|
||||||
|
style (Style | str, optional): You can supply the ``Style`` directly, or a
|
||||||
|
string (e.g. ``"blue on #f0f0f0"``).
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: When the value is malformed, e.g. a ``tuple`` with a length that is
|
||||||
|
not 1, 2, or 4.
|
||||||
|
"""
|
||||||
obj.refresh(layout=True)
|
obj.refresh(layout=True)
|
||||||
spacing = Spacing.unpack(spacing)
|
spacing = Spacing.unpack(spacing)
|
||||||
setattr(obj, self._internal_name, spacing)
|
setattr(obj, self._internal_name, spacing)
|
||||||
return spacing
|
|
||||||
|
|
||||||
|
|
||||||
class DocksProperty:
|
class DocksProperty:
|
||||||
|
"""Descriptor for getting and setting the docks property. This property
|
||||||
|
is used to define docks and their location on screen.
|
||||||
|
"""
|
||||||
|
|
||||||
def __get__(
|
def __get__(
|
||||||
self, obj: Styles, objtype: type[Styles] | None = None
|
self, obj: Styles, objtype: type[Styles] | None = None
|
||||||
) -> tuple[DockGroup, ...]:
|
) -> tuple[DockGroup, ...]:
|
||||||
|
"""Get the Docks property
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object.
|
||||||
|
objtype (type[Styles]): The ``Styles`` class.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple[DockGroup, ...]: A ``tuple`` containing the defined docks.
|
||||||
|
"""
|
||||||
return obj._rule_docks or ()
|
return obj._rule_docks or ()
|
||||||
|
|
||||||
def __set__(
|
def __set__(self, obj: Styles, docks: Iterable[DockGroup] | None):
|
||||||
self, obj: Styles, docks: Iterable[DockGroup] | None
|
"""Set the Docks property
|
||||||
) -> Iterable[DockGroup] | None:
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object.
|
||||||
|
docks (Iterable[DockGroup]): Iterable of DockGroups
|
||||||
|
"""
|
||||||
obj.refresh(layout=True)
|
obj.refresh(layout=True)
|
||||||
if docks is None:
|
if docks is None:
|
||||||
obj._rule_docks = None
|
obj._rule_docks = None
|
||||||
else:
|
else:
|
||||||
obj._rule_docks = tuple(docks)
|
obj._rule_docks = tuple(docks)
|
||||||
return docks
|
|
||||||
|
|
||||||
|
|
||||||
class DockProperty:
|
class DockProperty:
|
||||||
|
"""Descriptor for getting and setting the dock property. The dock property
|
||||||
|
allows you to specify which dock you wish a Widget to be attached to. This
|
||||||
|
should be used in conjunction with the "docks" property which lets you define
|
||||||
|
the docks themselves, and where they are located on screen.
|
||||||
|
"""
|
||||||
|
|
||||||
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> str:
|
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> str:
|
||||||
|
"""Get the Dock property
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object.
|
||||||
|
objtype (type[Styles]): The ``Styles`` class.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The dock name as a string, or "" if the rule is not set.
|
||||||
|
"""
|
||||||
return obj._rule_dock or ""
|
return obj._rule_dock or ""
|
||||||
|
|
||||||
def __set__(self, obj: Styles, spacing: str | None) -> str | None:
|
def __set__(self, obj: Styles, spacing: str | None):
|
||||||
|
"""Set the Dock property
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object
|
||||||
|
spacing (str | None): The spacing to use.
|
||||||
|
"""
|
||||||
obj.refresh(layout=True)
|
obj.refresh(layout=True)
|
||||||
obj._rule_dock = spacing
|
obj._rule_dock = spacing
|
||||||
return spacing
|
|
||||||
|
|
||||||
|
|
||||||
class LayoutProperty:
|
class LayoutProperty:
|
||||||
@@ -324,17 +471,43 @@ class LayoutProperty:
|
|||||||
|
|
||||||
|
|
||||||
class OffsetProperty:
|
class OffsetProperty:
|
||||||
|
"""Descriptor for getting and setting the offset property.
|
||||||
|
Offset consists of two values, x and y, that a widget's position
|
||||||
|
will be adjusted by before it is rendered.
|
||||||
|
"""
|
||||||
|
|
||||||
def __set_name__(self, owner: Styles, name: str) -> None:
|
def __set_name__(self, owner: Styles, name: str) -> None:
|
||||||
self._internal_name = f"_rule_{name}"
|
self._internal_name = f"_rule_{name}"
|
||||||
|
|
||||||
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> ScalarOffset:
|
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> ScalarOffset:
|
||||||
|
"""Get the offset
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object.
|
||||||
|
objtype (type[Styles]): The ``Styles`` class.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
ScalarOffset: The ``ScalarOffset`` indicating the adjustment that
|
||||||
|
will be made to widget position prior to it being rendered.
|
||||||
|
"""
|
||||||
return getattr(obj, self._internal_name) or ScalarOffset(
|
return getattr(obj, self._internal_name) or ScalarOffset(
|
||||||
Scalar.from_number(0), Scalar.from_number(0)
|
Scalar.from_number(0), Scalar.from_number(0)
|
||||||
)
|
)
|
||||||
|
|
||||||
def __set__(
|
def __set__(self, obj: Styles, offset: tuple[int | str, int | str] | ScalarOffset):
|
||||||
self, obj: Styles, offset: tuple[int | str, int | str] | ScalarOffset
|
"""Set the offset
|
||||||
) -> tuple[int | str, int | str] | ScalarOffset:
|
|
||||||
|
Args:
|
||||||
|
obj: The ``Styles`` class
|
||||||
|
offset: A ScalarOffset object, or a 2-tuple of the form ``(x, y)`` indicating
|
||||||
|
the x and y offsets. When the ``tuple`` form is used, x and y can be specified
|
||||||
|
as either ``int`` or ``str``. The string format allows you to also specify
|
||||||
|
any valid scalar unit e.g. ``("0.5vw", "0.5vh")``.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ScalarParseError: If any of the string values supplied in the 2-tuple cannot
|
||||||
|
be parsed into a Scalar. For example, if you specify an non-existent unit.
|
||||||
|
"""
|
||||||
obj.refresh(layout=True)
|
obj.refresh(layout=True)
|
||||||
if isinstance(offset, ScalarOffset):
|
if isinstance(offset, ScalarOffset):
|
||||||
setattr(obj, self._internal_name, offset)
|
setattr(obj, self._internal_name, offset)
|
||||||
@@ -352,26 +525,48 @@ class OffsetProperty:
|
|||||||
)
|
)
|
||||||
_offset = ScalarOffset(scalar_x, scalar_y)
|
_offset = ScalarOffset(scalar_x, scalar_y)
|
||||||
setattr(obj, self._internal_name, _offset)
|
setattr(obj, self._internal_name, _offset)
|
||||||
return offset
|
|
||||||
|
|
||||||
|
|
||||||
class IntegerProperty:
|
class IntegerProperty:
|
||||||
|
"""Descriptor for getting and setting integer properties"""
|
||||||
|
|
||||||
def __set_name__(self, owner: Styles, name: str) -> None:
|
def __set_name__(self, owner: Styles, name: str) -> None:
|
||||||
self._name = name
|
self._name = name
|
||||||
self._internal_name = f"_{name}"
|
self._internal_name = f"_{name}"
|
||||||
|
|
||||||
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> int:
|
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> int:
|
||||||
|
"""Get the integer property, or the default ``0`` if not set.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object.
|
||||||
|
objtype (type[Styles]): The ``Styles`` class.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: The integer property value
|
||||||
|
"""
|
||||||
return getattr(obj, self._internal_name, 0)
|
return getattr(obj, self._internal_name, 0)
|
||||||
|
|
||||||
def __set__(self, obj: Styles, value: int | None) -> int | None:
|
def __set__(self, obj: Styles, value: int):
|
||||||
|
"""Set the integer property
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj: The ``Styles`` object
|
||||||
|
value: The value to set the integer to
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
StyleTypeError: If the supplied value is not an integer.
|
||||||
|
"""
|
||||||
obj.refresh()
|
obj.refresh()
|
||||||
if not isinstance(value, int):
|
if not isinstance(value, int):
|
||||||
raise StyleTypeError(f"{self._name} must be a str")
|
raise StyleTypeError(f"{self._name} must be an integer")
|
||||||
setattr(obj, self._internal_name, value)
|
setattr(obj, self._internal_name, value)
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
class StringProperty:
|
class StringEnumProperty:
|
||||||
|
"""Descriptor for getting and setting string properties and ensuring that the set
|
||||||
|
value belongs in the set of valid values.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, valid_values: set[str], default: str) -> None:
|
def __init__(self, valid_values: set[str], default: str) -> None:
|
||||||
self._valid_values = valid_values
|
self._valid_values = valid_values
|
||||||
self._default = default
|
self._default = default
|
||||||
@@ -381,9 +576,27 @@ class StringProperty:
|
|||||||
self._internal_name = f"_rule_{name}"
|
self._internal_name = f"_rule_{name}"
|
||||||
|
|
||||||
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> str:
|
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> str:
|
||||||
|
"""Get the string property, or the default value if it's not set
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object.
|
||||||
|
objtype (type[Styles]): The ``Styles`` class.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The string property value
|
||||||
|
"""
|
||||||
return getattr(obj, self._internal_name, None) or self._default
|
return getattr(obj, self._internal_name, None) or self._default
|
||||||
|
|
||||||
def __set__(self, obj: Styles, value: str | None = None) -> str | None:
|
def __set__(self, obj: Styles, value: str | None = None):
|
||||||
|
"""Set the string property and ensure it is in the set of allowed values.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object
|
||||||
|
value (str, optional): The string value to set the property to.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
StyleValueError: If the value is not in the set of valid values.
|
||||||
|
"""
|
||||||
obj.refresh()
|
obj.refresh()
|
||||||
if value is not None:
|
if value is not None:
|
||||||
if value not in self._valid_values:
|
if value not in self._valid_values:
|
||||||
@@ -391,23 +604,41 @@ class StringProperty:
|
|||||||
f"{self._name} must be one of {friendly_list(self._valid_values)}"
|
f"{self._name} must be one of {friendly_list(self._valid_values)}"
|
||||||
)
|
)
|
||||||
setattr(obj, self._internal_name, value)
|
setattr(obj, self._internal_name, value)
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
class NameProperty:
|
class NameProperty:
|
||||||
|
"""Descriptor for getting and setting name properties."""
|
||||||
|
|
||||||
def __set_name__(self, owner: Styles, name: str) -> None:
|
def __set_name__(self, owner: Styles, name: str) -> None:
|
||||||
self._name = name
|
self._name = name
|
||||||
self._internal_name = f"_rule_{name}"
|
self._internal_name = f"_rule_{name}"
|
||||||
|
|
||||||
def __get__(self, obj: Styles, objtype: type[Styles] | None) -> str:
|
def __get__(self, obj: Styles, objtype: type[Styles] | None) -> str:
|
||||||
|
"""Get the name property
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object.
|
||||||
|
objtype (type[Styles]): The ``Styles`` class.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The name
|
||||||
|
"""
|
||||||
return getattr(obj, self._internal_name) or ""
|
return getattr(obj, self._internal_name) or ""
|
||||||
|
|
||||||
def __set__(self, obj: Styles, name: str | None) -> str | None:
|
def __set__(self, obj: Styles, name: str | None):
|
||||||
|
"""Set the name property
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj: The ``Styles`` object
|
||||||
|
name: The name to set the property to
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
StyleTypeError: If the value is not a ``str``.
|
||||||
|
"""
|
||||||
obj.refresh(layout=True)
|
obj.refresh(layout=True)
|
||||||
if not isinstance(name, str):
|
if not isinstance(name, str):
|
||||||
raise StyleTypeError(f"{self._name} must be a str")
|
raise StyleTypeError(f"{self._name} must be a str")
|
||||||
setattr(obj, self._internal_name, name)
|
setattr(obj, self._internal_name, name)
|
||||||
return name
|
|
||||||
|
|
||||||
|
|
||||||
class NameListProperty:
|
class NameListProperty:
|
||||||
@@ -436,14 +667,36 @@ class NameListProperty:
|
|||||||
|
|
||||||
|
|
||||||
class ColorProperty:
|
class ColorProperty:
|
||||||
|
"""Descriptor for getting and setting color properties."""
|
||||||
|
|
||||||
def __set_name__(self, owner: Styles, name: str) -> None:
|
def __set_name__(self, owner: Styles, name: str) -> None:
|
||||||
self._name = name
|
self._name = name
|
||||||
self._internal_name = f"_rule_{name}"
|
self._internal_name = f"_rule_{name}"
|
||||||
|
|
||||||
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> Color:
|
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> Color:
|
||||||
|
"""Get the ``Color``, or ``Color.default()`` if no color is set.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object.
|
||||||
|
objtype (type[Styles]): The ``Styles`` class.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Color: The Color
|
||||||
|
"""
|
||||||
return getattr(obj, self._internal_name, None) or Color.default()
|
return getattr(obj, self._internal_name, None) or Color.default()
|
||||||
|
|
||||||
def __set__(self, obj: Styles, color: Color | str | None) -> Color | str | None:
|
def __set__(self, obj: Styles, color: Color | str | None):
|
||||||
|
"""Set the Color
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object
|
||||||
|
color (Color | str | None): The color to set. Pass a ``Color`` instance directly,
|
||||||
|
or pass a ``str`` which will be parsed into a color (e.g. ``"red""``, ``"rgb(20, 50, 80)"``,
|
||||||
|
``"#f4e32d"``).
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ColorParseError: When the color string is invalid.
|
||||||
|
"""
|
||||||
obj.refresh()
|
obj.refresh()
|
||||||
if color is None:
|
if color is None:
|
||||||
setattr(self, self._internal_name, None)
|
setattr(self, self._internal_name, None)
|
||||||
@@ -453,10 +706,11 @@ class ColorProperty:
|
|||||||
elif isinstance(color, str):
|
elif isinstance(color, str):
|
||||||
new_color = Color.parse(color)
|
new_color = Color.parse(color)
|
||||||
setattr(self, self._internal_name, new_color)
|
setattr(self, self._internal_name, new_color)
|
||||||
return color
|
|
||||||
|
|
||||||
|
|
||||||
class StyleFlagsProperty:
|
class StyleFlagsProperty:
|
||||||
|
"""Descriptor for getting and set style flag properties (e.g. ``bold italic underline``)."""
|
||||||
|
|
||||||
_VALID_PROPERTIES = {
|
_VALID_PROPERTIES = {
|
||||||
"not",
|
"not",
|
||||||
"bold",
|
"bold",
|
||||||
@@ -475,9 +729,28 @@ class StyleFlagsProperty:
|
|||||||
self._internal_name = f"_rule_{name}"
|
self._internal_name = f"_rule_{name}"
|
||||||
|
|
||||||
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> Style:
|
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> Style:
|
||||||
|
"""Get the ``Style``
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object.
|
||||||
|
objtype (type[Styles]): The ``Styles`` class.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Style: The ``Style`` object
|
||||||
|
"""
|
||||||
return getattr(obj, self._internal_name, None) or Style.null()
|
return getattr(obj, self._internal_name, None) or Style.null()
|
||||||
|
|
||||||
def __set__(self, obj: Styles, style_flags: str | None) -> str | None:
|
def __set__(self, obj: Styles, style_flags: str | None):
|
||||||
|
"""Set the style using a style flag string
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object.
|
||||||
|
style_flags (str, optional): The style flags to set as a string. For example,
|
||||||
|
``"bold italic"``.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
StyleValueError: If the value is an invalid style flag
|
||||||
|
"""
|
||||||
obj.refresh()
|
obj.refresh()
|
||||||
if style_flags is None:
|
if style_flags is None:
|
||||||
setattr(self, self._internal_name, None)
|
setattr(self, self._internal_name, None)
|
||||||
@@ -486,13 +759,17 @@ class StyleFlagsProperty:
|
|||||||
valid_word = self._VALID_PROPERTIES.__contains__
|
valid_word = self._VALID_PROPERTIES.__contains__
|
||||||
for word in words:
|
for word in words:
|
||||||
if not valid_word(word):
|
if not valid_word(word):
|
||||||
raise StyleValueError(f"unknown word {word!r} in style flags")
|
raise StyleValueError(
|
||||||
|
f"unknown word {word!r} in style flags, "
|
||||||
|
f"valid values are {friendly_list(self._VALID_PROPERTIES)}"
|
||||||
|
)
|
||||||
style = Style.parse(style_flags)
|
style = Style.parse(style_flags)
|
||||||
setattr(obj, self._internal_name, style)
|
setattr(obj, self._internal_name, style)
|
||||||
return style_flags
|
|
||||||
|
|
||||||
|
|
||||||
class TransitionsProperty:
|
class TransitionsProperty:
|
||||||
|
"""Descriptor for getting transitions properties"""
|
||||||
|
|
||||||
def __set_name__(self, owner: Styles, name: str) -> None:
|
def __set_name__(self, owner: Styles, name: str) -> None:
|
||||||
self._name = name
|
self._name = name
|
||||||
self._internal_name = f"_rule_{name}"
|
self._internal_name = f"_rule_{name}"
|
||||||
@@ -500,4 +777,15 @@ class TransitionsProperty:
|
|||||||
def __get__(
|
def __get__(
|
||||||
self, obj: Styles, objtype: type[Styles] | None = None
|
self, obj: Styles, objtype: type[Styles] | None = None
|
||||||
) -> dict[str, Transition]:
|
) -> dict[str, Transition]:
|
||||||
|
"""Get a mapping of properties to the the transitions applied to them.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Styles): The ``Styles`` object.
|
||||||
|
objtype (type[Styles]): The ``Styles`` class.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict[str, Transition]: A ``dict`` mapping property names to the ``Transition`` applied to them.
|
||||||
|
e.g. ``{"offset": Transition(...), ...}``. If no transitions have been set, an empty ``dict``
|
||||||
|
is returned.
|
||||||
|
"""
|
||||||
return getattr(obj, self._internal_name, None) or {}
|
return getattr(obj, self._internal_name, None) or {}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ from ._style_properties import (
|
|||||||
NameListProperty,
|
NameListProperty,
|
||||||
ScalarProperty,
|
ScalarProperty,
|
||||||
SpacingProperty,
|
SpacingProperty,
|
||||||
StringProperty,
|
StringEnumProperty,
|
||||||
StyleProperty,
|
StyleProperty,
|
||||||
StyleFlagsProperty,
|
StyleFlagsProperty,
|
||||||
TransitionsProperty,
|
TransitionsProperty,
|
||||||
@@ -34,6 +34,8 @@ from .scalar import Scalar, ScalarOffset, Unit
|
|||||||
from .scalar_animation import ScalarAnimation
|
from .scalar_animation import ScalarAnimation
|
||||||
from .transition import Transition
|
from .transition import Transition
|
||||||
from .types import Display, Edge, Visibility
|
from .types import Display, Edge, Visibility
|
||||||
|
|
||||||
|
|
||||||
from .types import Specificity3, Specificity4
|
from .types import Specificity3, Specificity4
|
||||||
from .. import log
|
from .. import log
|
||||||
from .._animator import Animation, EasingFunction
|
from .._animator import Animation, EasingFunction
|
||||||
@@ -97,8 +99,8 @@ class Styles:
|
|||||||
|
|
||||||
important: set[str] = field(default_factory=set)
|
important: set[str] = field(default_factory=set)
|
||||||
|
|
||||||
display = StringProperty(VALID_DISPLAY, "block")
|
display = StringEnumProperty(VALID_DISPLAY, "block")
|
||||||
visibility = StringProperty(VALID_VISIBILITY, "visible")
|
visibility = StringEnumProperty(VALID_VISIBILITY, "visible")
|
||||||
layout = LayoutProperty()
|
layout = LayoutProperty()
|
||||||
|
|
||||||
text = StyleProperty()
|
text = StyleProperty()
|
||||||
|
|||||||
@@ -14,9 +14,6 @@ if TYPE_CHECKING:
|
|||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
|
|
||||||
|
|
||||||
WINDOWS = platform.system() == "Windows"
|
|
||||||
|
|
||||||
|
|
||||||
class Driver(ABC):
|
class Driver(ABC):
|
||||||
def __init__(self, console: "Console", target: "MessageTarget") -> None:
|
def __init__(self, console: "Console", target: "MessageTarget") -> None:
|
||||||
self.console = console
|
self.console = console
|
||||||
|
|||||||
0
src/textual/drivers/__init__.py
Normal file
0
src/textual/drivers/__init__.py
Normal file
@@ -14,17 +14,19 @@ from threading import Event, Thread
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
|
|
||||||
from . import log
|
from .. import log
|
||||||
|
|
||||||
from . import events
|
from .. import events
|
||||||
from .driver import Driver
|
from ..driver import Driver
|
||||||
from .geometry import Size
|
from ..geometry import Size
|
||||||
from ._types import MessageTarget
|
from .._types import MessageTarget
|
||||||
from ._xterm_parser import XTermParser
|
from .._xterm_parser import XTermParser
|
||||||
from ._profile import timer
|
from .._profile import timer
|
||||||
|
|
||||||
|
|
||||||
class LinuxDriver(Driver):
|
class LinuxDriver(Driver):
|
||||||
|
"""Powers display and input for Linux / MacOS"""
|
||||||
|
|
||||||
def __init__(self, console: "Console", target: "MessageTarget") -> None:
|
def __init__(self, console: "Console", target: "MessageTarget") -> None:
|
||||||
super().__init__(console, target)
|
super().__init__(console, target)
|
||||||
self.fileno = sys.stdin.fileno()
|
self.fileno = sys.stdin.fileno()
|
||||||
@@ -155,21 +157,17 @@ class LinuxDriver(Driver):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def stop_application_mode(self) -> None:
|
def stop_application_mode(self) -> None:
|
||||||
|
self.disable_input()
|
||||||
|
|
||||||
with timer("disable_input"):
|
if self.attrs_before is not None:
|
||||||
self.disable_input()
|
try:
|
||||||
|
termios.tcsetattr(self.fileno, termios.TCSANOW, self.attrs_before)
|
||||||
|
except termios.error:
|
||||||
|
pass
|
||||||
|
|
||||||
with timer("tcsetattr"):
|
with self.console:
|
||||||
if self.attrs_before is not None:
|
self.console.set_alt_screen(False)
|
||||||
try:
|
self.console.show_cursor(True)
|
||||||
termios.tcsetattr(self.fileno, termios.TCSANOW, self.attrs_before)
|
|
||||||
except termios.error:
|
|
||||||
pass
|
|
||||||
|
|
||||||
with timer("set_alt_screen False, show cursor"):
|
|
||||||
with self.console:
|
|
||||||
self.console.set_alt_screen(False)
|
|
||||||
self.console.show_cursor(True)
|
|
||||||
|
|
||||||
def run_input_thread(self, loop) -> None:
|
def run_input_thread(self, loop) -> None:
|
||||||
try:
|
try:
|
||||||
@@ -215,11 +213,11 @@ class LinuxDriver(Driver):
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
from . import events
|
from .. import events
|
||||||
|
|
||||||
console = Console()
|
console = Console()
|
||||||
|
|
||||||
from .app import App
|
from ..app import App
|
||||||
|
|
||||||
class MyApp(App):
|
class MyApp(App):
|
||||||
async def on_mount(self, event: events.Mount) -> None:
|
async def on_mount(self, event: events.Mount) -> None:
|
||||||
289
src/textual/drivers/win32.py
Normal file
289
src/textual/drivers/win32.py
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
import ctypes
|
||||||
|
import msvcrt
|
||||||
|
import sys
|
||||||
|
import threading
|
||||||
|
from asyncio import AbstractEventLoop, run_coroutine_threadsafe
|
||||||
|
from ctypes import Structure, Union, byref, wintypes
|
||||||
|
from ctypes.wintypes import BOOL, CHAR, DWORD, HANDLE, SHORT, UINT, WCHAR, WORD
|
||||||
|
from typing import IO, Callable, List, Optional
|
||||||
|
|
||||||
|
from .._types import EventTarget
|
||||||
|
from .._xterm_parser import XTermParser
|
||||||
|
from ..events import Event, Resize
|
||||||
|
from ..geometry import Size
|
||||||
|
|
||||||
|
KERNEL32 = ctypes.WinDLL("kernel32", use_last_error=True)
|
||||||
|
|
||||||
|
# Console input modes
|
||||||
|
ENABLE_ECHO_INPUT = 0x0004
|
||||||
|
ENABLE_EXTENDED_FLAGS = 0x0080
|
||||||
|
ENABLE_INSERT_MODE = 0x0020
|
||||||
|
ENABLE_LINE_INPUT = 0x0002
|
||||||
|
ENABLE_MOUSE_INPUT = 0x0010
|
||||||
|
ENABLE_PROCESSED_INPUT = 0x0001
|
||||||
|
ENABLE_QUICK_EDIT_MODE = 0x0040
|
||||||
|
ENABLE_WINDOW_INPUT = 0x0008
|
||||||
|
ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200
|
||||||
|
|
||||||
|
# Console output modes
|
||||||
|
ENABLE_PROCESSED_OUTPUT = 0x0001
|
||||||
|
ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
|
||||||
|
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
|
||||||
|
DISABLE_NEWLINE_AUTO_RETURN = 0x0008
|
||||||
|
ENABLE_LVB_GRID_WORLDWIDE = 0x0010
|
||||||
|
|
||||||
|
STD_INPUT_HANDLE = -10
|
||||||
|
STD_OUTPUT_HANDLE = -11
|
||||||
|
|
||||||
|
WAIT_TIMEOUT = 0x00000102
|
||||||
|
|
||||||
|
GetStdHandle = KERNEL32.GetStdHandle
|
||||||
|
GetStdHandle.argtypes = [wintypes.DWORD]
|
||||||
|
GetStdHandle.restype = wintypes.HANDLE
|
||||||
|
|
||||||
|
|
||||||
|
class COORD(Structure):
|
||||||
|
"""https://docs.microsoft.com/en-us/windows/console/coord-str"""
|
||||||
|
|
||||||
|
_fields_ = [
|
||||||
|
("X", SHORT),
|
||||||
|
("Y", SHORT),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class uChar(Union):
|
||||||
|
"""https://docs.microsoft.com/en-us/windows/console/key-event-record-str"""
|
||||||
|
|
||||||
|
_fields_ = [
|
||||||
|
("AsciiChar", CHAR),
|
||||||
|
("UnicodeChar", WCHAR),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class KEY_EVENT_RECORD(Structure):
|
||||||
|
"""https://docs.microsoft.com/en-us/windows/console/key-event-record-str"""
|
||||||
|
|
||||||
|
_fields_ = [
|
||||||
|
("bKeyDown", BOOL),
|
||||||
|
("wRepeatCount", WORD),
|
||||||
|
("wVirtualKeyCode", WORD),
|
||||||
|
("wVirtualScanCode", WORD),
|
||||||
|
("uChar", uChar),
|
||||||
|
("dwControlKeyState", DWORD),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class MOUSE_EVENT_RECORD(Structure):
|
||||||
|
"""https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str"""
|
||||||
|
|
||||||
|
_fields_ = [
|
||||||
|
("dwMousePosition", COORD),
|
||||||
|
("dwButtonState", DWORD),
|
||||||
|
("dwControlKeyState", DWORD),
|
||||||
|
("dwEventFlags", DWORD),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class WINDOW_BUFFER_SIZE_RECORD(Structure):
|
||||||
|
"""https://docs.microsoft.com/en-us/windows/console/window-buffer-size-record-str"""
|
||||||
|
|
||||||
|
_fields_ = [("dwSize", COORD)]
|
||||||
|
|
||||||
|
|
||||||
|
class MENU_EVENT_RECORD(Structure):
|
||||||
|
"""https://docs.microsoft.com/en-us/windows/console/menu-event-record-str"""
|
||||||
|
|
||||||
|
_fields_ = [("dwCommandId", UINT)]
|
||||||
|
|
||||||
|
|
||||||
|
class FOCUS_EVENT_RECORD(Structure):
|
||||||
|
"""https://docs.microsoft.com/en-us/windows/console/focus-event-record-str"""
|
||||||
|
|
||||||
|
_fields_ = [("bSetFocus", BOOL)]
|
||||||
|
|
||||||
|
|
||||||
|
class InputEvent(Union):
|
||||||
|
"""https://docs.microsoft.com/en-us/windows/console/input-record-str"""
|
||||||
|
|
||||||
|
_fields_ = [
|
||||||
|
("KeyEvent", KEY_EVENT_RECORD),
|
||||||
|
("MouseEvent", MOUSE_EVENT_RECORD),
|
||||||
|
("WindowBufferSizeEvent", WINDOW_BUFFER_SIZE_RECORD),
|
||||||
|
("MenuEvent", MENU_EVENT_RECORD),
|
||||||
|
("FocusEvent", FOCUS_EVENT_RECORD),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class INPUT_RECORD(Structure):
|
||||||
|
"""https://docs.microsoft.com/en-us/windows/console/input-record-str"""
|
||||||
|
|
||||||
|
_fields_ = [("EventType", wintypes.WORD), ("Event", InputEvent)]
|
||||||
|
|
||||||
|
|
||||||
|
def _set_console_mode(file: IO, mode: int) -> bool:
|
||||||
|
"""Set the console mode for a given file (stdout or stdin).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file (IO): A file like object.
|
||||||
|
mode (int): New mode.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True on success, otherwise False.
|
||||||
|
"""
|
||||||
|
windows_filehandle = msvcrt.get_osfhandle(file.fileno())
|
||||||
|
success = KERNEL32.SetConsoleMode(windows_filehandle, mode)
|
||||||
|
return success
|
||||||
|
|
||||||
|
|
||||||
|
def _get_console_mode(file: IO) -> int:
|
||||||
|
"""Get the console mode for a given file (stdout or stdin)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file (IO): A file-like object.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: The current console mode.
|
||||||
|
"""
|
||||||
|
windows_filehandle = msvcrt.get_osfhandle(file.fileno())
|
||||||
|
mode = wintypes.DWORD()
|
||||||
|
KERNEL32.GetConsoleMode(windows_filehandle, ctypes.byref(mode))
|
||||||
|
return mode.value
|
||||||
|
|
||||||
|
|
||||||
|
def enable_application_mode() -> Callable[[], None]:
|
||||||
|
"""Enable application mode.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Callable[[], None]: A callable that will restore terminal to previous state.
|
||||||
|
"""
|
||||||
|
|
||||||
|
terminal_in = sys.stdin
|
||||||
|
terminal_out = sys.stdout
|
||||||
|
|
||||||
|
current_console_mode_in = _get_console_mode(terminal_in)
|
||||||
|
current_console_mode_out = _get_console_mode(terminal_out)
|
||||||
|
|
||||||
|
def restore() -> None:
|
||||||
|
"""Restore console mode to previous settings"""
|
||||||
|
_set_console_mode(terminal_in, current_console_mode_in)
|
||||||
|
_set_console_mode(terminal_out, current_console_mode_out)
|
||||||
|
|
||||||
|
_set_console_mode(
|
||||||
|
terminal_out, current_console_mode_out | ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||||
|
)
|
||||||
|
_set_console_mode(terminal_in, ENABLE_VIRTUAL_TERMINAL_INPUT)
|
||||||
|
return restore
|
||||||
|
|
||||||
|
|
||||||
|
def _wait_for_handles(handles: List[HANDLE], timeout: int = -1) -> Optional[HANDLE]:
|
||||||
|
"""
|
||||||
|
Waits for multiple handles. (Similar to 'select') Returns the handle which is ready.
|
||||||
|
Returns `None` on timeout.
|
||||||
|
http://msdn.microsoft.com/en-us/library/windows/desktop/ms687025(v=vs.85).aspx
|
||||||
|
Note that handles should be a list of `HANDLE` objects, not integers. See
|
||||||
|
this comment in the patch by @quark-zju for the reason why:
|
||||||
|
''' Make sure HANDLE on Windows has a correct size
|
||||||
|
Previously, the type of various HANDLEs are native Python integer
|
||||||
|
types. The ctypes library will treat them as 4-byte integer when used
|
||||||
|
in function arguments. On 64-bit Windows, HANDLE is 8-byte and usually
|
||||||
|
a small integer. Depending on whether the extra 4 bytes are zero-ed out
|
||||||
|
or not, things can happen to work, or break. '''
|
||||||
|
This function returns either `None` or one of the given `HANDLE` objects.
|
||||||
|
(The return value can be tested with the `is` operator.)
|
||||||
|
"""
|
||||||
|
arrtype = HANDLE * len(handles)
|
||||||
|
handle_array = arrtype(*handles)
|
||||||
|
|
||||||
|
ret: int = KERNEL32.WaitForMultipleObjects(
|
||||||
|
len(handle_array), handle_array, BOOL(False), DWORD(timeout)
|
||||||
|
)
|
||||||
|
|
||||||
|
if ret == WAIT_TIMEOUT:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return handles[ret]
|
||||||
|
|
||||||
|
|
||||||
|
class EventMonitor(threading.Thread):
|
||||||
|
"""A thread to send key / window events to Textual loop."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
loop: AbstractEventLoop,
|
||||||
|
app,
|
||||||
|
target: EventTarget,
|
||||||
|
exit_event: threading.Event,
|
||||||
|
process_event: Callable[[Event], None],
|
||||||
|
) -> None:
|
||||||
|
self.loop = loop
|
||||||
|
self.app = app
|
||||||
|
self.target = target
|
||||||
|
self.exit_event = exit_event
|
||||||
|
self.process_event = process_event
|
||||||
|
self.app.log("event monitor constructed")
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
def run(self) -> None:
|
||||||
|
self.app.log("event monitor thread started")
|
||||||
|
exit_requested = self.exit_event.is_set
|
||||||
|
parser = XTermParser(self.target, lambda: False)
|
||||||
|
|
||||||
|
try:
|
||||||
|
read_count = wintypes.DWORD(0)
|
||||||
|
hIn = GetStdHandle(STD_INPUT_HANDLE)
|
||||||
|
|
||||||
|
MAX_EVENTS = 1024
|
||||||
|
KEY_EVENT = 0x0001
|
||||||
|
WINDOW_BUFFER_SIZE_EVENT = 0x0004
|
||||||
|
|
||||||
|
arrtype = INPUT_RECORD * MAX_EVENTS
|
||||||
|
input_records = arrtype()
|
||||||
|
ReadConsoleInputW = KERNEL32.ReadConsoleInputW
|
||||||
|
keys: List[str] = []
|
||||||
|
append_key = keys.append
|
||||||
|
|
||||||
|
while not exit_requested():
|
||||||
|
# Wait for new events
|
||||||
|
if _wait_for_handles([hIn], 200) is None:
|
||||||
|
# No new events
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Get new events
|
||||||
|
ReadConsoleInputW(
|
||||||
|
hIn, byref(input_records), MAX_EVENTS, byref(read_count)
|
||||||
|
)
|
||||||
|
read_input_records = input_records[: read_count.value]
|
||||||
|
|
||||||
|
del keys[:]
|
||||||
|
new_size: Optional[tuple[int, int]] = None
|
||||||
|
|
||||||
|
for input_record in read_input_records:
|
||||||
|
event_type = input_record.EventType
|
||||||
|
|
||||||
|
if event_type == KEY_EVENT:
|
||||||
|
# Key event, store unicode char in keys list
|
||||||
|
key_event = input_record.Event.KeyEvent
|
||||||
|
key = key_event.uChar.UnicodeChar
|
||||||
|
if key_event.bKeyDown or key == "\x1b":
|
||||||
|
append_key(key)
|
||||||
|
elif event_type == WINDOW_BUFFER_SIZE_EVENT:
|
||||||
|
# Window size changed, store size
|
||||||
|
size = input_record.Event.WindowBufferSizeEvent.dwSize
|
||||||
|
new_size = (size.X, size.Y)
|
||||||
|
|
||||||
|
if keys:
|
||||||
|
# Process keys
|
||||||
|
for event in parser.feed("".join(keys)):
|
||||||
|
self.process_event(event)
|
||||||
|
if new_size is not None:
|
||||||
|
# Process changed size
|
||||||
|
self.on_size_change(*new_size)
|
||||||
|
|
||||||
|
except Exception as error:
|
||||||
|
self.app.log("EVENT MONITOR ERROR", error)
|
||||||
|
self.app.log("event monitor thread finished")
|
||||||
|
|
||||||
|
def on_size_change(self, width: int, height: int) -> None:
|
||||||
|
"""Called when terminal size changes."""
|
||||||
|
event = Resize(self.target, Size(width, height))
|
||||||
|
run_coroutine_threadsafe(self.target.post_message(event), loop=self.loop)
|
||||||
81
src/textual/drivers/windows_driver.py
Normal file
81
src/textual/drivers/windows_driver.py
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import sys
|
||||||
|
from threading import Event, Thread
|
||||||
|
from typing import TYPE_CHECKING, Callable
|
||||||
|
|
||||||
|
from .._context import active_app
|
||||||
|
from .._types import MessageTarget
|
||||||
|
from ..driver import Driver
|
||||||
|
from . import win32
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from rich.console import Console
|
||||||
|
|
||||||
|
|
||||||
|
class WindowsDriver(Driver):
|
||||||
|
"""Powers display and input for Windows."""
|
||||||
|
|
||||||
|
def __init__(self, console: "Console", target: "MessageTarget") -> None:
|
||||||
|
super().__init__(console, target)
|
||||||
|
self.in_fileno = sys.stdin.fileno()
|
||||||
|
self.out_fileno = sys.stdout.fileno()
|
||||||
|
|
||||||
|
self.exit_event = Event()
|
||||||
|
self._event_thread: Thread | None = None
|
||||||
|
self._restore_console: Callable[[], None] | None = None
|
||||||
|
|
||||||
|
def _enable_mouse_support(self) -> None:
|
||||||
|
write = self.console.file.write
|
||||||
|
write("\x1b[?1000h") # SET_VT200_MOUSE
|
||||||
|
write("\x1b[?1003h") # SET_ANY_EVENT_MOUSE
|
||||||
|
write("\x1b[?1015h") # SET_VT200_HIGHLIGHT_MOUSE
|
||||||
|
write("\x1b[?1006h") # SET_SGR_EXT_MODE_MOUSE
|
||||||
|
self.console.file.flush()
|
||||||
|
|
||||||
|
def _disable_mouse_support(self) -> None:
|
||||||
|
write = self.console.file.write
|
||||||
|
write("\x1b[?1000l")
|
||||||
|
write("\x1b[?1003l")
|
||||||
|
write("\x1b[?1015l")
|
||||||
|
write("\x1b[?1006l")
|
||||||
|
self.console.file.flush()
|
||||||
|
|
||||||
|
def start_application_mode(self) -> None:
|
||||||
|
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
|
||||||
|
self._restore_console = win32.enable_application_mode()
|
||||||
|
|
||||||
|
self.console.set_alt_screen(True)
|
||||||
|
self._enable_mouse_support()
|
||||||
|
self.console.show_cursor(False)
|
||||||
|
self.console.file.write("\033[?1003h\n")
|
||||||
|
|
||||||
|
app = active_app.get()
|
||||||
|
|
||||||
|
self._event_thread = win32.EventMonitor(
|
||||||
|
loop, app, self._target, self.exit_event, self.process_event
|
||||||
|
)
|
||||||
|
self._event_thread.start()
|
||||||
|
|
||||||
|
def disable_input(self) -> None:
|
||||||
|
try:
|
||||||
|
if not self.exit_event.is_set():
|
||||||
|
self._disable_mouse_support()
|
||||||
|
self.exit_event.set()
|
||||||
|
if self._event_thread is not None:
|
||||||
|
self._event_thread.join()
|
||||||
|
self._event_thread = None
|
||||||
|
except Exception as error:
|
||||||
|
# TODO: log this
|
||||||
|
pass
|
||||||
|
|
||||||
|
def stop_application_mode(self) -> None:
|
||||||
|
self.disable_input()
|
||||||
|
if self._restore_console:
|
||||||
|
self._restore_console()
|
||||||
|
with self.console:
|
||||||
|
self.console.set_alt_screen(False)
|
||||||
|
self.console.show_cursor(True)
|
||||||
@@ -237,7 +237,7 @@ class MouseEvent(InputEvent, bubble=True):
|
|||||||
Args:
|
Args:
|
||||||
sender (MessageTarget): The sender of the event.
|
sender (MessageTarget): The sender of the event.
|
||||||
x (int): The relative x coordinate.
|
x (int): The relative x coordinate.
|
||||||
y (int): The relative y cootdinate.
|
y (int): The relative y coordinate.
|
||||||
delta_x (int): Change in x since the last message.
|
delta_x (int): Change in x since the last message.
|
||||||
delta_y (int): Change in y since the last message.
|
delta_y (int): Change in y since the last message.
|
||||||
button (int): Indexed of the pressed button.
|
button (int): Indexed of the pressed button.
|
||||||
|
|||||||
0
src/textual/renderables/__init__.py
Normal file
0
src/textual/renderables/__init__.py
Normal file
122
src/textual/renderables/underline_bar.py
Normal file
122
src/textual/renderables/underline_bar.py
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from rich.console import ConsoleOptions, Console, RenderResult
|
||||||
|
from rich.segment import Segment
|
||||||
|
from rich.style import StyleType
|
||||||
|
|
||||||
|
|
||||||
|
class UnderlineBar:
|
||||||
|
"""Thin horizontal bar with a portion highlighted.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
highlight_range (tuple[float, float]): The range to highlight. Defaults to ``(0, 0)`` (no highlight)
|
||||||
|
highlight_style (StyleType): The style of the highlighted range of the bar.
|
||||||
|
background_style (StyleType): The style of the non-highlighted range(s) of the bar.
|
||||||
|
width (int, optional): The width of the bar, or ``None`` to fill available width.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
highlight_range: tuple[float, float] = (0, 0),
|
||||||
|
highlight_style: StyleType = "magenta",
|
||||||
|
background_style: StyleType = "grey37",
|
||||||
|
width: int | None = None,
|
||||||
|
) -> None:
|
||||||
|
self.highlight_range = highlight_range
|
||||||
|
self.highlight_style = highlight_style
|
||||||
|
self.background_style = background_style
|
||||||
|
self.width = width
|
||||||
|
|
||||||
|
def __rich_console__(
|
||||||
|
self, console: Console, options: ConsoleOptions
|
||||||
|
) -> RenderResult:
|
||||||
|
highlight_style = console.get_style(self.highlight_style)
|
||||||
|
background_style = console.get_style(self.background_style)
|
||||||
|
|
||||||
|
half_bar_right = "╸"
|
||||||
|
half_bar_left = "╺"
|
||||||
|
bar = "━"
|
||||||
|
|
||||||
|
width = self.width or options.max_width
|
||||||
|
start, end = self.highlight_range
|
||||||
|
|
||||||
|
start = max(start, 0)
|
||||||
|
end = min(end, width)
|
||||||
|
|
||||||
|
if start == end == 0 or end < 0 or start > end:
|
||||||
|
yield Segment(bar * width, style=background_style)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Round start and end to nearest half
|
||||||
|
start = round(start * 2) / 2
|
||||||
|
end = round(end * 2) / 2
|
||||||
|
|
||||||
|
# Check if we start/end on a number that rounds to a .5
|
||||||
|
half_start = start - int(start) > 0
|
||||||
|
half_end = end - int(end) > 0
|
||||||
|
|
||||||
|
# Initial non-highlighted portion of bar
|
||||||
|
yield Segment(bar * (int(start - 0.5)), style=background_style)
|
||||||
|
if not half_start and start > 0:
|
||||||
|
yield Segment(half_bar_right, style=background_style)
|
||||||
|
|
||||||
|
# The highlighted portion
|
||||||
|
bar_width = int(end) - int(start)
|
||||||
|
if half_start:
|
||||||
|
yield Segment(half_bar_left + bar * (bar_width - 1), style=highlight_style)
|
||||||
|
else:
|
||||||
|
yield Segment(bar * bar_width, style=highlight_style)
|
||||||
|
if half_end:
|
||||||
|
yield Segment(half_bar_right, style=highlight_style)
|
||||||
|
|
||||||
|
# The non-highlighted tail
|
||||||
|
if not half_end and end - width != 0:
|
||||||
|
yield Segment(half_bar_left, style=background_style)
|
||||||
|
yield Segment(bar * (int(width) - int(end) - 1), style=background_style)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import random
|
||||||
|
from time import sleep
|
||||||
|
from rich.color import ANSI_COLOR_NAMES
|
||||||
|
|
||||||
|
console = Console()
|
||||||
|
|
||||||
|
def frange(start, end, step):
|
||||||
|
current = start
|
||||||
|
while current < end:
|
||||||
|
yield current
|
||||||
|
current += step
|
||||||
|
|
||||||
|
while current >= 0:
|
||||||
|
yield current
|
||||||
|
current -= step
|
||||||
|
|
||||||
|
step = 0.1
|
||||||
|
start_range = frange(0.5, 10.5, step)
|
||||||
|
end_range = frange(10, 20, step)
|
||||||
|
ranges = zip(start_range, end_range)
|
||||||
|
|
||||||
|
console.print(UnderlineBar(width=20), f" (.0, .0)")
|
||||||
|
|
||||||
|
for range in ranges:
|
||||||
|
color = random.choice(list(ANSI_COLOR_NAMES.keys()))
|
||||||
|
console.print(
|
||||||
|
UnderlineBar(
|
||||||
|
range,
|
||||||
|
highlight_style=color,
|
||||||
|
width=20,
|
||||||
|
),
|
||||||
|
f" {range}",
|
||||||
|
)
|
||||||
|
|
||||||
|
from rich.live import Live
|
||||||
|
|
||||||
|
bar = UnderlineBar(width=80, highlight_range=(0, 4.5))
|
||||||
|
with Live(bar, refresh_per_second=60) as live:
|
||||||
|
while True:
|
||||||
|
bar.highlight_range = (
|
||||||
|
bar.highlight_range[0] + 0.1,
|
||||||
|
bar.highlight_range[1] + 0.1,
|
||||||
|
)
|
||||||
|
sleep(0.005)
|
||||||
0
tests/renderables/__init__.py
Normal file
0
tests/renderables/__init__.py
Normal file
126
tests/renderables/test_underline_bar.py
Normal file
126
tests/renderables/test_underline_bar.py
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
from tests.utilities.render import render
|
||||||
|
from textual.renderables.underline_bar import UnderlineBar
|
||||||
|
|
||||||
|
MAGENTA = "\x1b[35m"
|
||||||
|
GREY = "\x1b[38;5;59m"
|
||||||
|
STOP = "\x1b[0m"
|
||||||
|
GREEN = "\x1b[32m"
|
||||||
|
RED = "\x1b[31m"
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_highlight():
|
||||||
|
bar = UnderlineBar(width=6)
|
||||||
|
assert render(bar) == f"{GREY}━━━━━━{STOP}"
|
||||||
|
|
||||||
|
|
||||||
|
def test_highlight_from_zero():
|
||||||
|
bar = UnderlineBar(highlight_range=(0, 2.5), width=6)
|
||||||
|
assert render(bar) == (
|
||||||
|
f"{MAGENTA}━━{STOP}{MAGENTA}╸{STOP}{GREY}━━━{STOP}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_highlight_from_zero_point_five():
|
||||||
|
bar = UnderlineBar(highlight_range=(0.5, 2), width=6)
|
||||||
|
assert render(bar) == (
|
||||||
|
f"{MAGENTA}╺━{STOP}{GREY}╺{STOP}{GREY}━━━{STOP}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_highlight_middle():
|
||||||
|
bar = UnderlineBar(highlight_range=(2, 4), width=6)
|
||||||
|
assert render(bar) == (
|
||||||
|
f"{GREY}━{STOP}"
|
||||||
|
f"{GREY}╸{STOP}"
|
||||||
|
f"{MAGENTA}━━{STOP}"
|
||||||
|
f"{GREY}╺{STOP}"
|
||||||
|
f"{GREY}━{STOP}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_highlight_half_start():
|
||||||
|
bar = UnderlineBar(highlight_range=(2.5, 4), width=6)
|
||||||
|
assert render(bar) == (
|
||||||
|
f"{GREY}━━{STOP}"
|
||||||
|
f"{MAGENTA}╺━{STOP}"
|
||||||
|
f"{GREY}╺{STOP}"
|
||||||
|
f"{GREY}━{STOP}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_highlight_half_end():
|
||||||
|
bar = UnderlineBar(highlight_range=(2, 4.5), width=6)
|
||||||
|
assert render(bar) == (
|
||||||
|
f"{GREY}━{STOP}"
|
||||||
|
f"{GREY}╸{STOP}"
|
||||||
|
f"{MAGENTA}━━{STOP}"
|
||||||
|
f"{MAGENTA}╸{STOP}"
|
||||||
|
f"{GREY}━{STOP}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_highlight_half_start_and_half_end():
|
||||||
|
bar = UnderlineBar(highlight_range=(2.5, 4.5), width=6)
|
||||||
|
assert render(bar) == (
|
||||||
|
f"{GREY}━━{STOP}"
|
||||||
|
f"{MAGENTA}╺━{STOP}"
|
||||||
|
f"{MAGENTA}╸{STOP}"
|
||||||
|
f"{GREY}━{STOP}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_highlight_to_near_end():
|
||||||
|
bar = UnderlineBar(highlight_range=(3, 5.5), width=6)
|
||||||
|
assert render(bar) == (
|
||||||
|
f"{GREY}━━{STOP}"
|
||||||
|
f"{GREY}╸{STOP}"
|
||||||
|
f"{MAGENTA}━━{STOP}"
|
||||||
|
f"{MAGENTA}╸{STOP}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_highlight_to_end():
|
||||||
|
bar = UnderlineBar(highlight_range=(3, 6), width=6)
|
||||||
|
assert render(bar) == (
|
||||||
|
f"{GREY}━━{STOP}{GREY}╸{STOP}{MAGENTA}━━━{STOP}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_highlight_out_of_bounds_start():
|
||||||
|
bar = UnderlineBar(highlight_range=(-2, 3), width=6)
|
||||||
|
assert render(bar) == (
|
||||||
|
f"{MAGENTA}━━━{STOP}{GREY}╺{STOP}{GREY}━━{STOP}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_highlight_out_of_bounds_end():
|
||||||
|
bar = UnderlineBar(highlight_range=(3, 9), width=6)
|
||||||
|
assert render(bar) == (
|
||||||
|
f"{GREY}━━{STOP}{GREY}╸{STOP}{MAGENTA}━━━{STOP}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_highlight_full_range_out_of_bounds_end():
|
||||||
|
bar = UnderlineBar(highlight_range=(9, 10), width=6)
|
||||||
|
assert render(bar) == f"{GREY}━━━━━━{STOP}"
|
||||||
|
|
||||||
|
|
||||||
|
def test_highlight_full_range_out_of_bounds_start():
|
||||||
|
bar = UnderlineBar(highlight_range=(-5, -2), width=6)
|
||||||
|
assert render(bar) == f"{GREY}━━━━━━{STOP}"
|
||||||
|
|
||||||
|
|
||||||
|
def test_custom_styles():
|
||||||
|
bar = UnderlineBar(
|
||||||
|
highlight_range=(2, 4),
|
||||||
|
highlight_style="red",
|
||||||
|
background_style="green",
|
||||||
|
width=6
|
||||||
|
)
|
||||||
|
assert render(bar) == (
|
||||||
|
f"{GREEN}━{STOP}"
|
||||||
|
f"{GREEN}╸{STOP}"
|
||||||
|
f"{RED}━━{STOP}"
|
||||||
|
f"{GREEN}╺{STOP}"
|
||||||
|
f"{GREEN}━{STOP}"
|
||||||
|
)
|
||||||
24
tests/utilities/render.py
Normal file
24
tests/utilities/render.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import io
|
||||||
|
import re
|
||||||
|
|
||||||
|
from rich.console import Console, RenderableType
|
||||||
|
|
||||||
|
|
||||||
|
re_link_ids = re.compile(r"id=[\d\.\-]*?;.*?\x1b")
|
||||||
|
|
||||||
|
|
||||||
|
def replace_link_ids(render: str) -> str:
|
||||||
|
"""Link IDs have a random ID and system path which is a problem for
|
||||||
|
reproducible tests.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return re_link_ids.sub("id=0;foo\x1b", render)
|
||||||
|
|
||||||
|
|
||||||
|
def render(renderable: RenderableType, no_wrap: bool = False) -> str:
|
||||||
|
console = Console(
|
||||||
|
width=100, file=io.StringIO(), color_system="truecolor", legacy_windows=False
|
||||||
|
)
|
||||||
|
console.print(renderable, no_wrap=no_wrap)
|
||||||
|
output = replace_link_ids(console.file.getvalue())
|
||||||
|
return output
|
||||||
Reference in New Issue
Block a user