mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
merge
This commit is contained in:
4
Makefile
4
Makefile
@@ -6,3 +6,7 @@ format:
|
||||
black src
|
||||
format-check:
|
||||
black --check src
|
||||
docs-serve:
|
||||
mkdocs serve
|
||||
docs-build:
|
||||
mkdocs build
|
||||
|
||||
@@ -17,7 +17,3 @@ The `Resize` event is sent to a widget when its size changes and when it is firs
|
||||
`event.container_size`
|
||||
|
||||
: The size of the widget's container.
|
||||
|
||||
## Code
|
||||
|
||||
::: textual.events.Resize
|
||||
|
||||
20
docs/examples/light_dark.py
Normal file
20
docs/examples/light_dark.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from textual.app import App
|
||||
from textual.widgets import Button
|
||||
|
||||
|
||||
class ButtonApp(App):
|
||||
|
||||
CSS = """
|
||||
|
||||
Button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
def compose(self):
|
||||
yield Button("Lights off")
|
||||
|
||||
def handle_pressed(self, event):
|
||||
self.dark = not self.dark
|
||||
event.button.label = "Lights ON" if self.dark else "Lights OFF"
|
||||
BIN
docs/images/dom.excalidraw.png
Normal file
BIN
docs/images/dom.excalidraw.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
BIN
docs/images/events.excalidraw.png
Normal file
BIN
docs/images/events.excalidraw.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 446 KiB |
BIN
docs/images/message_pump.excalidraw.png
Normal file
BIN
docs/images/message_pump.excalidraw.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 190 KiB |
@@ -34,13 +34,15 @@ The command prompt should disappear and you will see a blank screen. It will loo
|
||||
|
||||
Hit ++ctrl+c++ to exit and return to the command prompt.
|
||||
|
||||
### The code
|
||||
|
||||
The first step in all Textual applications is to import the `App` class from `textual.app` and extend it:
|
||||
|
||||
```python hl_lines="1 2 3 4 5" title="intro01.py"
|
||||
--8<-- "docs/examples/introduction/intro01.py"
|
||||
```
|
||||
|
||||
There will be a single App class in any Textual application. The App class is responsible for loading data, setting up the screen, managing events etc. In a real app most of the core logic of your application will be contained within methods on the this class.
|
||||
This App class is responsible for loading data, setting up the screen, managing events etc. In a real app most of the core logic of your application will be contained within methods on the this class.
|
||||
|
||||
The last two lines create an instance of the application and calls `run()`:
|
||||
|
||||
@@ -52,13 +54,15 @@ The `run` method will put your terminal in to "application mode" which disables
|
||||
|
||||
## Handling Events
|
||||
|
||||
In the previously example our app did next to nothing. Most applications will contain event handler methods, which are called in response to user actions such as key presses and mouse movements in addition to other changes your app needs to know about such as terminal resize, scrolling, timers, etc.
|
||||
Most real-world applications will want to interact with the user in some way. To do this we can make use of _event handler_ methods, which are called in response to things the user does such as pressing a key(s), moving the mouse, resizing the terminal, etc.
|
||||
|
||||
Each event type is represented by an event object, which is an instance of a class containing information you may need to respond the the event. For instance the `Key` event contains the key the user pressed and a `Mouse` event will contain the coordinates of the mouse cursor.
|
||||
|
||||
!!! note
|
||||
|
||||
Although `intro01.py` did not explicitly define any event handlers, Textual still had to respond to events to catch ++ctrl+c++, otherwise you wouldn't be able to exit the app.
|
||||
|
||||
In our next example, we are going to handle two events; `Mount` and `Key`. The `Mount` event is sent when the app is first run, and a `Key` event is sent when the user presses a key on the keyboard. Try running `intro02.py` in the `docs/examples/introduction`:
|
||||
The next example demonstrates handling events. Try running `intro02.py` in the `docs/examples/introduction`:
|
||||
|
||||
```python title="intro02.py"
|
||||
--8<-- "docs/examples/introduction/intro02.py"
|
||||
@@ -78,17 +82,17 @@ If you hit any of the number keys ++0++-++9++, the background will change color
|
||||
|
||||
There are two event handlers in this app. Event handlers start with the text `on_` followed by the name of the event in lower case. Hence `on_mount` is called for the `Mount` event, and `on_key` is called for the `Key` event.
|
||||
|
||||
The first event handler to run is `on_mount`:
|
||||
The first event handler to run is `on_mount`. The `Mount` is sent to your application immediately after entering application mode.
|
||||
|
||||
```python hl_lines="19 20" title="intro02.py"
|
||||
--8<-- "docs/examples/introduction/intro02.py"
|
||||
```
|
||||
|
||||
This `on_mount` method sets the `background` attribute of `self.styles` to `"darkblue"` which updates the background color. There are a lot of other properties on the Styles object, which define how your app looks. We will explore what you can do with this object later.
|
||||
This `on_mount` method sets the `background` attribute of `self.styles` to `"darkblue"` which makes the background blue when the application starts. There are a lot of other properties on the Styles object, which define how your app looks. We will explore what you can do with this object later.
|
||||
|
||||
!!! note
|
||||
|
||||
You may have noticed there was no function call to repaint the screen in this examples. Textual will detect when a refresh is required, and do it automatically.
|
||||
You may have noticed there is no function call to repaint the screen in this example. Textual is generally quite smart in detecting when a refresh is required, and updating the screen automatically.
|
||||
|
||||
The second event handler will receive `Key` events whenever you press a key on the keyboard:
|
||||
|
||||
@@ -96,15 +100,15 @@ The second event handler will receive `Key` events whenever you press a key on t
|
||||
--8<-- "docs/examples/introduction/intro02.py"
|
||||
```
|
||||
|
||||
This method has an `event` positional argument which contains information regarding the key that was pressed. The body of the method sets the background to a corresponding color int the `COLORS` list when you press one of the digit keys. It also calls `bell()` which is a method on App that plays your terminal's bell.
|
||||
This method has an `event` positional argument which will receive the event object; in this case the `Key` event. The body of the method sets the background to a corresponding color in the `COLORS` list when you press one of the digit keys. It also calls `bell()` which is a method on App that plays your terminal's bell.
|
||||
|
||||
!!! note
|
||||
|
||||
Every event has a corresponding `Event` object, but Textual knows to only call the event handler with the event object if you have it in the argument list. It does this by inspecting the handler method prior to calling it.
|
||||
Every event has a corresponding `Event` object, but Textual knows to only call the event handler with the event object if you have it in the argument list. It does this by inspecting the handler method prior to calling it. So if you don't need the event object, you may leave it out.
|
||||
|
||||
## Widgets
|
||||
|
||||
Most Textual applications will also make use of one or more `Widget` classes. A Widget is a self contained component responsible for defining how a given part of the screen should look. Widgets respond to events in much the same way as the App does.
|
||||
Most Textual applications will make use of one or more `Widget` classes. A Widget is a self contained component responsible for defining how a given part of the screen should look. Widgets respond to events in much the same way as the App does.
|
||||
|
||||
Let's look at an app with a simple Widget to show the current time and date. Here is the code for `"clock01.py"` which is in the same directory as the previous examples:
|
||||
|
||||
@@ -124,7 +128,7 @@ This script imports App as before, but also the `Widget` class from `textual.wid
|
||||
--8<-- "docs/examples/introduction/clock01.py"
|
||||
```
|
||||
|
||||
Widgets support many of the same events as the Application itself, and can be thought of as mini-applications in their own right. The Clock widget also responds to a Mount event which is the first event received when a widget is _mounted_ (added to the App). The code in `Clock.on_mount` sets `styles.content_align` to tuple of `("center", "middle")` which tells Textual to display the Widget's content aligned to the horizontal center, and in the middle vertically. If you resize the terminal, you should find the time remains in the center.
|
||||
Widgets support many of the same events as the Application itself, and can be thought of as mini-applications in their own right. The Clock widget responds to a Mount event which is the first event received when a widget is _mounted_ (added to the App). The code in `Clock.on_mount` sets `styles.content_align` to tuple of `("center", "middle")` which tells Textual to display the Widget's content aligned to the horizontal center, and in the middle vertically. If you resize the terminal, you should find the time remains in the center.
|
||||
|
||||
The second line in `on_mount` calls `self.set_interval` which tells Textual to invoke the `self.refresh` function once a second to refresh the Clock widget.
|
||||
|
||||
|
||||
1
docs/reference/geometry.md
Normal file
1
docs/reference/geometry.md
Normal file
@@ -0,0 +1 @@
|
||||
::: textual.geometry
|
||||
@@ -16,6 +16,7 @@ nav:
|
||||
- Reference:
|
||||
- "reference/app.md"
|
||||
- "reference/events.md"
|
||||
- "reference/geometry.md"
|
||||
- "reference/widget.md"
|
||||
|
||||
markdown_extensions:
|
||||
@@ -70,7 +71,7 @@ plugins:
|
||||
handlers:
|
||||
python:
|
||||
rendering:
|
||||
show_source: true
|
||||
show_source: false
|
||||
selection:
|
||||
filters:
|
||||
- "!^_"
|
||||
|
||||
260
poetry.lock
generated
260
poetry.lock
generated
@@ -31,17 +31,6 @@ python-versions = ">=3.6"
|
||||
[package.dependencies]
|
||||
frozenlist = ">=1.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "astunparse"
|
||||
version = "1.6.3"
|
||||
description = "An AST unparser for Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.dependencies]
|
||||
six = ">=1.6.1,<2.0"
|
||||
|
||||
[[package]]
|
||||
name = "async-timeout"
|
||||
version = "4.0.2"
|
||||
@@ -166,7 +155,7 @@ test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"]
|
||||
|
||||
[[package]]
|
||||
name = "coverage"
|
||||
version = "6.4"
|
||||
version = "6.4.1"
|
||||
description = "Code coverage measurement for Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
@@ -185,7 +174,7 @@ python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "filelock"
|
||||
version = "3.7.0"
|
||||
version = "3.7.1"
|
||||
description = "A platform independent file lock."
|
||||
category = "dev"
|
||||
optional = false
|
||||
@@ -219,7 +208,7 @@ dev = ["twine", "markdown", "flake8", "wheel"]
|
||||
|
||||
[[package]]
|
||||
name = "griffe"
|
||||
version = "0.19.2"
|
||||
version = "0.19.3"
|
||||
description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API."
|
||||
category = "dev"
|
||||
optional = false
|
||||
@@ -356,7 +345,7 @@ mkdocs = ">=1.1"
|
||||
|
||||
[[package]]
|
||||
name = "mkdocs-material"
|
||||
version = "8.2.15"
|
||||
version = "8.3.0"
|
||||
description = "Documentation that simply works"
|
||||
category = "dev"
|
||||
optional = false
|
||||
@@ -380,7 +369,7 @@ python-versions = ">=3.6"
|
||||
|
||||
[[package]]
|
||||
name = "mkdocstrings"
|
||||
version = "0.18.1"
|
||||
version = "0.19.0"
|
||||
description = "Automatic documentation from sources, for MkDocs."
|
||||
category = "dev"
|
||||
optional = false
|
||||
@@ -393,7 +382,6 @@ MarkupSafe = ">=1.1"
|
||||
mkdocs = ">=1.2"
|
||||
mkdocs-autorefs = ">=0.3.1"
|
||||
mkdocstrings-python = {version = ">=0.5.2", optional = true, markers = "extra == \"python\""}
|
||||
mkdocstrings-python-legacy = ">=0.2"
|
||||
pymdown-extensions = ">=6.3"
|
||||
|
||||
[package.extras]
|
||||
@@ -403,7 +391,7 @@ python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "mkdocstrings-python"
|
||||
version = "0.6.6"
|
||||
version = "0.7.0"
|
||||
description = "A Python handler for mkdocstrings."
|
||||
category = "dev"
|
||||
optional = false
|
||||
@@ -411,24 +399,12 @@ python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
griffe = ">=0.11.1"
|
||||
mkdocstrings = ">=0.18"
|
||||
|
||||
[[package]]
|
||||
name = "mkdocstrings-python-legacy"
|
||||
version = "0.2.2"
|
||||
description = "A legacy Python handler for mkdocstrings."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
mkdocstrings = ">=0.18"
|
||||
pytkdocs = ">=0.14"
|
||||
mkdocstrings = ">=0.19"
|
||||
|
||||
[[package]]
|
||||
name = "msgpack"
|
||||
version = "1.0.3"
|
||||
description = "MessagePack (de)serializer."
|
||||
version = "1.0.4"
|
||||
description = "MessagePack serializer"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
@@ -657,22 +633,6 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
|
||||
[package.dependencies]
|
||||
six = ">=1.5"
|
||||
|
||||
[[package]]
|
||||
name = "pytkdocs"
|
||||
version = "0.16.1"
|
||||
description = "Load Python objects documentation."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
astunparse = {version = ">=1.6", markers = "python_version < \"3.9\""}
|
||||
cached-property = {version = ">=1.5", markers = "python_version < \"3.8\""}
|
||||
typing-extensions = {version = ">=3.7", markers = "python_version < \"3.8\""}
|
||||
|
||||
[package.extras]
|
||||
numpy-style = ["docstring_parser (>=0.7)"]
|
||||
|
||||
[[package]]
|
||||
name = "pyyaml"
|
||||
version = "6.0"
|
||||
@@ -817,7 +777,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-
|
||||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.7"
|
||||
content-hash = "bfa71851a0d29adf2bf6de97054967e2122355bdefe859439bca5ec4377c9992"
|
||||
content-hash = "378a60041202d505cba26ea7084886fe1b01090a0035253b100593b559aed090"
|
||||
|
||||
[metadata.files]
|
||||
aiohttp = [
|
||||
@@ -898,10 +858,6 @@ aiosignal = [
|
||||
{file = "aiosignal-1.2.0-py3-none-any.whl", hash = "sha256:26e62109036cd181df6e6ad646f91f0dcfd05fe16d0cb924138ff2ab75d64e3a"},
|
||||
{file = "aiosignal-1.2.0.tar.gz", hash = "sha256:78ed67db6c7b7ced4f98e495e572106d5c432a93e1ddd1bf475e1dc05f5b7df2"},
|
||||
]
|
||||
astunparse = [
|
||||
{file = "astunparse-1.6.3-py2.py3-none-any.whl", hash = "sha256:c2652417f2c8b5bb325c885ae329bdf3f86424075c4fd1a128674bc6fba4b8e8"},
|
||||
{file = "astunparse-1.6.3.tar.gz", hash = "sha256:5ad93a8456f0d084c3456d059fd9a92cce667963232cbf763eac3bc5b7940872"},
|
||||
]
|
||||
async-timeout = [
|
||||
{file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"},
|
||||
{file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"},
|
||||
@@ -968,55 +924,55 @@ commonmark = [
|
||||
{file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"},
|
||||
]
|
||||
coverage = [
|
||||
{file = "coverage-6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:50ed480b798febce113709846b11f5d5ed1e529c88d8ae92f707806c50297abf"},
|
||||
{file = "coverage-6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:26f8f92699756cb7af2b30720de0c5bb8d028e923a95b6d0c891088025a1ac8f"},
|
||||
{file = "coverage-6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60c2147921da7f4d2d04f570e1838db32b95c5509d248f3fe6417e91437eaf41"},
|
||||
{file = "coverage-6.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:750e13834b597eeb8ae6e72aa58d1d831b96beec5ad1d04479ae3772373a8088"},
|
||||
{file = "coverage-6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af5b9ee0fc146e907aa0f5fb858c3b3da9199d78b7bb2c9973d95550bd40f701"},
|
||||
{file = "coverage-6.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a022394996419142b33a0cf7274cb444c01d2bb123727c4bb0b9acabcb515dea"},
|
||||
{file = "coverage-6.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5a78cf2c43b13aa6b56003707c5203f28585944c277c1f3f109c7b041b16bd39"},
|
||||
{file = "coverage-6.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9229d074e097f21dfe0643d9d0140ee7433814b3f0fc3706b4abffd1e3038632"},
|
||||
{file = "coverage-6.4-cp310-cp310-win32.whl", hash = "sha256:fb45fe08e1abc64eb836d187b20a59172053999823f7f6ef4f18a819c44ba16f"},
|
||||
{file = "coverage-6.4-cp310-cp310-win_amd64.whl", hash = "sha256:3cfd07c5889ddb96a401449109a8b97a165be9d67077df6802f59708bfb07720"},
|
||||
{file = "coverage-6.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:03014a74023abaf5a591eeeaf1ac66a73d54eba178ff4cb1fa0c0a44aae70383"},
|
||||
{file = "coverage-6.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c82f2cd69c71698152e943f4a5a6b83a3ab1db73b88f6e769fabc86074c3b08"},
|
||||
{file = "coverage-6.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b546cf2b1974ddc2cb222a109b37c6ed1778b9be7e6b0c0bc0cf0438d9e45a6"},
|
||||
{file = "coverage-6.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc173f1ce9ffb16b299f51c9ce53f66a62f4d975abe5640e976904066f3c835d"},
|
||||
{file = "coverage-6.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c53ad261dfc8695062fc8811ac7c162bd6096a05a19f26097f411bdf5747aee7"},
|
||||
{file = "coverage-6.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:eef5292b60b6de753d6e7f2d128d5841c7915fb1e3321c3a1fe6acfe76c38052"},
|
||||
{file = "coverage-6.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:543e172ce4c0de533fa892034cce260467b213c0ea8e39da2f65f9a477425211"},
|
||||
{file = "coverage-6.4-cp37-cp37m-win32.whl", hash = "sha256:00c8544510f3c98476bbd58201ac2b150ffbcce46a8c3e4fb89ebf01998f806a"},
|
||||
{file = "coverage-6.4-cp37-cp37m-win_amd64.whl", hash = "sha256:b84ab65444dcc68d761e95d4d70f3cfd347ceca5a029f2ffec37d4f124f61311"},
|
||||
{file = "coverage-6.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d548edacbf16a8276af13063a2b0669d58bbcfca7c55a255f84aac2870786a61"},
|
||||
{file = "coverage-6.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:033ebec282793bd9eb988d0271c211e58442c31077976c19c442e24d827d356f"},
|
||||
{file = "coverage-6.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:742fb8b43835078dd7496c3c25a1ec8d15351df49fb0037bffb4754291ef30ce"},
|
||||
{file = "coverage-6.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d55fae115ef9f67934e9f1103c9ba826b4c690e4c5bcf94482b8b2398311bf9c"},
|
||||
{file = "coverage-6.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cd698341626f3c77784858427bad0cdd54a713115b423d22ac83a28303d1d95"},
|
||||
{file = "coverage-6.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:62d382f7d77eeeaff14b30516b17bcbe80f645f5cf02bb755baac376591c653c"},
|
||||
{file = "coverage-6.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:016d7f5cf1c8c84f533a3c1f8f36126fbe00b2ec0ccca47cc5731c3723d327c6"},
|
||||
{file = "coverage-6.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:69432946f154c6add0e9ede03cc43b96e2ef2733110a77444823c053b1ff5166"},
|
||||
{file = "coverage-6.4-cp38-cp38-win32.whl", hash = "sha256:83bd142cdec5e4a5c4ca1d4ff6fa807d28460f9db919f9f6a31babaaa8b88426"},
|
||||
{file = "coverage-6.4-cp38-cp38-win_amd64.whl", hash = "sha256:4002f9e8c1f286e986fe96ec58742b93484195defc01d5cc7809b8f7acb5ece3"},
|
||||
{file = "coverage-6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e4f52c272fdc82e7c65ff3f17a7179bc5f710ebc8ce8a5cadac81215e8326740"},
|
||||
{file = "coverage-6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b5578efe4038be02d76c344007b13119b2b20acd009a88dde8adec2de4f630b5"},
|
||||
{file = "coverage-6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8099ea680201c2221f8468c372198ceba9338a5fec0e940111962b03b3f716a"},
|
||||
{file = "coverage-6.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a00441f5ea4504f5abbc047589d09e0dc33eb447dc45a1a527c8b74bfdd32c65"},
|
||||
{file = "coverage-6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e76bd16f0e31bc2b07e0fb1379551fcd40daf8cdf7e24f31a29e442878a827c"},
|
||||
{file = "coverage-6.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8d2e80dd3438e93b19e1223a9850fa65425e77f2607a364b6fd134fcd52dc9df"},
|
||||
{file = "coverage-6.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:341e9c2008c481c5c72d0e0dbf64980a4b2238631a7f9780b0fe2e95755fb018"},
|
||||
{file = "coverage-6.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:21e6686a95025927775ac501e74f5940cdf6fe052292f3a3f7349b0abae6d00f"},
|
||||
{file = "coverage-6.4-cp39-cp39-win32.whl", hash = "sha256:968ed5407f9460bd5a591cefd1388cc00a8f5099de9e76234655ae48cfdbe2c3"},
|
||||
{file = "coverage-6.4-cp39-cp39-win_amd64.whl", hash = "sha256:e35217031e4b534b09f9b9a5841b9344a30a6357627761d4218818b865d45055"},
|
||||
{file = "coverage-6.4-pp36.pp37.pp38-none-any.whl", hash = "sha256:e637ae0b7b481905358624ef2e81d7fb0b1af55f5ff99f9ba05442a444b11e45"},
|
||||
{file = "coverage-6.4.tar.gz", hash = "sha256:727dafd7f67a6e1cad808dc884bd9c5a2f6ef1f8f6d2f22b37b96cb0080d4f49"},
|
||||
{file = "coverage-6.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f1d5aa2703e1dab4ae6cf416eb0095304f49d004c39e9db1d86f57924f43006b"},
|
||||
{file = "coverage-6.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4ce1b258493cbf8aec43e9b50d89982346b98e9ffdfaae8ae5793bc112fb0068"},
|
||||
{file = "coverage-6.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83c4e737f60c6936460c5be330d296dd5b48b3963f48634c53b3f7deb0f34ec4"},
|
||||
{file = "coverage-6.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84e65ef149028516c6d64461b95a8dbcfce95cfd5b9eb634320596173332ea84"},
|
||||
{file = "coverage-6.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f69718750eaae75efe506406c490d6fc5a6161d047206cc63ce25527e8a3adad"},
|
||||
{file = "coverage-6.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e57816f8ffe46b1df8f12e1b348f06d164fd5219beba7d9433ba79608ef011cc"},
|
||||
{file = "coverage-6.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:01c5615d13f3dd3aa8543afc069e5319cfa0c7d712f6e04b920431e5c564a749"},
|
||||
{file = "coverage-6.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:75ab269400706fab15981fd4bd5080c56bd5cc07c3bccb86aab5e1d5a88dc8f4"},
|
||||
{file = "coverage-6.4.1-cp310-cp310-win32.whl", hash = "sha256:a7f3049243783df2e6cc6deafc49ea123522b59f464831476d3d1448e30d72df"},
|
||||
{file = "coverage-6.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:ee2ddcac99b2d2aec413e36d7a429ae9ebcadf912946b13ffa88e7d4c9b712d6"},
|
||||
{file = "coverage-6.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fb73e0011b8793c053bfa85e53129ba5f0250fdc0392c1591fd35d915ec75c46"},
|
||||
{file = "coverage-6.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:106c16dfe494de3193ec55cac9640dd039b66e196e4641fa8ac396181578b982"},
|
||||
{file = "coverage-6.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87f4f3df85aa39da00fd3ec4b5abeb7407e82b68c7c5ad181308b0e2526da5d4"},
|
||||
{file = "coverage-6.4.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:961e2fb0680b4f5ad63234e0bf55dfb90d302740ae9c7ed0120677a94a1590cb"},
|
||||
{file = "coverage-6.4.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:cec3a0f75c8f1031825e19cd86ee787e87cf03e4fd2865c79c057092e69e3a3b"},
|
||||
{file = "coverage-6.4.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:129cd05ba6f0d08a766d942a9ed4b29283aff7b2cccf5b7ce279d50796860bb3"},
|
||||
{file = "coverage-6.4.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bf5601c33213d3cb19d17a796f8a14a9eaa5e87629a53979a5981e3e3ae166f6"},
|
||||
{file = "coverage-6.4.1-cp37-cp37m-win32.whl", hash = "sha256:269eaa2c20a13a5bf17558d4dc91a8d078c4fa1872f25303dddcbba3a813085e"},
|
||||
{file = "coverage-6.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f02cbbf8119db68455b9d763f2f8737bb7db7e43720afa07d8eb1604e5c5ae28"},
|
||||
{file = "coverage-6.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ffa9297c3a453fba4717d06df579af42ab9a28022444cae7fa605af4df612d54"},
|
||||
{file = "coverage-6.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:145f296d00441ca703a659e8f3eb48ae39fb083baba2d7ce4482fb2723e050d9"},
|
||||
{file = "coverage-6.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d44996140af8b84284e5e7d398e589574b376fb4de8ccd28d82ad8e3bea13"},
|
||||
{file = "coverage-6.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2bd9a6fc18aab8d2e18f89b7ff91c0f34ff4d5e0ba0b33e989b3cd4194c81fd9"},
|
||||
{file = "coverage-6.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3384f2a3652cef289e38100f2d037956194a837221edd520a7ee5b42d00cc605"},
|
||||
{file = "coverage-6.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9b3e07152b4563722be523e8cd0b209e0d1a373022cfbde395ebb6575bf6790d"},
|
||||
{file = "coverage-6.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1480ff858b4113db2718848d7b2d1b75bc79895a9c22e76a221b9d8d62496428"},
|
||||
{file = "coverage-6.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:865d69ae811a392f4d06bde506d531f6a28a00af36f5c8649684a9e5e4a85c83"},
|
||||
{file = "coverage-6.4.1-cp38-cp38-win32.whl", hash = "sha256:664a47ce62fe4bef9e2d2c430306e1428ecea207ffd68649e3b942fa8ea83b0b"},
|
||||
{file = "coverage-6.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:26dff09fb0d82693ba9e6231248641d60ba606150d02ed45110f9ec26404ed1c"},
|
||||
{file = "coverage-6.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d9c80df769f5ec05ad21ea34be7458d1dc51ff1fb4b2219e77fe24edf462d6df"},
|
||||
{file = "coverage-6.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:39ee53946bf009788108b4dd2894bf1349b4e0ca18c2016ffa7d26ce46b8f10d"},
|
||||
{file = "coverage-6.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5b66caa62922531059bc5ac04f836860412f7f88d38a476eda0a6f11d4724f4"},
|
||||
{file = "coverage-6.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd180ed867e289964404051a958f7cccabdeed423f91a899829264bb7974d3d3"},
|
||||
{file = "coverage-6.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84631e81dd053e8a0d4967cedab6db94345f1c36107c71698f746cb2636c63e3"},
|
||||
{file = "coverage-6.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8c08da0bd238f2970230c2a0d28ff0e99961598cb2e810245d7fc5afcf1254e8"},
|
||||
{file = "coverage-6.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d42c549a8f41dc103a8004b9f0c433e2086add8a719da00e246e17cbe4056f72"},
|
||||
{file = "coverage-6.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:309ce4a522ed5fca432af4ebe0f32b21d6d7ccbb0f5fcc99290e71feba67c264"},
|
||||
{file = "coverage-6.4.1-cp39-cp39-win32.whl", hash = "sha256:fdb6f7bd51c2d1714cea40718f6149ad9be6a2ee7d93b19e9f00934c0f2a74d9"},
|
||||
{file = "coverage-6.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:342d4aefd1c3e7f620a13f4fe563154d808b69cccef415415aece4c786665397"},
|
||||
{file = "coverage-6.4.1-pp36.pp37.pp38-none-any.whl", hash = "sha256:4803e7ccf93230accb928f3a68f00ffa80a88213af98ed338a57ad021ef06815"},
|
||||
{file = "coverage-6.4.1.tar.gz", hash = "sha256:4321f075095a096e70aff1d002030ee612b65a205a0a0f5b815280d5dc58100c"},
|
||||
]
|
||||
distlib = [
|
||||
{file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"},
|
||||
{file = "distlib-0.3.4.zip", hash = "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"},
|
||||
]
|
||||
filelock = [
|
||||
{file = "filelock-3.7.0-py3-none-any.whl", hash = "sha256:c7b5fdb219b398a5b28c8e4c1893ef5f98ece6a38c6ab2c22e26ec161556fed6"},
|
||||
{file = "filelock-3.7.0.tar.gz", hash = "sha256:b795f1b42a61bbf8ec7113c341dad679d772567b936fbd1bf43c9a238e673e20"},
|
||||
{file = "filelock-3.7.1-py3-none-any.whl", hash = "sha256:37def7b658813cda163b56fc564cdc75e86d338246458c4c28ae84cabefa2404"},
|
||||
{file = "filelock-3.7.1.tar.gz", hash = "sha256:3a0fd85166ad9dbab54c9aec96737b744106dc5f15c0b09a6744a445299fcf04"},
|
||||
]
|
||||
frozenlist = [
|
||||
{file = "frozenlist-1.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d2257aaba9660f78c7b1d8fea963b68f3feffb1a9d5d05a18401ca9eb3e8d0a3"},
|
||||
@@ -1084,8 +1040,8 @@ ghp-import = [
|
||||
{file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"},
|
||||
]
|
||||
griffe = [
|
||||
{file = "griffe-0.19.2-py3-none-any.whl", hash = "sha256:5855368feffaabca51be721ca4110220320e3eb361b6c068f2273a6bf7d0bd05"},
|
||||
{file = "griffe-0.19.2.tar.gz", hash = "sha256:edf925b6ff3101930a97ce48661e34d547b9347fd11e87d49e8cee4c59d30f90"},
|
||||
{file = "griffe-0.19.3-py3-none-any.whl", hash = "sha256:348422f0e303ff3b76d6b35a96fa9c90dddcbe175506171fda78e8e5cf8c4246"},
|
||||
{file = "griffe-0.19.3.tar.gz", hash = "sha256:3a51e53bc58c45d38d6d7b4509b41b153b506de3df99767e6f891c75d91706a5"},
|
||||
]
|
||||
identify = [
|
||||
{file = "identify-2.5.1-py2.py3-none-any.whl", hash = "sha256:0dca2ea3e4381c435ef9c33ba100a78a9b40c0bab11189c7cf121f75815efeaa"},
|
||||
@@ -1166,60 +1122,74 @@ mkdocs-autorefs = [
|
||||
{file = "mkdocs_autorefs-0.4.1-py3-none-any.whl", hash = "sha256:a2248a9501b29dc0cc8ba4c09f4f47ff121945f6ce33d760f145d6f89d313f5b"},
|
||||
]
|
||||
mkdocs-material = [
|
||||
{file = "mkdocs-material-8.2.15.tar.gz", hash = "sha256:93b57e53733051431cc83216446e774bdf08bf516a6251ff2f24974f45f98149"},
|
||||
{file = "mkdocs_material-8.2.15-py2.py3-none-any.whl", hash = "sha256:9d6c4ca1ceecc00b2e38c214665ed7605d275321dcaa22f38b9d1175edc58955"},
|
||||
{file = "mkdocs-material-8.3.0.tar.gz", hash = "sha256:4cad98c47c49a86591ed16a790c07d59402901fc5345f575a3b7329403f5c66e"},
|
||||
{file = "mkdocs_material-8.3.0-py2.py3-none-any.whl", hash = "sha256:e37e7da1c5923c5b9f0bb8c4ad90bc694fee8f966b43b302a7ff61cb2c35c2e0"},
|
||||
]
|
||||
mkdocs-material-extensions = [
|
||||
{file = "mkdocs-material-extensions-1.0.3.tar.gz", hash = "sha256:bfd24dfdef7b41c312ede42648f9eb83476ea168ec163b613f9abd12bbfddba2"},
|
||||
{file = "mkdocs_material_extensions-1.0.3-py3-none-any.whl", hash = "sha256:a82b70e533ce060b2a5d9eb2bc2e1be201cf61f901f93704b4acf6e3d5983a44"},
|
||||
]
|
||||
mkdocstrings = [
|
||||
{file = "mkdocstrings-0.18.1-py3-none-any.whl", hash = "sha256:4053929356df8cd69ed32eef71d8f676a472ef72980c9ffd4f933ead1debcdad"},
|
||||
{file = "mkdocstrings-0.18.1.tar.gz", hash = "sha256:fb7c91ce7e3ab70488d3fa6c073a4f827cdc319042f682ef8ea95459790d64fc"},
|
||||
{file = "mkdocstrings-0.19.0-py3-none-any.whl", hash = "sha256:3217d510d385c961f69385a670b2677e68e07b5fea4a504d86bf54c006c87c7d"},
|
||||
{file = "mkdocstrings-0.19.0.tar.gz", hash = "sha256:efa34a67bad11229d532d89f6836a8a215937548623b64f3698a1df62e01cc3e"},
|
||||
]
|
||||
mkdocstrings-python = [
|
||||
{file = "mkdocstrings-python-0.6.6.tar.gz", hash = "sha256:37281696b9f199624ae420e0625b6659b7fdfbea736618bce7fd978682dea3b1"},
|
||||
{file = "mkdocstrings_python-0.6.6-py3-none-any.whl", hash = "sha256:c118438d3cb4b14c492a51d109f4e5b27ab06ba19b099d624430dfd904926152"},
|
||||
]
|
||||
mkdocstrings-python-legacy = [
|
||||
{file = "mkdocstrings-python-legacy-0.2.2.tar.gz", hash = "sha256:f0e7ec6a19750581b752acb38f6b32fcd1efe006f14f6703125d2c2c9a5c6f02"},
|
||||
{file = "mkdocstrings_python_legacy-0.2.2-py3-none-any.whl", hash = "sha256:379107a3a5b8db9b462efc4493c122efe21e825e3702425dbd404621302a563a"},
|
||||
{file = "mkdocstrings-python-0.7.0.tar.gz", hash = "sha256:e54c67890e8bb7dc4604360c8ef5dd214b23b6924de7706f461e3c998d4ea061"},
|
||||
{file = "mkdocstrings_python-0.7.0-py3-none-any.whl", hash = "sha256:6964bd92f106766e771ac6cd5bc02643a960602b4d921b95362e31d491e9a6db"},
|
||||
]
|
||||
msgpack = [
|
||||
{file = "msgpack-1.0.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:96acc674bb9c9be63fa8b6dabc3248fdc575c4adc005c440ad02f87ca7edd079"},
|
||||
{file = "msgpack-1.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2c3ca57c96c8e69c1a0d2926a6acf2d9a522b41dc4253a8945c4c6cd4981a4e3"},
|
||||
{file = "msgpack-1.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0a792c091bac433dfe0a70ac17fc2087d4595ab835b47b89defc8bbabcf5c73"},
|
||||
{file = "msgpack-1.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c58cdec1cb5fcea8c2f1771d7b5fec79307d056874f746690bd2bdd609ab147"},
|
||||
{file = "msgpack-1.0.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f97c0f35b3b096a330bb4a1a9247d0bd7e1f3a2eba7ab69795501504b1c2c39"},
|
||||
{file = "msgpack-1.0.3-cp310-cp310-win32.whl", hash = "sha256:36a64a10b16c2ab31dcd5f32d9787ed41fe68ab23dd66957ca2826c7f10d0b85"},
|
||||
{file = "msgpack-1.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c1ba333b4024c17c7591f0f372e2daa3c31db495a9b2af3cf664aef3c14354f7"},
|
||||
{file = "msgpack-1.0.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c2140cf7a3ec475ef0938edb6eb363fa704159e0bf71dde15d953bacc1cf9d7d"},
|
||||
{file = "msgpack-1.0.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f4c22717c74d44bcd7af353024ce71c6b55346dad5e2cc1ddc17ce8c4507c6b"},
|
||||
{file = "msgpack-1.0.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d733a15ade190540c703de209ffbc42a3367600421b62ac0c09fde594da6ec"},
|
||||
{file = "msgpack-1.0.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7e03b06f2982aa98d4ddd082a210c3db200471da523f9ac197f2828e80e7770"},
|
||||
{file = "msgpack-1.0.3-cp36-cp36m-win32.whl", hash = "sha256:3d875631ecab42f65f9dce6f55ce6d736696ced240f2634633188de2f5f21af9"},
|
||||
{file = "msgpack-1.0.3-cp36-cp36m-win_amd64.whl", hash = "sha256:40fb89b4625d12d6027a19f4df18a4de5c64f6f3314325049f219683e07e678a"},
|
||||
{file = "msgpack-1.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6eef0cf8db3857b2b556213d97dd82de76e28a6524853a9beb3264983391dc1a"},
|
||||
{file = "msgpack-1.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d8c332f53ffff01953ad25131272506500b14750c1d0ce8614b17d098252fbc"},
|
||||
{file = "msgpack-1.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c0903bd93cbd34653dd63bbfcb99d7539c372795201f39d16fdfde4418de43a"},
|
||||
{file = "msgpack-1.0.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bf1e6bfed4860d72106f4e0a1ab519546982b45689937b40257cfd820650b920"},
|
||||
{file = "msgpack-1.0.3-cp37-cp37m-win32.whl", hash = "sha256:d02cea2252abc3756b2ac31f781f7a98e89ff9759b2e7450a1c7a0d13302ff50"},
|
||||
{file = "msgpack-1.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:2f30dd0dc4dfe6231ad253b6f9f7128ac3202ae49edd3f10d311adc358772dba"},
|
||||
{file = "msgpack-1.0.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f201d34dc89342fabb2a10ed7c9a9aaaed9b7af0f16a5923f1ae562b31258dea"},
|
||||
{file = "msgpack-1.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bb87f23ae7d14b7b3c21009c4b1705ec107cb21ee71975992f6aca571fb4a42a"},
|
||||
{file = "msgpack-1.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a3a5c4b16e9d0edb823fe54b59b5660cc8d4782d7bf2c214cb4b91a1940a8ef"},
|
||||
{file = "msgpack-1.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f74da1e5fcf20ade12c6bf1baa17a2dc3604958922de8dc83cbe3eff22e8b611"},
|
||||
{file = "msgpack-1.0.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:73a80bd6eb6bcb338c1ec0da273f87420829c266379c8c82fa14c23fb586cfa1"},
|
||||
{file = "msgpack-1.0.3-cp38-cp38-win32.whl", hash = "sha256:9fce00156e79af37bb6db4e7587b30d11e7ac6a02cb5bac387f023808cd7d7f4"},
|
||||
{file = "msgpack-1.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:9b6f2d714c506e79cbead331de9aae6837c8dd36190d02da74cb409b36162e8a"},
|
||||
{file = "msgpack-1.0.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:89908aea5f46ee1474cc37fbc146677f8529ac99201bc2faf4ef8edc023c2bf3"},
|
||||
{file = "msgpack-1.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:973ad69fd7e31159eae8f580f3f707b718b61141838321c6fa4d891c4a2cca52"},
|
||||
{file = "msgpack-1.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da24375ab4c50e5b7486c115a3198d207954fe10aaa5708f7b65105df09109b2"},
|
||||
{file = "msgpack-1.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a598d0685e4ae07a0672b59792d2cc767d09d7a7f39fd9bd37ff84e060b1a996"},
|
||||
{file = "msgpack-1.0.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4c309a68cb5d6bbd0c50d5c71a25ae81f268c2dc675c6f4ea8ab2feec2ac4e2"},
|
||||
{file = "msgpack-1.0.3-cp39-cp39-win32.whl", hash = "sha256:494471d65b25a8751d19c83f1a482fd411d7ca7a3b9e17d25980a74075ba0e88"},
|
||||
{file = "msgpack-1.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:f01b26c2290cbd74316990ba84a14ac3d599af9cebefc543d241a66e785cf17d"},
|
||||
{file = "msgpack-1.0.3.tar.gz", hash = "sha256:51fdc7fb93615286428ee7758cecc2f374d5ff363bdd884c7ea622a7a327a81e"},
|
||||
{file = "msgpack-1.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4ab251d229d10498e9a2f3b1e68ef64cb393394ec477e3370c457f9430ce9250"},
|
||||
{file = "msgpack-1.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:112b0f93202d7c0fef0b7810d465fde23c746a2d482e1e2de2aafd2ce1492c88"},
|
||||
{file = "msgpack-1.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:002b5c72b6cd9b4bafd790f364b8480e859b4712e91f43014fe01e4f957b8467"},
|
||||
{file = "msgpack-1.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35bc0faa494b0f1d851fd29129b2575b2e26d41d177caacd4206d81502d4c6a6"},
|
||||
{file = "msgpack-1.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4733359808c56d5d7756628736061c432ded018e7a1dff2d35a02439043321aa"},
|
||||
{file = "msgpack-1.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb514ad14edf07a1dbe63761fd30f89ae79b42625731e1ccf5e1f1092950eaa6"},
|
||||
{file = "msgpack-1.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c23080fdeec4716aede32b4e0ef7e213c7b1093eede9ee010949f2a418ced6ba"},
|
||||
{file = "msgpack-1.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:49565b0e3d7896d9ea71d9095df15b7f75a035c49be733051c34762ca95bbf7e"},
|
||||
{file = "msgpack-1.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:aca0f1644d6b5a73eb3e74d4d64d5d8c6c3d577e753a04c9e9c87d07692c58db"},
|
||||
{file = "msgpack-1.0.4-cp310-cp310-win32.whl", hash = "sha256:0dfe3947db5fb9ce52aaea6ca28112a170db9eae75adf9339a1aec434dc954ef"},
|
||||
{file = "msgpack-1.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dea20515f660aa6b7e964433b1808d098dcfcabbebeaaad240d11f909298075"},
|
||||
{file = "msgpack-1.0.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e83f80a7fec1a62cf4e6c9a660e39c7f878f603737a0cdac8c13131d11d97f52"},
|
||||
{file = "msgpack-1.0.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c11a48cf5e59026ad7cb0dc29e29a01b5a66a3e333dc11c04f7e991fc5510a9"},
|
||||
{file = "msgpack-1.0.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1276e8f34e139aeff1c77a3cefb295598b504ac5314d32c8c3d54d24fadb94c9"},
|
||||
{file = "msgpack-1.0.4-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c9566f2c39ccced0a38d37c26cc3570983b97833c365a6044edef3574a00c08"},
|
||||
{file = "msgpack-1.0.4-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:fcb8a47f43acc113e24e910399376f7277cf8508b27e5b88499f053de6b115a8"},
|
||||
{file = "msgpack-1.0.4-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:76ee788122de3a68a02ed6f3a16bbcd97bc7c2e39bd4d94be2f1821e7c4a64e6"},
|
||||
{file = "msgpack-1.0.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:0a68d3ac0104e2d3510de90a1091720157c319ceeb90d74f7b5295a6bee51bae"},
|
||||
{file = "msgpack-1.0.4-cp36-cp36m-win32.whl", hash = "sha256:85f279d88d8e833ec015650fd15ae5eddce0791e1e8a59165318f371158efec6"},
|
||||
{file = "msgpack-1.0.4-cp36-cp36m-win_amd64.whl", hash = "sha256:c1683841cd4fa45ac427c18854c3ec3cd9b681694caf5bff04edb9387602d661"},
|
||||
{file = "msgpack-1.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a75dfb03f8b06f4ab093dafe3ddcc2d633259e6c3f74bb1b01996f5d8aa5868c"},
|
||||
{file = "msgpack-1.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9667bdfdf523c40d2511f0e98a6c9d3603be6b371ae9a238b7ef2dc4e7a427b0"},
|
||||
{file = "msgpack-1.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11184bc7e56fd74c00ead4f9cc9a3091d62ecb96e97653add7a879a14b003227"},
|
||||
{file = "msgpack-1.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac5bd7901487c4a1dd51a8c58f2632b15d838d07ceedaa5e4c080f7190925bff"},
|
||||
{file = "msgpack-1.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1e91d641d2bfe91ba4c52039adc5bccf27c335356055825c7f88742c8bb900dd"},
|
||||
{file = "msgpack-1.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2a2df1b55a78eb5f5b7d2a4bb221cd8363913830145fad05374a80bf0877cb1e"},
|
||||
{file = "msgpack-1.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:545e3cf0cf74f3e48b470f68ed19551ae6f9722814ea969305794645da091236"},
|
||||
{file = "msgpack-1.0.4-cp37-cp37m-win32.whl", hash = "sha256:2cc5ca2712ac0003bcb625c96368fd08a0f86bbc1a5578802512d87bc592fe44"},
|
||||
{file = "msgpack-1.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:eba96145051ccec0ec86611fe9cf693ce55f2a3ce89c06ed307de0e085730ec1"},
|
||||
{file = "msgpack-1.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7760f85956c415578c17edb39eed99f9181a48375b0d4a94076d84148cf67b2d"},
|
||||
{file = "msgpack-1.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:449e57cc1ff18d3b444eb554e44613cffcccb32805d16726a5494038c3b93dab"},
|
||||
{file = "msgpack-1.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d603de2b8d2ea3f3bcb2efe286849aa7a81531abc52d8454da12f46235092bcb"},
|
||||
{file = "msgpack-1.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f5d88c99f64c456413d74a975bd605a9b0526293218a3b77220a2c15458ba9"},
|
||||
{file = "msgpack-1.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6916c78f33602ecf0509cc40379271ba0f9ab572b066bd4bdafd7434dee4bc6e"},
|
||||
{file = "msgpack-1.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81fc7ba725464651190b196f3cd848e8553d4d510114a954681fd0b9c479d7e1"},
|
||||
{file = "msgpack-1.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d5b5b962221fa2c5d3a7f8133f9abffc114fe218eb4365e40f17732ade576c8e"},
|
||||
{file = "msgpack-1.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:77ccd2af37f3db0ea59fb280fa2165bf1b096510ba9fe0cc2bf8fa92a22fdb43"},
|
||||
{file = "msgpack-1.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b17be2478b622939e39b816e0aa8242611cc8d3583d1cd8ec31b249f04623243"},
|
||||
{file = "msgpack-1.0.4-cp38-cp38-win32.whl", hash = "sha256:2bb8cdf50dd623392fa75525cce44a65a12a00c98e1e37bf0fb08ddce2ff60d2"},
|
||||
{file = "msgpack-1.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:26b8feaca40a90cbe031b03d82b2898bf560027160d3eae1423f4a67654ec5d6"},
|
||||
{file = "msgpack-1.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:462497af5fd4e0edbb1559c352ad84f6c577ffbbb708566a0abaaa84acd9f3ae"},
|
||||
{file = "msgpack-1.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2999623886c5c02deefe156e8f869c3b0aaeba14bfc50aa2486a0415178fce55"},
|
||||
{file = "msgpack-1.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f0029245c51fd9473dc1aede1160b0a29f4a912e6b1dd353fa6d317085b219da"},
|
||||
{file = "msgpack-1.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed6f7b854a823ea44cf94919ba3f727e230da29feb4a99711433f25800cf747f"},
|
||||
{file = "msgpack-1.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0df96d6eaf45ceca04b3f3b4b111b86b33785683d682c655063ef8057d61fd92"},
|
||||
{file = "msgpack-1.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a4192b1ab40f8dca3f2877b70e63799d95c62c068c84dc028b40a6cb03ccd0f"},
|
||||
{file = "msgpack-1.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0e3590f9fb9f7fbc36df366267870e77269c03172d086fa76bb4eba8b2b46624"},
|
||||
{file = "msgpack-1.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:1576bd97527a93c44fa856770197dec00d223b0b9f36ef03f65bac60197cedf8"},
|
||||
{file = "msgpack-1.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:63e29d6e8c9ca22b21846234913c3466b7e4ee6e422f205a2988083de3b08cae"},
|
||||
{file = "msgpack-1.0.4-cp39-cp39-win32.whl", hash = "sha256:fb62ea4b62bfcb0b380d5680f9a4b3f9a2d166d9394e9bbd9666c0ee09a3645c"},
|
||||
{file = "msgpack-1.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:4d5834a2a48965a349da1c5a79760d94a1a0172fbb5ab6b5b33cbf8447e109ce"},
|
||||
{file = "msgpack-1.0.4.tar.gz", hash = "sha256:f5d869c18f030202eb412f08b28d2afeea553d6613aee89e200d7aca7ef01f5f"},
|
||||
]
|
||||
multidict = [
|
||||
{file = "multidict-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b9e95a740109c6047602f4db4da9949e6c5945cefbad34a1299775ddc9a62e2"},
|
||||
@@ -1372,10 +1342,6 @@ python-dateutil = [
|
||||
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
|
||||
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
|
||||
]
|
||||
pytkdocs = [
|
||||
{file = "pytkdocs-0.16.1-py3-none-any.whl", hash = "sha256:a8c3f46ecef0b92864cc598e9101e9c4cf832ebbf228f50c84aa5dd850aac379"},
|
||||
{file = "pytkdocs-0.16.1.tar.gz", hash = "sha256:e2ccf6dfe9dbbceb09818673f040f1a7c32ed0bffb2d709b06be6453c4026045"},
|
||||
]
|
||||
pyyaml = [
|
||||
{file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
|
||||
{file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"},
|
||||
|
||||
@@ -35,7 +35,7 @@ black = "^22.3.0"
|
||||
mypy = "^0.950"
|
||||
pytest-cov = "^2.12.1"
|
||||
mkdocs = "^1.3.0"
|
||||
mkdocstrings = {extras = ["python"], version = "^0.18.1"}
|
||||
mkdocstrings = {extras = ["python"], version = "^0.19.0"}
|
||||
mkdocs-material = "^8.2.15"
|
||||
pre-commit = "^2.13.0"
|
||||
pytest-aiohttp = "^1.0.4"
|
||||
|
||||
@@ -11,19 +11,21 @@
|
||||
scrollbar-background-hover: $panel-darken-3;
|
||||
scrollbar-color: $system;
|
||||
scrollbar-color-active: $accent-darken-1;
|
||||
scrollbar-size-horizontal: 1;
|
||||
scrollbar-size-vertical: 2;
|
||||
}
|
||||
|
||||
App > Screen {
|
||||
layout: dock;
|
||||
docks: side=left/1;
|
||||
background: $surface;
|
||||
color: $text-surface;
|
||||
color: $text-surface;
|
||||
}
|
||||
|
||||
|
||||
#sidebar {
|
||||
color: $text-primary;
|
||||
background: $primary;
|
||||
background: $primary-background;
|
||||
dock: side;
|
||||
width: 30;
|
||||
offset-x: -100%;
|
||||
@@ -37,7 +39,7 @@ App > Screen {
|
||||
|
||||
#sidebar .title {
|
||||
height: 3;
|
||||
background: $primary-darken-2;
|
||||
background: $primary-background-darken-2;
|
||||
color: $text-primary-darken-2 ;
|
||||
border-right: outer $primary-darken-3;
|
||||
content-align: center middle;
|
||||
@@ -45,16 +47,16 @@ App > Screen {
|
||||
|
||||
#sidebar .user {
|
||||
height: 8;
|
||||
background: $primary-darken-1;
|
||||
background: $primary-background-darken-1;
|
||||
color: $text-primary-darken-1;
|
||||
border-right: outer $primary-darken-3;
|
||||
border-right: outer $primary-background-darken-3;
|
||||
content-align: center middle;
|
||||
}
|
||||
|
||||
#sidebar .content {
|
||||
background: $primary;
|
||||
color: $text-primary;
|
||||
border-right: outer $primary-darken-3;
|
||||
background: $primary-background;
|
||||
color: $text-primary-background;
|
||||
border-right: outer $primary-background-darken-3;
|
||||
content-align: center middle;
|
||||
}
|
||||
|
||||
@@ -90,14 +92,6 @@ Tweet {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
Tweet.scrollbar-size-custom {
|
||||
scrollbar-size-vertical: 2;
|
||||
}
|
||||
|
||||
|
||||
Tweet.scroll-horizontal {
|
||||
scrollbar-size-horizontal: 2;
|
||||
}
|
||||
|
||||
.scrollable {
|
||||
width: 80;
|
||||
@@ -178,8 +172,8 @@ Tweet.scroll-horizontal TweetBody {
|
||||
|
||||
OptionItem {
|
||||
height: 3;
|
||||
background: $primary;
|
||||
border-right: outer $primary-darken-2;
|
||||
background: $primary-background;
|
||||
border-right: outer $primary-background-darken-2;
|
||||
border-left: blank;
|
||||
content-align: center middle;
|
||||
}
|
||||
@@ -187,7 +181,7 @@ OptionItem {
|
||||
OptionItem:hover {
|
||||
height: 3;
|
||||
color: $accent;
|
||||
background: $primary-darken-1;
|
||||
background: $primary-background-darken-1;
|
||||
/* border-top: hkey $accent2-darken-3;
|
||||
border-bottom: hkey $accent2-darken-3; */
|
||||
text-style: bold;
|
||||
|
||||
@@ -17,8 +17,6 @@ class Hr(Widget):
|
||||
|
||||
|
||||
class Info(Widget):
|
||||
DEFAULT_STYLES = "height: 2;"
|
||||
|
||||
def __init__(self, text: str) -> None:
|
||||
super().__init__()
|
||||
self.text = text
|
||||
|
||||
@@ -7,7 +7,7 @@ def format_svg(source, language, css_class, options, md, attrs, **kwargs):
|
||||
"""A superfences formatter to insert a SVG screenshot."""
|
||||
|
||||
os.environ["TEXTUAL"] = "headless"
|
||||
os.environ["TEXTUAL_SCREENSHOT"] = "0.1"
|
||||
os.environ["TEXTUAL_SCREENSHOT"] = "0.15"
|
||||
os.environ["COLUMNS"] = attrs.get("columns", "80")
|
||||
os.environ["LINES"] = attrs.get("lines", "24")
|
||||
path = attrs.get("path")
|
||||
|
||||
@@ -47,6 +47,7 @@ from ._context import active_app
|
||||
from ._event_broker import extract_handler_actions, NoHandler
|
||||
from .binding import Bindings, NoBinding
|
||||
from .css.stylesheet import Stylesheet
|
||||
from .css.styles import RenderStyles
|
||||
from .css.query import NoMatchingNodesError
|
||||
from .design import ColorSystem
|
||||
from .devtools.client import DevtoolsClient, DevtoolsConnectionError, DevtoolsLog
|
||||
@@ -60,6 +61,8 @@ from .layouts.dock import Dock
|
||||
from .message_pump import MessagePump
|
||||
from .reactive import Reactive
|
||||
from .renderables.blank import Blank
|
||||
from ._profile import timer
|
||||
|
||||
from .screen import Screen
|
||||
from .widget import Widget
|
||||
|
||||
@@ -108,6 +111,10 @@ class App(Generic[ReturnType], DOMNode):
|
||||
"""The base class for Textual Applications"""
|
||||
|
||||
CSS = """
|
||||
App {
|
||||
background: $surface;
|
||||
color: $text-surface;
|
||||
}
|
||||
"""
|
||||
|
||||
CSS_PATH: str | None = None
|
||||
@@ -139,6 +146,7 @@ class App(Generic[ReturnType], DOMNode):
|
||||
# this will create some first references to an asyncio loop.
|
||||
_init_uvloop()
|
||||
|
||||
super().__init__()
|
||||
self.features: frozenset[FeatureFlag] = parse_features(os.getenv("TEXTUAL", ""))
|
||||
|
||||
self.console = Console(
|
||||
@@ -201,10 +209,10 @@ class App(Generic[ReturnType], DOMNode):
|
||||
else None
|
||||
)
|
||||
|
||||
super().__init__()
|
||||
|
||||
def __init_subclass__(cls, css_path: str | None = None) -> None:
|
||||
super().__init_subclass__()
|
||||
def __init_subclass__(
|
||||
cls, css_path: str | None = None, inherit_css: bool = True
|
||||
) -> None:
|
||||
super().__init_subclass__(inherit_css=inherit_css)
|
||||
cls.CSS_PATH = css_path
|
||||
|
||||
title: Reactive[str] = Reactive("Textual")
|
||||
@@ -335,7 +343,15 @@ class App(Generic[ReturnType], DOMNode):
|
||||
|
||||
def watch_dark(self, dark: bool) -> None:
|
||||
"""Watches the dark bool."""
|
||||
|
||||
self.screen.dark = dark
|
||||
if dark:
|
||||
self.add_class("-dark-mode")
|
||||
self.remove_class("-light-mode")
|
||||
else:
|
||||
self.remove_class("-dark-mode")
|
||||
self.add_class("-light-mode")
|
||||
|
||||
self.refresh_css()
|
||||
|
||||
def get_driver_class(self) -> Type[Driver]:
|
||||
@@ -359,6 +375,18 @@ class App(Generic[ReturnType], DOMNode):
|
||||
|
||||
def __rich_repr__(self) -> rich.repr.Result:
|
||||
yield "title", self.title
|
||||
yield "id", self.id, None
|
||||
if self.name:
|
||||
yield "name", self.name
|
||||
if self.classes:
|
||||
yield "classes", set(self.classes)
|
||||
pseudo_classes = self.pseudo_classes
|
||||
if pseudo_classes:
|
||||
yield "pseudo_classes", set(pseudo_classes)
|
||||
|
||||
@property
|
||||
def is_transparent(self) -> bool:
|
||||
return True
|
||||
|
||||
@property
|
||||
def animator(self) -> Animator:
|
||||
@@ -368,10 +396,6 @@ class App(Generic[ReturnType], DOMNode):
|
||||
def screen(self) -> Screen:
|
||||
return self._screen_stack[-1]
|
||||
|
||||
@property
|
||||
def css_type(self) -> str:
|
||||
return "app"
|
||||
|
||||
@property
|
||||
def size(self) -> Size:
|
||||
return Size(*self.console.size)
|
||||
@@ -716,10 +740,8 @@ class App(Generic[ReturnType], DOMNode):
|
||||
try:
|
||||
if self.css_path is not None:
|
||||
self.stylesheet.read(self.css_path)
|
||||
if self.CSS is not None:
|
||||
self.stylesheet.add_source(
|
||||
self.CSS, path=f"<{self.__class__.__name__}>"
|
||||
)
|
||||
for path, css in self.css:
|
||||
self.stylesheet.add_source(css, path=path)
|
||||
except Exception as error:
|
||||
self.on_exception(error)
|
||||
self._print_error_renderables()
|
||||
@@ -736,8 +758,8 @@ class App(Generic[ReturnType], DOMNode):
|
||||
|
||||
driver = self._driver = self.driver_class(self.console, self)
|
||||
driver.start_application_mode()
|
||||
with redirect_stdout(StdoutRedirector(self.devtools, self._log_file)): # type: ignore
|
||||
try:
|
||||
try:
|
||||
with redirect_stdout(StdoutRedirector(self.devtools, self._log_file)): # type: ignore
|
||||
mount_event = events.Mount(sender=self)
|
||||
await self.dispatch_message(mount_event)
|
||||
|
||||
@@ -749,8 +771,8 @@ class App(Generic[ReturnType], DOMNode):
|
||||
await super().process_messages()
|
||||
await self.animator.stop()
|
||||
await self.close_all()
|
||||
finally:
|
||||
driver.stop_application_mode()
|
||||
finally:
|
||||
driver.stop_application_mode()
|
||||
except Exception as error:
|
||||
self.on_exception(error)
|
||||
finally:
|
||||
@@ -871,6 +893,7 @@ class App(Generic[ReturnType], DOMNode):
|
||||
|
||||
def refresh(self, *, repaint: bool = True, layout: bool = False) -> None:
|
||||
self.screen.refresh(repaint=repaint, layout=layout)
|
||||
self.check_idle()
|
||||
|
||||
def _paint(self):
|
||||
"""Perform a "paint" (draw the screen)."""
|
||||
@@ -886,7 +909,7 @@ class App(Generic[ReturnType], DOMNode):
|
||||
stylesheet.set_variables(self.get_css_variables())
|
||||
stylesheet.reparse()
|
||||
stylesheet.update(self.app, animate=animate)
|
||||
self.refresh(layout=True)
|
||||
self.screen._refresh_layout(self.size, full=True)
|
||||
|
||||
def _display(self, renderable: RenderableType | None) -> None:
|
||||
"""Display a renderable within a sync.
|
||||
|
||||
@@ -86,7 +86,7 @@ class Selector:
|
||||
return node.has_pseudo_class(*self.pseudo_classes)
|
||||
|
||||
def _check_type(self, node: DOMNode) -> bool:
|
||||
if node.css_type != self._name_lower:
|
||||
if self._name_lower not in node._css_type_names:
|
||||
return False
|
||||
if self.pseudo_classes and not node.has_pseudo_class(*self.pseudo_classes):
|
||||
return False
|
||||
|
||||
@@ -115,7 +115,7 @@ class StylesheetErrors:
|
||||
)
|
||||
|
||||
|
||||
@rich.repr.auto
|
||||
@rich.repr.auto(angular=True)
|
||||
class Stylesheet:
|
||||
def __init__(self, *, variables: dict[str, str] | None = None) -> None:
|
||||
self._rules: list[RuleSet] = []
|
||||
@@ -124,7 +124,7 @@ class Stylesheet:
|
||||
self._require_parse = False
|
||||
|
||||
def __rich_repr__(self) -> rich.repr.Result:
|
||||
yield self.rules
|
||||
yield list(self.source.keys())
|
||||
|
||||
@property
|
||||
def rules(self) -> list[RuleSet]:
|
||||
|
||||
@@ -188,6 +188,8 @@ class ColorSystem:
|
||||
COLORS = [
|
||||
("primary", primary),
|
||||
("secondary", secondary),
|
||||
("primary-background", primary),
|
||||
("secondary-background", secondary),
|
||||
("background", background),
|
||||
("panel", panel),
|
||||
("surface", surface),
|
||||
@@ -199,7 +201,7 @@ class ColorSystem:
|
||||
]
|
||||
|
||||
# Colors names that have a dark variant
|
||||
DARK_SHADES = {"primary", "secondary"}
|
||||
DARK_SHADES = {"primary-background", "secondary-background"}
|
||||
|
||||
for name, color in COLORS:
|
||||
is_dark_shade = dark and name in DARK_SHADES
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Iterable, Iterator, TYPE_CHECKING
|
||||
from inspect import getfile
|
||||
from typing import ClassVar, Iterable, Iterator, Type, TYPE_CHECKING
|
||||
|
||||
import rich.repr
|
||||
from rich.highlighter import ReprHighlighter
|
||||
@@ -38,8 +39,13 @@ class DOMNode(MessagePump):
|
||||
|
||||
"""
|
||||
|
||||
DEFAULT_STYLES = ""
|
||||
INLINE_STYLES = ""
|
||||
# Custom CSS
|
||||
CSS: ClassVar[str] = ""
|
||||
|
||||
# True if this node inherits the CSS from the base class.
|
||||
_inherit_css: ClassVar[bool] = True
|
||||
# List of names of base class (lower cased) that inherit CSS
|
||||
_css_type_names: ClassVar[frozenset[str]] = frozenset()
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -53,14 +59,51 @@ class DOMNode(MessagePump):
|
||||
self._classes: set[str] = set() if classes is None else set(classes.split())
|
||||
self.children = NodeList()
|
||||
self._css_styles: Styles = Styles(self)
|
||||
self._inline_styles: Styles = Styles.parse(
|
||||
self.INLINE_STYLES, repr(self), node=self
|
||||
)
|
||||
self._inline_styles: Styles = Styles(self)
|
||||
self.styles = RenderStyles(self, self._css_styles, self._inline_styles)
|
||||
self._default_styles = Styles()
|
||||
self._default_rules = self._default_styles.extract_rules((0, 0, 0))
|
||||
super().__init__()
|
||||
|
||||
def __init_subclass__(cls, inherit_css: bool = True) -> None:
|
||||
super().__init_subclass__()
|
||||
cls._inherit_css = inherit_css
|
||||
css_type_names: set[str] = set()
|
||||
for base in cls._css_bases(cls):
|
||||
css_type_names.add(base.__name__.lower())
|
||||
cls._css_type_names = frozenset(css_type_names)
|
||||
|
||||
@property
|
||||
def _node_bases(self) -> Iterator[Type[DOMNode]]:
|
||||
"""Get the DOMNode bases classes (including self.__class__)
|
||||
|
||||
Returns:
|
||||
Iterator[Type[DOMNode]]: An iterable of DOMNode classes.
|
||||
"""
|
||||
return self._css_bases(self.__class__)
|
||||
|
||||
@classmethod
|
||||
def _css_bases(cls, base: Type[DOMNode]) -> Iterator[Type[DOMNode]]:
|
||||
"""Get the DOMNode base classes, which inherit CSS.
|
||||
|
||||
Args:
|
||||
base (Type[DOMNode]): A DOMNode class
|
||||
|
||||
Returns:
|
||||
Iterator[Type[DOMNode]]: An iterable of DOMNode classes.
|
||||
"""
|
||||
_class = base
|
||||
while True:
|
||||
yield _class
|
||||
if not _class._inherit_css:
|
||||
break
|
||||
for _base in _class.__bases__:
|
||||
if issubclass(_base, DOMNode):
|
||||
_class = _base
|
||||
break
|
||||
else:
|
||||
break
|
||||
|
||||
def on_register(self, app: App) -> None:
|
||||
"""Called when the widget is registered
|
||||
|
||||
@@ -74,12 +117,37 @@ class DOMNode(MessagePump):
|
||||
if self._classes:
|
||||
yield "classes", " ".join(self._classes)
|
||||
|
||||
@property
|
||||
def css(self) -> list[tuple[str, str]]:
|
||||
"""Gets the CSS for this class and inherited from bases.
|
||||
|
||||
Returns:
|
||||
list[tuple[str, str]]: a list of tuples containing (PATH, SOURCE) for this
|
||||
and inherited from base classes.
|
||||
"""
|
||||
|
||||
css_stack: list[tuple[str, str]] = []
|
||||
|
||||
def get_path(base: Type[DOMNode]) -> str:
|
||||
"""Get a path to the DOM Node"""
|
||||
try:
|
||||
return f"{getfile(base)}:{base.__name__}"
|
||||
except TypeError:
|
||||
return f"{base.__name__}"
|
||||
|
||||
for base in self._node_bases:
|
||||
css = base.CSS.strip()
|
||||
if css:
|
||||
css_stack.append((get_path(base), css))
|
||||
|
||||
return css_stack
|
||||
|
||||
@property
|
||||
def parent(self) -> DOMNode | None:
|
||||
"""Get the parent node.
|
||||
|
||||
Returns:
|
||||
DOMNode: The node which is the direct parent of this node.
|
||||
DOMNode | None: The node which is the direct parent of this node.
|
||||
"""
|
||||
return self._parent
|
||||
|
||||
@@ -158,15 +226,6 @@ class DOMNode(MessagePump):
|
||||
pseudo_classes = frozenset({*self.get_pseudo_classes()})
|
||||
return pseudo_classes
|
||||
|
||||
@property
|
||||
def css_type(self) -> str:
|
||||
"""Gets the CSS type, used by the CSS.
|
||||
|
||||
Returns:
|
||||
str: A type used in CSS (lower cased class name).
|
||||
"""
|
||||
return self.__class__.__name__.lower()
|
||||
|
||||
@property
|
||||
def css_path_nodes(self) -> list[DOMNode]:
|
||||
"""A list of nodes from the root to this node, forming a "path".
|
||||
@@ -238,20 +297,29 @@ class DOMNode(MessagePump):
|
||||
from rich.console import Group
|
||||
from rich.panel import Panel
|
||||
|
||||
highlighter = ReprHighlighter()
|
||||
tree = Tree(highlighter(repr(self)))
|
||||
from .widget import Widget
|
||||
|
||||
def add_children(tree, node):
|
||||
for child in node.children:
|
||||
def render_info(node: DOMNode) -> Columns:
|
||||
if isinstance(node, Widget):
|
||||
info = Columns(
|
||||
[
|
||||
Pretty(child),
|
||||
highlighter(f"region={child.region!r}"),
|
||||
Pretty(node),
|
||||
highlighter(f"region={node.region!r}"),
|
||||
highlighter(
|
||||
f"virtual_size={child.virtual_size!r}",
|
||||
f"virtual_size={node.virtual_size!r}",
|
||||
),
|
||||
]
|
||||
)
|
||||
else:
|
||||
info = Columns([Pretty(node)])
|
||||
return info
|
||||
|
||||
highlighter = ReprHighlighter()
|
||||
tree = Tree(render_info(self))
|
||||
|
||||
def add_children(tree, node):
|
||||
for child in node.children:
|
||||
info = render_info(child)
|
||||
css = child.styles.css
|
||||
if css:
|
||||
info = Group(
|
||||
@@ -464,7 +532,6 @@ class DOMNode(MessagePump):
|
||||
self._classes.update(class_names)
|
||||
try:
|
||||
self.app.stylesheet.update(self.app, animate=True)
|
||||
self.refresh()
|
||||
except NoActiveAppError:
|
||||
pass
|
||||
|
||||
@@ -478,7 +545,6 @@ class DOMNode(MessagePump):
|
||||
self._classes.difference_update(class_names)
|
||||
try:
|
||||
self.app.stylesheet.update(self.app, animate=True)
|
||||
self.refresh()
|
||||
except NoActiveAppError:
|
||||
pass
|
||||
|
||||
@@ -492,7 +558,6 @@ class DOMNode(MessagePump):
|
||||
self._classes.symmetric_difference_update(class_names)
|
||||
try:
|
||||
self.app.stylesheet.update(self.app, animate=True)
|
||||
self.refresh()
|
||||
except NoActiveAppError:
|
||||
pass
|
||||
|
||||
|
||||
@@ -160,10 +160,10 @@ class LinuxDriver(Driver):
|
||||
if not self.exit_event.is_set():
|
||||
signal.signal(signal.SIGWINCH, signal.SIG_DFL)
|
||||
self._disable_mouse_support()
|
||||
termios.tcflush(self.fileno, termios.TCIFLUSH)
|
||||
self.exit_event.set()
|
||||
if self._key_thread is not None:
|
||||
self._key_thread.join()
|
||||
termios.tcflush(self.fileno, termios.TCIFLUSH)
|
||||
except Exception as error:
|
||||
# TODO: log this
|
||||
pass
|
||||
@@ -207,7 +207,6 @@ class LinuxDriver(Driver):
|
||||
utf8_decoder = getincrementaldecoder("utf-8")().decode
|
||||
decode = utf8_decoder
|
||||
read = os.read
|
||||
|
||||
EVENT_READ = selectors.EVENT_READ
|
||||
|
||||
try:
|
||||
|
||||
@@ -303,7 +303,7 @@ class Region(NamedTuple):
|
||||
"""Get the maxima and minima of region.
|
||||
|
||||
Returns:
|
||||
tuple[int, int, int, int]: A tuple of (<min x>, <max x>, <min y>, <max y>)
|
||||
tuple[int, int, int, int]: A tuple of `(<min x>, <max x>, <min y>, <max y>)`
|
||||
"""
|
||||
x, y, width, height = self
|
||||
return x, y, x + width, y + height
|
||||
@@ -527,6 +527,7 @@ class Region(NamedTuple):
|
||||
def split(self, cut_x: int, cut_y: int) -> tuple[Region, Region, Region, Region]:
|
||||
"""Split a region in to 4 from given x and y offsets (cuts).
|
||||
|
||||
```
|
||||
cut_x ↓
|
||||
┌────────┐┌───┐
|
||||
│ ││ │
|
||||
@@ -536,6 +537,7 @@ class Region(NamedTuple):
|
||||
┌────────┐┌───┐
|
||||
│ 2 ││ 3 │
|
||||
└────────┘└───┘
|
||||
```
|
||||
|
||||
Args:
|
||||
cut_x (int): Offset from self.x where the cut should be made. If negative, the cut
|
||||
@@ -564,11 +566,13 @@ class Region(NamedTuple):
|
||||
def split_vertical(self, cut: int) -> tuple[Region, Region]:
|
||||
"""Split a region in to two, from a given x offset.
|
||||
|
||||
```
|
||||
cut ↓
|
||||
┌────────┐┌───┐
|
||||
│ 0 ││ 1 │
|
||||
│ ││ │
|
||||
└────────┘└───┘
|
||||
```
|
||||
|
||||
Args:
|
||||
cut (int): An offset from self.x where the cut should be made. If cut is negative,
|
||||
@@ -590,6 +594,7 @@ class Region(NamedTuple):
|
||||
def split_horizontal(self, cut: int) -> tuple[Region, Region]:
|
||||
"""Split a region in to two, from a given x offset.
|
||||
|
||||
```
|
||||
┌─────────┐
|
||||
│ 0 │
|
||||
│ │
|
||||
@@ -597,6 +602,7 @@ class Region(NamedTuple):
|
||||
┌─────────┐
|
||||
│ 1 │
|
||||
└─────────┘
|
||||
```
|
||||
|
||||
Args:
|
||||
cut (int): An offset from self.x where the cut should be made. May be negative,
|
||||
|
||||
@@ -5,7 +5,7 @@ import inspect
|
||||
from asyncio import CancelledError
|
||||
from asyncio import PriorityQueue, QueueEmpty, Task
|
||||
from functools import partial, total_ordering
|
||||
from typing import TYPE_CHECKING, Awaitable, Iterable, Callable, NamedTuple
|
||||
from typing import TYPE_CHECKING, Awaitable, Iterable, Callable
|
||||
from weakref import WeakSet
|
||||
|
||||
from . import events
|
||||
@@ -268,6 +268,7 @@ class MessagePump:
|
||||
self.app.on_exception(error)
|
||||
break
|
||||
finally:
|
||||
self._message_queue.task_done()
|
||||
if self._message_queue.empty():
|
||||
if not self._closed:
|
||||
event = events.Idle(self)
|
||||
|
||||
@@ -30,7 +30,7 @@ class Screen(Widget):
|
||||
"""A widget for the root of the app."""
|
||||
|
||||
CSS = """
|
||||
Screen {
|
||||
Screen {
|
||||
layout: vertical;
|
||||
overflow-y: auto;
|
||||
}
|
||||
@@ -112,20 +112,19 @@ class Screen(Widget):
|
||||
def on_idle(self, event: events.Idle) -> None:
|
||||
# Check for any widgets marked as 'dirty' (needs a repaint)
|
||||
event.prevent_default()
|
||||
|
||||
if self._layout_required:
|
||||
self._refresh_layout()
|
||||
self._layout_required = False
|
||||
self._dirty_widgets.clear()
|
||||
elif self._dirty_widgets:
|
||||
elif self._dirty_widgets or self._dirty_regions:
|
||||
self.update_timer.resume()
|
||||
|
||||
def _on_update(self) -> None:
|
||||
"""Called by the _update_timer."""
|
||||
# Render widgets together
|
||||
|
||||
if self._dirty_widgets:
|
||||
if self._dirty_widgets or self._dirty_regions:
|
||||
self._compositor.update_widgets(self._dirty_widgets)
|
||||
self._compositor.add_dirty_regions(self._dirty_regions)
|
||||
self.app._display(self._compositor.render())
|
||||
self._dirty_widgets.clear()
|
||||
self.update_timer.pause()
|
||||
|
||||
@@ -22,7 +22,6 @@ from . import errors
|
||||
from . import events
|
||||
from ._animator import BoundAnimator
|
||||
from ._border import Border
|
||||
from ._profile import timer
|
||||
from .box_model import BoxModel, get_box_model
|
||||
from ._context import active_app
|
||||
from ._types import Lines
|
||||
@@ -34,7 +33,6 @@ from .message import Message
|
||||
from . import messages
|
||||
from ._layout import Layout
|
||||
from .reactive import Reactive, watch
|
||||
from .renderables.blank import Blank
|
||||
from .renderables.opacity import Opacity
|
||||
from .renderables.tint import Tint
|
||||
|
||||
@@ -69,9 +67,6 @@ class RenderCache(NamedTuple):
|
||||
@rich.repr.auto
|
||||
class Widget(DOMNode):
|
||||
|
||||
CSS = """
|
||||
"""
|
||||
|
||||
can_focus: bool = False
|
||||
can_focus_children: bool = True
|
||||
|
||||
@@ -179,10 +174,9 @@ class Widget(DOMNode):
|
||||
Args:
|
||||
app (App): App instance.
|
||||
"""
|
||||
# Parser the Widget's CSS
|
||||
self.app.stylesheet.add_source(
|
||||
self.CSS, f"{__file__}:<{self.__class__.__name__}>"
|
||||
)
|
||||
# Parse the Widget's CSS
|
||||
for path, css in self.css:
|
||||
self.app.stylesheet.add_source(css, path=path)
|
||||
|
||||
def get_box_model(
|
||||
self, container: Size, viewport: Size, fraction_unit: Fraction
|
||||
@@ -539,12 +533,16 @@ class Widget(DOMNode):
|
||||
|
||||
def scroll_page_left(self, *, animate: bool = True) -> bool:
|
||||
return self.scroll_to(
|
||||
x=self.scroll_target_x - self.container_size.width, animate=animate
|
||||
x=self.scroll_target_x - self.container_size.width,
|
||||
animate=animate,
|
||||
duration=0.3,
|
||||
)
|
||||
|
||||
def scroll_page_right(self, *, animate: bool = True) -> bool:
|
||||
return self.scroll_to(
|
||||
x=self.scroll_target_x + self.container_size.width, animate=animate
|
||||
x=self.scroll_target_x + self.container_size.width,
|
||||
animate=animate,
|
||||
duration=0.3,
|
||||
)
|
||||
|
||||
def scroll_to_widget(self, widget: Widget, *, animate: bool = True) -> bool:
|
||||
@@ -592,9 +590,12 @@ class Widget(DOMNode):
|
||||
)
|
||||
|
||||
def __init_subclass__(
|
||||
cls, can_focus: bool = True, can_focus_children: bool = True
|
||||
cls,
|
||||
can_focus: bool = True,
|
||||
can_focus_children: bool = True,
|
||||
inherit_css: bool = True,
|
||||
) -> None:
|
||||
super().__init_subclass__()
|
||||
super().__init_subclass__(inherit_css=inherit_css)
|
||||
cls.can_focus = can_focus
|
||||
cls.can_focus_children = can_focus_children
|
||||
|
||||
@@ -1038,8 +1039,8 @@ class Widget(DOMNode):
|
||||
event.stop()
|
||||
|
||||
def handle_scroll_to(self, message: ScrollTo) -> None:
|
||||
if self.is_scrollable:
|
||||
self.scroll_to(message.x, message.y, animate=message.animate)
|
||||
if self.is_container:
|
||||
self.scroll_to(message.x, message.y, animate=message.animate, duration=0.1)
|
||||
message.stop()
|
||||
|
||||
def handle_scroll_up(self, event: ScrollUp) -> None:
|
||||
|
||||
@@ -17,18 +17,31 @@ class Button(Widget, can_focus=True):
|
||||
|
||||
CSS = """
|
||||
|
||||
|
||||
Button {
|
||||
width: auto;
|
||||
height: 3;
|
||||
padding: 0 2;
|
||||
background: $primary;
|
||||
color: $text-primary;
|
||||
content-align: center middle;
|
||||
border: tall $primary-lighten-3;
|
||||
|
||||
margin: 1 0;
|
||||
align: center middle;
|
||||
text-style: bold;
|
||||
}
|
||||
|
||||
.-dark-mode Button {
|
||||
border: tall white $primary-lighten-2;
|
||||
color: $primary-lighten-2;
|
||||
background: $background;
|
||||
}
|
||||
|
||||
.-dark-mode Button:hover {
|
||||
background: $surface;
|
||||
}
|
||||
|
||||
|
||||
Button:hover {
|
||||
background:$primary-darken-2;
|
||||
color: $text-primary-darken-2;
|
||||
|
||||
@@ -191,8 +191,6 @@ class Tabs(Widget):
|
||||
that character.
|
||||
"""
|
||||
|
||||
DEFAULT_STYLES = "height: 2;"
|
||||
|
||||
_active_tab_name: Reactive[str | None] = Reactive("")
|
||||
_bar_offset: Reactive[float] = Reactive(0.0)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user