mirror of
https://github.com/Textualize/rich.git
synced 2025-07-07 12:54:59 +00:00
Merge branch 'master' into fix-panel-fix-title-missing-panel-background
This commit is contained in:
commit
6b8b3fa281
56 changed files with 527 additions and 384 deletions
|
@ -17,4 +17,6 @@ Thank you for your issue. Give us a little time to review it.
|
|||
PS. You might want to check the [FAQ]({{ faq_url }}) if you haven't done so already.
|
||||
{%- endif %}
|
||||
|
||||
Rich was created by Will McGugan. Consider [sponsoring Will's work on Rich](https://github.com/sponsors/willmcgugan).
|
||||
|
||||
This is an automated reply, generated by [FAQtory](https://github.com/willmcgugan/faqtory)
|
||||
|
|
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
|
@ -1,2 +1,3 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
github: willmcgugan
|
||||
|
|
15
.github/pull_request_template.md
vendored
15
.github/pull_request_template.md
vendored
|
@ -1,3 +1,18 @@
|
|||
|
||||
<!--
|
||||
Please note that Rich isn't accepting any new features at this point.
|
||||
|
||||
If a feature can be implemented without modifying the core library, then
|
||||
they should be released as a third-party module. I can accept updates to the
|
||||
core library that make it easier to extend (think hooks).
|
||||
|
||||
Bugfixes are always welcome of course.
|
||||
|
||||
Sometimes it is not clear what is a feature and what is a bug fix.
|
||||
If there is any doubt, please open a discussion first.
|
||||
|
||||
-->
|
||||
|
||||
## Type of changes
|
||||
|
||||
- [ ] Bug fix
|
||||
|
|
8
.github/workflows/comment.yml
vendored
8
.github/workflows/comment.yml
vendored
|
@ -13,7 +13,11 @@ jobs:
|
|||
with:
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
body: |
|
||||
I hope we solved your problem.
|
||||
I hope I helped!
|
||||
|
||||
If you like using Rich, you might also enjoy [Textual](https://textual.textualize.io)
|
||||
Consider [sponsoring](https://github.com/sponsors/willmcgugan) my work on Rich. I give tech support for free, in addition to maintaining Rich and Textual.
|
||||
|
||||
If you like using Rich, you might also enjoy [Textual](https://textual.textualize.io).
|
||||
|
||||
Will McGugan
|
||||
|
||||
|
|
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -5,12 +5,25 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
|
||||
- Removed `typing_extensions` from runtime dependencies https://github.com/Textualize/rich/pull/3763
|
||||
- Live objects (including Progress) may now be nested https://github.com/Textualize/rich/pull/3768
|
||||
- Added padding property to Syntax which returns a tuple of four integers https://github.com/Textualize/rich/pull/3782
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed extraction of recursive exceptions https://github.com/Textualize/rich/pull/3772
|
||||
- Fixed padding applied to Syntax https://github.com/Textualize/rich/pull/3782
|
||||
- Fixed `Panel` title missing the panel background style https://github.com/Textualize/rich/issues/3569
|
||||
|
||||
### Added
|
||||
|
||||
- Added `TTY_INTERACTIVE` environment variable to force interactive mode off or on https://github.com/Textualize/rich/pull/3777
|
||||
|
||||
## [14.0.0] - 2025-03-30
|
||||
|
||||
### Added
|
||||
|
|
|
@ -67,6 +67,7 @@ The following people have contributed to the development of Rich:
|
|||
- [Louis Sautier](https://github.com/sbraz)
|
||||
- [Tim Savage](https://github.com/timsavage)
|
||||
- [Anthony Shaw](https://github.com/tonybaloney)
|
||||
- [Damian Shaw](https://github.com/notatallshaw)
|
||||
- [Nicolas Simonds](https://github.com/0xDEC0DE)
|
||||
- [Aaron Stephens](https://github.com/aaronst)
|
||||
- [Karolina Surma](https://github.com/befeleme)
|
||||
|
@ -92,3 +93,4 @@ The following people have contributed to the development of Rich:
|
|||
- [chthollyphile](https://github.com/chthollyphile)
|
||||
- [Jonathan Helmus](https://github.com/jjhelmus)
|
||||
- [Brandon Capener](https://github.com/bcapener)
|
||||
- [Alex Zheng](https://github.com/alexzheng111)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
|
||||
[](https://pepy.tech/project/rich)
|
||||
[](https://badge.fury.io/py/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://www.willmcgugan.com/tag/rich/)
|
||||
[](https://twitter.com/willmcgugan)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
|
||||
[](https://pepy.tech/project/rich)
|
||||
[](https://badge.fury.io/py/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://www.willmcgugan.com/tag/rich/)
|
||||
[](https://twitter.com/willmcgugan)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
|
||||
[](https://pepy.tech/project/rich)
|
||||
[](https://badge.fury.io/py/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://www.willmcgugan.com/tag/rich/)
|
||||
[](https://twitter.com/willmcgugan)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
|
||||
[](https://pepy.tech/project/rich)
|
||||
[](https://badge.fury.io/py/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://www.willmcgugan.com/tag/rich/)
|
||||
[](https://twitter.com/willmcgugan)
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
|
||||
[](https://pepy.tech/project/rich)
|
||||
[](https://codecov.io/gh/textualize/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://www.willmcgugan.com/tag/rich/)
|
||||
[](https://twitter.com/willmcgugan)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
|
||||
[](https://pepy.tech/project/rich)
|
||||
[](https://badge.fury.io/py/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://www.willmcgugan.com/tag/rich/)
|
||||
[](https://twitter.com/willmcgugan)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
|
||||
[](https://pepy.tech/project/rich)
|
||||
[](https://badge.fury.io/py/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://www.willmcgugan.com/tag/rich/)
|
||||
[](https://twitter.com/willmcgugan)
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
|
||||
[](https://pepy.tech/project/rich)
|
||||
[](https://codecov.io/gh/textualize/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://www.willmcgugan.com/tag/rich/)
|
||||
[](https://twitter.com/willmcgugan)
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
|
||||
[](https://pepy.tech/project/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://www.willmcgugan.com/tag/rich/)
|
||||
[](https://twitter.com/willmcgugan)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
|
||||
[](https://pepy.tech/project/rich)
|
||||
[](https://badge.fury.io/py/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://www.willmcgugan.com/tag/rich/)
|
||||
[](https://twitter.com/willmcgugan)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
|
||||
[](https://pepy.tech/project/rich)
|
||||
[](https://badge.fury.io/py/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://www.willmcgugan.com/tag/rich/)
|
||||
[](https://twitter.com/willmcgugan)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
|
||||
[](https://pepy.tech/project/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
|
@ -436,4 +436,4 @@ See also [Rich CLI](https://github.com/textualize/rich-cli) for a command line a
|
|||
|
||||
See also Rich's sister project, [Textual](https://github.com/Textualize/textual), which you can use to build sophisticated User Interfaces in the terminal.
|
||||
|
||||

|
||||

|
||||
|
|
18
README.pl.md
18
README.pl.md
|
@ -1,4 +1,4 @@
|
|||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
|
||||
[](https://pepy.tech/project/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
|
@ -82,7 +82,7 @@ Rich może zostać zainstalowany w REPL, żeby wszystkie struktury danych były
|
|||
|
||||
## Używanie konsoli
|
||||
|
||||
Dla większej kontroli nad bogatą zawartością terminala, zaimportuj i skonstruuj objekt [Console](https://rich.readthedocs.io/en/latest/reference/console.html#rich.console.Console).
|
||||
Dla większej kontroli nad bogatą zawartością terminala, zaimportuj i skonstruuj obiekt [Console](https://rich.readthedocs.io/en/latest/reference/console.html#rich.console.Console).
|
||||
|
||||
```python
|
||||
from rich.console import Console
|
||||
|
@ -90,7 +90,7 @@ from rich.console import Console
|
|||
console = Console()
|
||||
```
|
||||
|
||||
Objekt Console ma metodę `print`, mającą celowo podobny interfejs do wbudowanej funkcji `print`. Tu jest przykład użycia:
|
||||
Obiekt Console ma metodę `print`, mającą celowo podobny interfejs do wbudowanej funkcji `print`. Tu jest przykład użycia:
|
||||
|
||||
```python
|
||||
console.print("Hello", "World!")
|
||||
|
@ -116,11 +116,11 @@ console.print("Where there is a [bold cyan]Will[/bold cyan] there [u]is[/u] a [i
|
|||
|
||||

|
||||
|
||||
Możesz użyć objektu Console, aby wygenerować skomplikowane wyjście bez problemu. Więcej informacji odnośnie Console API w [dokumentacji](https://rich.readthedocs.io/en/latest/console.html).
|
||||
Możesz użyć obiektu Console, aby wygenerować skomplikowane wyjście bez problemu. Więcej informacji odnośnie Console API w [dokumentacji](https://rich.readthedocs.io/en/latest/console.html).
|
||||
|
||||
## Rich Inspect
|
||||
|
||||
Rich ma funkcję [inspect](https://rich.readthedocs.io/en/latest/reference/init.html?highlight=inspect#rich.inspect), która może produkować raporty na jakimkolwiek objekcie Python, jak np. klasa, instancja, lub wbudowana funkcja.
|
||||
Rich ma funkcję [inspect](https://rich.readthedocs.io/en/latest/reference/init.html?highlight=inspect#rich.inspect), która może produkować raporty na jakimkolwiek obiekcie Python, jak np. klasa, instancja, lub wbudowana funkcja.
|
||||
|
||||
```python
|
||||
>>> my_list = ["foo", "bar"]
|
||||
|
@ -141,7 +141,7 @@ Kliknij poniższe nagłówki, żeby poznać detale:
|
|||
<details>
|
||||
<summary>Log</summary>
|
||||
|
||||
Objekt Console ma metodę `log()`, mającą podobny interfejs do `print()`, ale wyświetla również kolumnę zawierającą aktualny czas oraz plik i linijkę, która wywołała powyższą metodę. Domyślnie Rich podświetla składnię dla struktur Pythona i ciągów repr. Jeśli zlogujesz kolekcję (czyli listę `list` lub słownik `dict`), Rich ją ładnie wypisze tak, żeby zmieściła się w dostępnym miejscu. Poniżej znajduje się przykład tych funkcji.
|
||||
Obiekt Console ma metodę `log()`, mającą podobny interfejs do `print()`, ale wyświetla również kolumnę zawierającą aktualny czas oraz plik i linijkę, która wywołała powyższą metodę. Domyślnie Rich podświetla składnię dla struktur Pythona i ciągów repr. Jeśli zlogujesz kolekcję (czyli listę `list` lub słownik `dict`), Rich ją ładnie wypisze tak, żeby zmieściła się w dostępnym miejscu. Poniżej znajduje się przykład tych funkcji.
|
||||
|
||||
```python
|
||||
from rich.console import Console
|
||||
|
@ -170,7 +170,7 @@ Powyższy kod wyświetla poniższy tekst:
|
|||
|
||||

|
||||
|
||||
Istnieje argument `log_locals`, który wyświetla tabelę zawierającą zmienne lokalne z kąd wywołano metodę log.
|
||||
Istnieje argument `log_locals`, który wyświetla tabelę zawierającą zmienne lokalne skąd wywołano metodę log.
|
||||
|
||||
Metoda log może być używana do logowania do terminala dla długo działających aplikacji takich jak serwery, ale jest również bardzo dobrą pomocą w debugowaniu.
|
||||
|
||||
|
@ -178,7 +178,7 @@ Metoda log może być używana do logowania do terminala dla długo działający
|
|||
<details>
|
||||
<summary>Handler Logów</summary>
|
||||
|
||||
Możesz także użyć wbudowanej [klasy Handler](https://rich.readthedocs.io/en/latest/logging.html), aby zformatować i pokolorować wyjście z modułu logging Pythona. Przykład poniżej:
|
||||
Możesz także użyć wbudowanej [klasy Handler](https://rich.readthedocs.io/en/latest/logging.html), aby sformatować i pokolorować wyjście z modułu logging Pythona. Przykład poniżej:
|
||||
|
||||

|
||||
|
||||
|
@ -379,7 +379,7 @@ Ten kod wyświetli tekst w stylu:
|
|||
<details>
|
||||
<summary>Podświetlanie kodu źródłowego</summary>
|
||||
|
||||
Rich używa biblioteki [pygments](https://pygments.org/), żeby zaimplementować [podświetlanie kodu źródłowego](https://rich.readthedocs.io/en/latest/syntax.html). Użycie jest podobne do renderowania markdownu; skonstruuj objekt `Syntax` i wydrukuj go do konsoli. Przykład poniżej:
|
||||
Rich używa biblioteki [pygments](https://pygments.org/), żeby zaimplementować [podświetlanie kodu źródłowego](https://rich.readthedocs.io/en/latest/syntax.html). Użycie jest podobne do renderowania markdownu; skonstruuj obiekt `Syntax` i wydrukuj go do konsoli. Przykład poniżej:
|
||||
|
||||
```python
|
||||
from rich.console import Console
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
|
||||
[](https://pepy.tech/project/rich)
|
||||
[](https://badge.fury.io/py/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://www.willmcgugan.com/tag/rich/)
|
||||
[](https://twitter.com/willmcgugan)
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
|
||||
[](https://pepy.tech/project/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://www.willmcgugan.com/tag/rich/)
|
||||
[](https://twitter.com/willmcgugan)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
|
||||
[](https://pepy.tech/project/rich)
|
||||
[](https://badge.fury.io/py/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://www.willmcgugan.com/tag/rich/)
|
||||
[](https://twitter.com/willmcgugan)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
|
||||
[](https://pepy.tech/project/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[](https://pypi.org/project/rich/) [](https://badge.fury.io/py/rich)
|
||||
|
||||
[](https://pepy.tech/project/rich)
|
||||
[](https://badge.fury.io/py/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://codecov.io/gh/Textualize/rich)
|
||||
[](https://www.willmcgugan.com/tag/rich/)
|
||||
[](https://twitter.com/willmcgugan)
|
||||
|
||||
|
|
|
@ -17,14 +17,8 @@
|
|||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
import sys
|
||||
|
||||
import sphinx_rtd_theme
|
||||
|
||||
if sys.version_info >= (3, 8):
|
||||
from importlib.metadata import Distribution
|
||||
else:
|
||||
from importlib_metadata import Distribution
|
||||
from importlib.metadata import Distribution
|
||||
|
||||
html_theme = "sphinx_rtd_theme"
|
||||
|
||||
|
@ -50,6 +44,7 @@ extensions = [
|
|||
"sphinx.ext.intersphinx",
|
||||
"sphinx.ext.autosectionlabel",
|
||||
"sphinx_copybutton",
|
||||
"sphinx_rtd_theme",
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
|
|
|
@ -405,13 +405,13 @@ If Rich detects that it is not writing to a terminal it will strip control codes
|
|||
|
||||
Letting Rich auto-detect terminals is useful as it will write plain text when you pipe output to a file or other application.
|
||||
|
||||
.. _interactive_mode:
|
||||
|
||||
Interactive mode
|
||||
----------------
|
||||
|
||||
Rich will remove animations such as progress bars and status indicators when not writing to a terminal as you probably don't want to write these out to a text file (for example). You can override this behavior by setting the ``force_interactive`` argument on the constructor. Set it to True to enable animations or False to disable them.
|
||||
Rich will remove animations such as progress bars and status indicators when not writing to a terminal as you probably don't want to write these out to a text file (for example). You can override this behavior by setting the ``force_interactive`` argument on the constructor. Set it to ``True`` to enable animations or ``False`` to disable them.
|
||||
|
||||
.. note::
|
||||
Some CI systems support ANSI color and style but not anything that moves the cursor or selectively refreshes parts of the terminal. For these you might want to set ``force_terminal`` to ``True`` and ``force_interactive`` to ``False``.
|
||||
|
||||
Environment variables
|
||||
---------------------
|
||||
|
@ -429,8 +429,11 @@ If the environment variable ``NO_COLOR`` is set, Rich will disable all color in
|
|||
|
||||
The environment variable ``TTY_COMPATIBLE`` is used to override Rich's auto-detection of terminal support. If ``TTY_COMPATIBLE`` is set to ``1`` then Rich will assume it is writing to a device which can handle escape sequences like a terminal. If ``TTY_COMPATIBLE`` is set to ``"0"``, then Rich will assume that it is writing to a device that is *not* capable of displaying escape sequences (such as a regular file). If the variable is not set, or set to a value other than "0" or "1", then Rich will attempt to auto-detect terminal support.
|
||||
|
||||
The environment variable ``TTY_INTERACTIVE`` is used to override Rich's auto-detection of :ref:`interactive_mode`. If you set this to ``"0"``, it will disable interactive mode even if Rich thinks it is writing to a terminal. Set this to ``"1"`` to force interactive mode on. If this environment variable is not set, or set to any other value, then interactive mode will be auto-detected as normal.
|
||||
|
||||
.. note::
|
||||
If you want Rich output in CI or Github Actions, then you should set ``TTY_COMPATIBLE=1``.
|
||||
If you want Rich output in CI or Github Actions, then you should set ``TTY_COMPATIBLE=1`` and ``TTY_INTERACTIVE=0``. The combination of both these variables tells rich that it can output escape sequences,
|
||||
and also that there is no user interacting with the terminal -- so it won't bother animating progress bars.
|
||||
|
||||
If ``width`` / ``height`` arguments are not explicitly provided as arguments to ``Console`` then the environment variables ``COLUMNS`` / ``LINES`` can be used to set the console width / height. ``JUPYTER_COLUMNS`` / ``JUPYTER_LINES`` behave similarly and are used in Jupyter.
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ Rich works with macOS, Linux and Windows.
|
|||
|
||||
On Windows both the (ancient) cmd.exe terminal is supported and the new `Windows Terminal <https://github.com/microsoft/terminal/releases>`_. The latter has much improved support for color and style.
|
||||
|
||||
Rich requires Python 3.7.0 and above.
|
||||
Rich requires Python 3.8.0 and above.
|
||||
|
||||
.. note::
|
||||
PyCharm users will need to enable "emulate terminal" in output console option in run/debug configuration to see styled output.
|
||||
|
@ -30,6 +30,12 @@ If you intend to use Rich with Jupyter then there are some additional dependenci
|
|||
|
||||
pip install "rich[jupyter]"
|
||||
|
||||
Demo
|
||||
----
|
||||
|
||||
To check if Rich was installed correctly, and to see a little of what Rich can do, run the following from the command line::
|
||||
|
||||
python -m rich
|
||||
|
||||
Quick Start
|
||||
-----------
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
Live Display
|
||||
============
|
||||
|
||||
Progress bars and status indicators use a *live* display to animate parts of the terminal. You can build custom live displays with the :class:`~rich.live.Live` class.
|
||||
Progress bars and status indicators use a *live* display to animate parts of the terminal. You can build custom live displays with the :class:`~rich.live.Live` class.
|
||||
|
||||
For a demonstration of a live display, run the following command::
|
||||
|
||||
|
@ -72,7 +72,7 @@ You can also change the renderable on-the-fly by calling the :meth:`~rich.live.L
|
|||
Alternate screen
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
You can opt to show a Live display in the "alternate screen" by setting ``screen=True`` on the constructor. This will allow your live display to go full screen and restore the command prompt on exit.
|
||||
You can opt to show a Live display in the "alternate screen" by setting ``screen=True`` on the constructor. This will allow your live display to go full screen and restore the command prompt on exit.
|
||||
|
||||
You can use this feature in combination with :ref:`Layout` to display sophisticated terminal "applications".
|
||||
|
||||
|
@ -80,7 +80,7 @@ Transient display
|
|||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Normally when you exit live context manager (or call :meth:`~rich.live.Live.stop`) the last refreshed item remains in the terminal with the cursor on the following line.
|
||||
You can also make the live display disappear on exit by setting ``transient=True`` on the Live constructor.
|
||||
You can also make the live display disappear on exit by setting ``transient=True`` on the Live constructor.
|
||||
|
||||
Auto refresh
|
||||
~~~~~~~~~~~~
|
||||
|
@ -149,13 +149,10 @@ This feature is enabled by default, but you can disable by setting ``redirect_st
|
|||
Nesting Lives
|
||||
-------------
|
||||
|
||||
Note that only a single live context may be active at any one time. The following will raise a :class:`~rich.errors.LiveError` because status also uses Live::
|
||||
If you create a Live instance within the context of an existing Live instance, then the content of the inner Live will be displayed below the outer Live.
|
||||
|
||||
with Live(table, console=console):
|
||||
with console.status("working"): # Will not work
|
||||
do_work()
|
||||
Prior to version 14.0.0 this would have resulted in a :class:`~rich.errors.LiveError` exception.
|
||||
|
||||
In practice this is rarely a problem because you can display any combination of renderables in a Live context.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
|
|
@ -163,7 +163,6 @@ The following column objects are available:
|
|||
- :class:`~rich.progress.TransferSpeedColumn` Displays transfer speed (assumes the steps are bytes).
|
||||
- :class:`~rich.progress.SpinnerColumn` Displays a "spinner" animation.
|
||||
- :class:`~rich.progress.RenderableColumn` Displays an arbitrary Rich renderable in the column.
|
||||
- :class:`~rich.progress.IterationSpeedColumn` Displays iteration speed in it/s (iterations per second).
|
||||
|
||||
To implement your own columns, extend the :class:`~rich.progress.ProgressColumn` class and use it as you would the other columns.
|
||||
|
||||
|
@ -266,6 +265,28 @@ If you expect to be reading from multiple files, you can use :meth:`~rich.progre
|
|||
See `cp_progress.py <https://github.com/willmcgugan/rich/blob/master/examples/cp_progress.py>`_ for a minimal clone of the ``cp`` command which shows a progress bar as the file is copied.
|
||||
|
||||
|
||||
Nesting Progress bars
|
||||
---------------------
|
||||
|
||||
If you create a new progress bar within the context of an existing progress bar (with the context manager or `track` function), then Rich will display the inner progress bar(s) under the initial bar.
|
||||
|
||||
Here's an example that nests progress bars::
|
||||
|
||||
from rich.progress import track
|
||||
from time import sleep
|
||||
|
||||
|
||||
for count in track(range(10)):
|
||||
for letter in track("ABCDEF", transient=True):
|
||||
print(f"Stage {count}{letter}")
|
||||
sleep(0.1)
|
||||
sleep(0.1)
|
||||
|
||||
The inner loop creates a new progress bar below the first, but both can update.
|
||||
|
||||
Note that if you nest progress bars like this, then the nested bars will updating according to the `refresh_per_second` attribute of the outer bar.
|
||||
|
||||
|
||||
Multiple Progress
|
||||
-----------------
|
||||
|
||||
|
|
5
docs/source/reference/control.rst
Normal file
5
docs/source/reference/control.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
rich.control
|
||||
============
|
||||
|
||||
.. automodule:: rich.control
|
||||
:members:
|
|
@ -1,7 +1,6 @@
|
|||
"""Lite simulation of the top linux command."""
|
||||
import datetime
|
||||
import random
|
||||
import sys
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
@ -9,11 +8,7 @@ from rich import box
|
|||
from rich.console import Console
|
||||
from rich.live import Live
|
||||
from rich.table import Table
|
||||
|
||||
if sys.version_info >= (3, 8):
|
||||
from typing import Literal
|
||||
else:
|
||||
from typing_extensions import Literal
|
||||
from typing import Literal
|
||||
|
||||
|
||||
@dataclass
|
||||
|
|
252
poetry.lock
generated
252
poetry.lock
generated
|
@ -13,21 +13,18 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "asttokens"
|
||||
version = "2.4.1"
|
||||
version = "3.0.0"
|
||||
description = "Annotate AST trees with source code positions"
|
||||
optional = true
|
||||
python-versions = "*"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"},
|
||||
{file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"},
|
||||
{file = "asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2"},
|
||||
{file = "asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
six = ">=1.12.0"
|
||||
|
||||
[package.extras]
|
||||
astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"]
|
||||
test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"]
|
||||
astroid = ["astroid (>=2,<4)"]
|
||||
test = ["astroid (>=2,<4)", "pytest", "pytest-cov", "pytest-xdist"]
|
||||
|
||||
[[package]]
|
||||
name = "asv"
|
||||
|
@ -122,13 +119,13 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.1.7"
|
||||
version = "8.1.8"
|
||||
description = "Composable command line interface toolkit"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
|
||||
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
|
||||
{file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"},
|
||||
{file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
@ -251,49 +248,52 @@ toml = ["tomli"]
|
|||
|
||||
[[package]]
|
||||
name = "decorator"
|
||||
version = "5.1.1"
|
||||
version = "5.2.1"
|
||||
description = "Decorators for Humans"
|
||||
optional = true
|
||||
python-versions = ">=3.5"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"},
|
||||
{file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"},
|
||||
{file = "decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a"},
|
||||
{file = "decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "distlib"
|
||||
version = "0.3.8"
|
||||
version = "0.3.9"
|
||||
description = "Distribution utilities"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"},
|
||||
{file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"},
|
||||
{file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"},
|
||||
{file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exceptiongroup"
|
||||
version = "1.2.2"
|
||||
version = "1.3.0"
|
||||
description = "Backport of PEP 654 (exception groups)"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
|
||||
{file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
|
||||
{file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"},
|
||||
{file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""}
|
||||
|
||||
[package.extras]
|
||||
test = ["pytest (>=6)"]
|
||||
|
||||
[[package]]
|
||||
name = "executing"
|
||||
version = "2.1.0"
|
||||
version = "2.2.0"
|
||||
description = "Get the currently executing AST node of a frame, and other information"
|
||||
optional = true
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "executing-2.1.0-py2.py3-none-any.whl", hash = "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf"},
|
||||
{file = "executing-2.1.0.tar.gz", hash = "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab"},
|
||||
{file = "executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa"},
|
||||
{file = "executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
|
@ -331,13 +331,13 @@ license = ["ukkonen"]
|
|||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
version = "2.0.0"
|
||||
version = "2.1.0"
|
||||
description = "brain-dead simple config-ini parsing"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
|
||||
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
|
||||
{file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"},
|
||||
{file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -381,53 +381,53 @@ test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pa
|
|||
|
||||
[[package]]
|
||||
name = "ipywidgets"
|
||||
version = "8.1.5"
|
||||
version = "8.1.7"
|
||||
description = "Jupyter interactive widgets"
|
||||
optional = true
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "ipywidgets-8.1.5-py3-none-any.whl", hash = "sha256:3290f526f87ae6e77655555baba4f36681c555b8bdbbff430b70e52c34c86245"},
|
||||
{file = "ipywidgets-8.1.5.tar.gz", hash = "sha256:870e43b1a35656a80c18c9503bbf2d16802db1cb487eec6fab27d683381dde17"},
|
||||
{file = "ipywidgets-8.1.7-py3-none-any.whl", hash = "sha256:764f2602d25471c213919b8a1997df04bef869251db4ca8efba1b76b1bd9f7bb"},
|
||||
{file = "ipywidgets-8.1.7.tar.gz", hash = "sha256:15f1ac050b9ccbefd45dccfbb2ef6bed0029d8278682d569d71b8dd96bee0376"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
comm = ">=0.1.3"
|
||||
ipython = ">=6.1.0"
|
||||
jupyterlab-widgets = ">=3.0.12,<3.1.0"
|
||||
jupyterlab_widgets = ">=3.0.15,<3.1.0"
|
||||
traitlets = ">=4.3.1"
|
||||
widgetsnbextension = ">=4.0.12,<4.1.0"
|
||||
widgetsnbextension = ">=4.0.14,<4.1.0"
|
||||
|
||||
[package.extras]
|
||||
test = ["ipykernel", "jsonschema", "pytest (>=3.6.0)", "pytest-cov", "pytz"]
|
||||
|
||||
[[package]]
|
||||
name = "jedi"
|
||||
version = "0.19.1"
|
||||
version = "0.19.2"
|
||||
description = "An autocompletion tool for Python that can be used for text editors."
|
||||
optional = true
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"},
|
||||
{file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"},
|
||||
{file = "jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9"},
|
||||
{file = "jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
parso = ">=0.8.3,<0.9.0"
|
||||
parso = ">=0.8.4,<0.9.0"
|
||||
|
||||
[package.extras]
|
||||
docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"]
|
||||
qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"]
|
||||
testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"]
|
||||
testing = ["Django", "attrs", "colorama", "docopt", "pytest (<9.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "jupyterlab-widgets"
|
||||
version = "3.0.13"
|
||||
version = "3.0.15"
|
||||
description = "Jupyter interactive widgets for JupyterLab"
|
||||
optional = true
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "jupyterlab_widgets-3.0.13-py3-none-any.whl", hash = "sha256:e3cda2c233ce144192f1e29914ad522b2f4c40e77214b0cc97377ca3d323db54"},
|
||||
{file = "jupyterlab_widgets-3.0.13.tar.gz", hash = "sha256:a2966d385328c1942b683a8cd96b89b8dd82c8b8f81dda902bb2bc06d46f5bed"},
|
||||
{file = "jupyterlab_widgets-3.0.15-py3-none-any.whl", hash = "sha256:d59023d7d7ef71400d51e6fee9a88867f6e65e10a4201605d2d7f3e8f012a31c"},
|
||||
{file = "jupyterlab_widgets-3.0.15.tar.gz", hash = "sha256:2920888a0c2922351a9202817957a68c07d99673504d6cd37345299e971bb08b"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -481,60 +481,72 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "mypy"
|
||||
version = "1.11.2"
|
||||
version = "1.14.1"
|
||||
description = "Optional static typing for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "mypy-1.11.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d42a6dd818ffce7be66cce644f1dff482f1d97c53ca70908dff0b9ddc120b77a"},
|
||||
{file = "mypy-1.11.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:801780c56d1cdb896eacd5619a83e427ce436d86a3bdf9112527f24a66618fef"},
|
||||
{file = "mypy-1.11.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41ea707d036a5307ac674ea172875f40c9d55c5394f888b168033177fce47383"},
|
||||
{file = "mypy-1.11.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6e658bd2d20565ea86da7d91331b0eed6d2eee22dc031579e6297f3e12c758c8"},
|
||||
{file = "mypy-1.11.2-cp310-cp310-win_amd64.whl", hash = "sha256:478db5f5036817fe45adb7332d927daa62417159d49783041338921dcf646fc7"},
|
||||
{file = "mypy-1.11.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75746e06d5fa1e91bfd5432448d00d34593b52e7e91a187d981d08d1f33d4385"},
|
||||
{file = "mypy-1.11.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a976775ab2256aadc6add633d44f100a2517d2388906ec4f13231fafbb0eccca"},
|
||||
{file = "mypy-1.11.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd953f221ac1379050a8a646585a29574488974f79d8082cedef62744f0a0104"},
|
||||
{file = "mypy-1.11.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:57555a7715c0a34421013144a33d280e73c08df70f3a18a552938587ce9274f4"},
|
||||
{file = "mypy-1.11.2-cp311-cp311-win_amd64.whl", hash = "sha256:36383a4fcbad95f2657642a07ba22ff797de26277158f1cc7bd234821468b1b6"},
|
||||
{file = "mypy-1.11.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e8960dbbbf36906c5c0b7f4fbf2f0c7ffb20f4898e6a879fcf56a41a08b0d318"},
|
||||
{file = "mypy-1.11.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06d26c277962f3fb50e13044674aa10553981ae514288cb7d0a738f495550b36"},
|
||||
{file = "mypy-1.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e7184632d89d677973a14d00ae4d03214c8bc301ceefcdaf5c474866814c987"},
|
||||
{file = "mypy-1.11.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3a66169b92452f72117e2da3a576087025449018afc2d8e9bfe5ffab865709ca"},
|
||||
{file = "mypy-1.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:969ea3ef09617aff826885a22ece0ddef69d95852cdad2f60c8bb06bf1f71f70"},
|
||||
{file = "mypy-1.11.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:37c7fa6121c1cdfcaac97ce3d3b5588e847aa79b580c1e922bb5d5d2902df19b"},
|
||||
{file = "mypy-1.11.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a8a53bc3ffbd161b5b2a4fff2f0f1e23a33b0168f1c0778ec70e1a3d66deb86"},
|
||||
{file = "mypy-1.11.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ff93107f01968ed834f4256bc1fc4475e2fecf6c661260066a985b52741ddce"},
|
||||
{file = "mypy-1.11.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:edb91dded4df17eae4537668b23f0ff6baf3707683734b6a818d5b9d0c0c31a1"},
|
||||
{file = "mypy-1.11.2-cp38-cp38-win_amd64.whl", hash = "sha256:ee23de8530d99b6db0573c4ef4bd8f39a2a6f9b60655bf7a1357e585a3486f2b"},
|
||||
{file = "mypy-1.11.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:801ca29f43d5acce85f8e999b1e431fb479cb02d0e11deb7d2abb56bdaf24fd6"},
|
||||
{file = "mypy-1.11.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af8d155170fcf87a2afb55b35dc1a0ac21df4431e7d96717621962e4b9192e70"},
|
||||
{file = "mypy-1.11.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7821776e5c4286b6a13138cc935e2e9b6fde05e081bdebf5cdb2bb97c9df81d"},
|
||||
{file = "mypy-1.11.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:539c570477a96a4e6fb718b8d5c3e0c0eba1f485df13f86d2970c91f0673148d"},
|
||||
{file = "mypy-1.11.2-cp39-cp39-win_amd64.whl", hash = "sha256:3f14cd3d386ac4d05c5a39a51b84387403dadbd936e17cb35882134d4f8f0d24"},
|
||||
{file = "mypy-1.11.2-py3-none-any.whl", hash = "sha256:b499bc07dbdcd3de92b0a8b29fdf592c111276f6a12fe29c30f6c417dd546d12"},
|
||||
{file = "mypy-1.11.2.tar.gz", hash = "sha256:7f9993ad3e0ffdc95c2a14b66dee63729f021968bff8ad911867579c65d13a79"},
|
||||
{file = "mypy-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:52686e37cf13d559f668aa398dd7ddf1f92c5d613e4f8cb262be2fb4fedb0fcb"},
|
||||
{file = "mypy-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1fb545ca340537d4b45d3eecdb3def05e913299ca72c290326be19b3804b39c0"},
|
||||
{file = "mypy-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90716d8b2d1f4cd503309788e51366f07c56635a3309b0f6a32547eaaa36a64d"},
|
||||
{file = "mypy-1.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ae753f5c9fef278bcf12e1a564351764f2a6da579d4a81347e1d5a15819997b"},
|
||||
{file = "mypy-1.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e0fe0f5feaafcb04505bcf439e991c6d8f1bf8b15f12b05feeed96e9e7bf1427"},
|
||||
{file = "mypy-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:7d54bd85b925e501c555a3227f3ec0cfc54ee8b6930bd6141ec872d1c572f81f"},
|
||||
{file = "mypy-1.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f995e511de847791c3b11ed90084a7a0aafdc074ab88c5a9711622fe4751138c"},
|
||||
{file = "mypy-1.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d64169ec3b8461311f8ce2fd2eb5d33e2d0f2c7b49116259c51d0d96edee48d1"},
|
||||
{file = "mypy-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba24549de7b89b6381b91fbc068d798192b1b5201987070319889e93038967a8"},
|
||||
{file = "mypy-1.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:183cf0a45457d28ff9d758730cd0210419ac27d4d3f285beda038c9083363b1f"},
|
||||
{file = "mypy-1.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f2a0ecc86378f45347f586e4163d1769dd81c5a223d577fe351f26b179e148b1"},
|
||||
{file = "mypy-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:ad3301ebebec9e8ee7135d8e3109ca76c23752bac1e717bc84cd3836b4bf3eae"},
|
||||
{file = "mypy-1.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:30ff5ef8519bbc2e18b3b54521ec319513a26f1bba19a7582e7b1f58a6e69f14"},
|
||||
{file = "mypy-1.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb9f255c18052343c70234907e2e532bc7e55a62565d64536dbc7706a20b78b9"},
|
||||
{file = "mypy-1.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b4e3413e0bddea671012b063e27591b953d653209e7a4fa5e48759cda77ca11"},
|
||||
{file = "mypy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:553c293b1fbdebb6c3c4030589dab9fafb6dfa768995a453d8a5d3b23784af2e"},
|
||||
{file = "mypy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fad79bfe3b65fe6a1efaed97b445c3d37f7be9fdc348bdb2d7cac75579607c89"},
|
||||
{file = "mypy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:8fa2220e54d2946e94ab6dbb3ba0a992795bd68b16dc852db33028df2b00191b"},
|
||||
{file = "mypy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:92c3ed5afb06c3a8e188cb5da4984cab9ec9a77ba956ee419c68a388b4595255"},
|
||||
{file = "mypy-1.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dbec574648b3e25f43d23577309b16534431db4ddc09fda50841f1e34e64ed34"},
|
||||
{file = "mypy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c6d94b16d62eb3e947281aa7347d78236688e21081f11de976376cf010eb31a"},
|
||||
{file = "mypy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d4b19b03fdf54f3c5b2fa474c56b4c13c9dbfb9a2db4370ede7ec11a2c5927d9"},
|
||||
{file = "mypy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0c911fde686394753fff899c409fd4e16e9b294c24bfd5e1ea4675deae1ac6fd"},
|
||||
{file = "mypy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8b21525cb51671219f5307be85f7e646a153e5acc656e5cebf64bfa076c50107"},
|
||||
{file = "mypy-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7084fb8f1128c76cd9cf68fe5971b37072598e7c31b2f9f95586b65c741a9d31"},
|
||||
{file = "mypy-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8f845a00b4f420f693f870eaee5f3e2692fa84cc8514496114649cfa8fd5e2c6"},
|
||||
{file = "mypy-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44bf464499f0e3a2d14d58b54674dee25c031703b2ffc35064bd0df2e0fac319"},
|
||||
{file = "mypy-1.14.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c99f27732c0b7dc847adb21c9d47ce57eb48fa33a17bc6d7d5c5e9f9e7ae5bac"},
|
||||
{file = "mypy-1.14.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:bce23c7377b43602baa0bd22ea3265c49b9ff0b76eb315d6c34721af4cdf1d9b"},
|
||||
{file = "mypy-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:8edc07eeade7ebc771ff9cf6b211b9a7d93687ff892150cb5692e4f4272b0837"},
|
||||
{file = "mypy-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3888a1816d69f7ab92092f785a462944b3ca16d7c470d564165fe703b0970c35"},
|
||||
{file = "mypy-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:46c756a444117c43ee984bd055db99e498bc613a70bbbc120272bd13ca579fbc"},
|
||||
{file = "mypy-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:27fc248022907e72abfd8e22ab1f10e903915ff69961174784a3900a8cba9ad9"},
|
||||
{file = "mypy-1.14.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:499d6a72fb7e5de92218db961f1a66d5f11783f9ae549d214617edab5d4dbdbb"},
|
||||
{file = "mypy-1.14.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:57961db9795eb566dc1d1b4e9139ebc4c6b0cb6e7254ecde69d1552bf7613f60"},
|
||||
{file = "mypy-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:07ba89fdcc9451f2ebb02853deb6aaaa3d2239a236669a63ab3801bbf923ef5c"},
|
||||
{file = "mypy-1.14.1-py3-none-any.whl", hash = "sha256:b66a60cc4073aeb8ae00057f9c1f64d49e90f918fbcef9a977eb121da8b8f1d1"},
|
||||
{file = "mypy-1.14.1.tar.gz", hash = "sha256:7ec88144fe9b510e8475ec2f5f251992690fcf89ccb4500b214b4226abcd32d6"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
mypy-extensions = ">=1.0.0"
|
||||
mypy_extensions = ">=1.0.0"
|
||||
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
||||
typing-extensions = ">=4.6.0"
|
||||
typing_extensions = ">=4.6.0"
|
||||
|
||||
[package.extras]
|
||||
dmypy = ["psutil (>=4.0)"]
|
||||
faster-cache = ["orjson"]
|
||||
install-types = ["pip"]
|
||||
mypyc = ["setuptools (>=50)"]
|
||||
reports = ["lxml"]
|
||||
|
||||
[[package]]
|
||||
name = "mypy-extensions"
|
||||
version = "1.0.0"
|
||||
version = "1.1.0"
|
||||
description = "Type system extensions for programs checked with the mypy type checker."
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
|
||||
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
|
||||
{file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"},
|
||||
{file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -550,13 +562,13 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "24.1"
|
||||
version = "25.0"
|
||||
description = "Core utilities for Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
|
||||
{file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
|
||||
{file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"},
|
||||
{file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -661,13 +673,13 @@ virtualenv = ">=20.10.0"
|
|||
|
||||
[[package]]
|
||||
name = "prompt-toolkit"
|
||||
version = "3.0.48"
|
||||
version = "3.0.51"
|
||||
description = "Library for building powerful interactive command lines in Python"
|
||||
optional = true
|
||||
python-versions = ">=3.7.0"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "prompt_toolkit-3.0.48-py3-none-any.whl", hash = "sha256:f49a827f90062e411f1ce1f854f2aedb3c23353244f8108b89283587397ac10e"},
|
||||
{file = "prompt_toolkit-3.0.48.tar.gz", hash = "sha256:d6623ab0477a80df74e646bdbc93621143f5caf104206aa29294d53de1a03d90"},
|
||||
{file = "prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07"},
|
||||
{file = "prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
@ -700,13 +712,13 @@ tests = ["pytest"]
|
|||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.18.0"
|
||||
version = "2.19.1"
|
||||
description = "Pygments is a syntax highlighting package written in Python."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"},
|
||||
{file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"},
|
||||
{file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"},
|
||||
{file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
|
@ -816,13 +828,13 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.16.0"
|
||||
version = "1.17.0"
|
||||
description = "Python 2 and 3 compatibility utilities"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
|
||||
files = [
|
||||
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
||||
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
|
||||
{file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"},
|
||||
{file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -846,13 +858,43 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"]
|
|||
|
||||
[[package]]
|
||||
name = "tomli"
|
||||
version = "2.0.1"
|
||||
version = "2.2.1"
|
||||
description = "A lil' TOML parser"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
|
||||
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"},
|
||||
{file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"},
|
||||
{file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -872,24 +914,24 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,
|
|||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.12.2"
|
||||
version = "4.13.2"
|
||||
description = "Backported and Experimental Type Hints for Python 3.8+"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
|
||||
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
|
||||
{file = "typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c"},
|
||||
{file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "virtualenv"
|
||||
version = "20.26.6"
|
||||
version = "20.31.2"
|
||||
description = "Virtual Python Environment builder"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "virtualenv-20.26.6-py3-none-any.whl", hash = "sha256:7345cc5b25405607a624d8418154577459c3e0277f5466dd79c49d5e492995f2"},
|
||||
{file = "virtualenv-20.26.6.tar.gz", hash = "sha256:280aede09a2a5c317e409a00102e7077c6432c5a38f0ef938e643805a7ad2c48"},
|
||||
{file = "virtualenv-20.31.2-py3-none-any.whl", hash = "sha256:36efd0d9650ee985f0cad72065001e66d49a6f24eb44d98980f630686243cf11"},
|
||||
{file = "virtualenv-20.31.2.tar.gz", hash = "sha256:e10c0a9d02835e592521be48b332b6caee6887f332c111aa79a09b9e79efc2af"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
@ -914,13 +956,13 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "widgetsnbextension"
|
||||
version = "4.0.13"
|
||||
version = "4.0.14"
|
||||
description = "Jupyter interactive widgets for Jupyter Notebook"
|
||||
optional = true
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "widgetsnbextension-4.0.13-py3-none-any.whl", hash = "sha256:74b2692e8500525cc38c2b877236ba51d34541e6385eeed5aec15a70f88a6c71"},
|
||||
{file = "widgetsnbextension-4.0.13.tar.gz", hash = "sha256:ffcb67bc9febd10234a362795f643927f4e0c05d9342c727b65d2384f8feacb6"},
|
||||
{file = "widgetsnbextension-4.0.14-py3-none-any.whl", hash = "sha256:4875a9eaf72fbf5079dc372a51a9f268fc38d46f767cbf85c43a36da5cb9b575"},
|
||||
{file = "widgetsnbextension-4.0.14.tar.gz", hash = "sha256:a3629b04e3edb893212df862038c7232f62973373869db5084aed739b437b5af"},
|
||||
]
|
||||
|
||||
[extras]
|
||||
|
@ -929,4 +971,4 @@ jupyter = ["ipywidgets"]
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.8.0"
|
||||
content-hash = "804a37e7036779a41ab3dfe0cab6324de5095f81684e7db724ba803b26159b60"
|
||||
content-hash = "2e87c73a127b5e6456de92c6cab8e8be8f746f2c4d792ae0563ae74e19593e4c"
|
||||
|
|
|
@ -28,7 +28,6 @@ include = ["rich/py.typed"]
|
|||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.8.0"
|
||||
typing-extensions = { version = ">=4.0.0, <5.0", python = "<3.11" }
|
||||
pygments = "^2.13.0"
|
||||
ipywidgets = { version = ">=7.5.1,<9", optional = true }
|
||||
markdown-it-py = ">=2.2.0"
|
||||
|
@ -44,6 +43,7 @@ pytest-cov = "^3.0.0"
|
|||
attrs = "^21.4.0"
|
||||
pre-commit = "^2.17.0"
|
||||
asv = "^0.5.1"
|
||||
typing-extensions = ">=4.0.0, <5.0"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
|
|
|
@ -207,6 +207,8 @@ Supports much of the *markdown* __syntax__!
|
|||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
from rich.panel import Panel
|
||||
|
||||
console = Console(
|
||||
file=io.StringIO(),
|
||||
force_terminal=True,
|
||||
|
@ -227,47 +229,17 @@ if __name__ == "__main__": # pragma: no cover
|
|||
c = Console(record=True)
|
||||
c.print(test_card)
|
||||
|
||||
print(f"rendered in {pre_cache_taken}ms (cold cache)")
|
||||
print(f"rendered in {taken}ms (warm cache)")
|
||||
|
||||
from rich.panel import Panel
|
||||
|
||||
console = Console()
|
||||
|
||||
sponsor_message = Table.grid(padding=1)
|
||||
sponsor_message.add_column(style="green", justify="right")
|
||||
sponsor_message.add_column(no_wrap=True)
|
||||
|
||||
sponsor_message.add_row(
|
||||
"Textualize",
|
||||
"[u blue link=https://github.com/textualize]https://github.com/textualize",
|
||||
)
|
||||
sponsor_message.add_row(
|
||||
"Twitter",
|
||||
"[u blue link=https://twitter.com/willmcgugan]https://twitter.com/willmcgugan",
|
||||
)
|
||||
|
||||
intro_message = Text.from_markup(
|
||||
"""\
|
||||
We hope you enjoy using Rich!
|
||||
|
||||
Rich is maintained with [red]:heart:[/] by [link=https://www.textualize.io]Textualize.io[/]
|
||||
|
||||
- Will McGugan"""
|
||||
)
|
||||
|
||||
message = Table.grid(padding=2)
|
||||
message.add_column()
|
||||
message.add_column(no_wrap=True)
|
||||
message.add_row(intro_message, sponsor_message)
|
||||
|
||||
console.print(f"[dim]rendered in [not dim]{pre_cache_taken}ms[/] (cold cache)")
|
||||
console.print(f"[dim]rendered in [not dim]{taken}ms[/] (warm cache)")
|
||||
console.print()
|
||||
console.print(
|
||||
Panel.fit(
|
||||
message,
|
||||
box=box.ROUNDED,
|
||||
padding=(1, 2),
|
||||
title="[b red]Thanks for trying out Rich!",
|
||||
border_style="bright_blue",
|
||||
),
|
||||
justify="center",
|
||||
"[b magenta]Hope you enjoy using Rich![/]\n\n"
|
||||
"Please consider sponsoring me if you get value from my work.\n\n"
|
||||
"Even the price of a ☕ can brighten my day!\n\n"
|
||||
"https://github.com/sponsors/willmcgugan",
|
||||
border_style="red",
|
||||
title="Help ensure Rich is maintained",
|
||||
)
|
||||
)
|
||||
|
|
|
@ -214,7 +214,7 @@ class Inspect(JupyterMixin):
|
|||
def _get_formatted_doc(self, object_: Any) -> Optional[str]:
|
||||
"""
|
||||
Extract the docstring of an object, process it and returns it.
|
||||
The processing consists in cleaning up the doctring's indentation,
|
||||
The processing consists in cleaning up the docstring's indentation,
|
||||
taking only its 1st paragraph if `self.help` is not True,
|
||||
and escape its control codes.
|
||||
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
import sys
|
||||
from fractions import Fraction
|
||||
from math import ceil
|
||||
from typing import cast, List, Optional, Sequence
|
||||
|
||||
if sys.version_info >= (3, 8):
|
||||
from typing import Protocol
|
||||
else:
|
||||
from typing_extensions import Protocol # pragma: no cover
|
||||
from typing import cast, List, Optional, Sequence, Protocol
|
||||
|
||||
|
||||
class Edge(Protocol):
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
import sys
|
||||
from itertools import chain
|
||||
from typing import TYPE_CHECKING, Iterable, Optional
|
||||
|
||||
if sys.version_info >= (3, 8):
|
||||
from typing import Literal
|
||||
else:
|
||||
from typing_extensions import Literal # pragma: no cover
|
||||
from typing import TYPE_CHECKING, Iterable, Optional, Literal
|
||||
|
||||
from .constrain import Constrain
|
||||
from .jupyter import JupyterMixin
|
||||
|
|
|
@ -1,10 +1,4 @@
|
|||
import sys
|
||||
from typing import TYPE_CHECKING, Iterable, List
|
||||
|
||||
if sys.version_info >= (3, 8):
|
||||
from typing import Literal
|
||||
else:
|
||||
from typing_extensions import Literal # pragma: no cover
|
||||
from typing import TYPE_CHECKING, Iterable, List, Literal
|
||||
|
||||
|
||||
from ._loop import loop_last
|
||||
|
|
|
@ -22,27 +22,21 @@ from typing import (
|
|||
Dict,
|
||||
Iterable,
|
||||
List,
|
||||
Literal,
|
||||
Mapping,
|
||||
NamedTuple,
|
||||
Optional,
|
||||
Protocol,
|
||||
TextIO,
|
||||
Tuple,
|
||||
Type,
|
||||
Union,
|
||||
cast,
|
||||
runtime_checkable,
|
||||
)
|
||||
|
||||
from rich._null_file import NULL_FILE
|
||||
|
||||
if sys.version_info >= (3, 8):
|
||||
from typing import Literal, Protocol, runtime_checkable
|
||||
else:
|
||||
from typing_extensions import (
|
||||
Literal,
|
||||
Protocol,
|
||||
runtime_checkable,
|
||||
) # pragma: no cover
|
||||
|
||||
from . import errors, themes
|
||||
from ._emoji_replace import _emoji_replace
|
||||
from ._export_format import CONSOLE_HTML_FORMAT, CONSOLE_SVG_FORMAT
|
||||
|
@ -739,6 +733,14 @@ class Console:
|
|||
if no_color is not None
|
||||
else self._environ.get("NO_COLOR", "") != ""
|
||||
)
|
||||
if force_interactive is None:
|
||||
tty_interactive = self._environ.get("TTY_INTERACTIVE", None)
|
||||
if tty_interactive is not None:
|
||||
if tty_interactive == "0":
|
||||
force_interactive = False
|
||||
elif tty_interactive == "1":
|
||||
force_interactive = True
|
||||
|
||||
self.is_interactive = (
|
||||
(self.is_terminal and not self.is_dumb_terminal)
|
||||
if force_interactive is None
|
||||
|
@ -751,7 +753,7 @@ class Console:
|
|||
)
|
||||
self._record_buffer: List[Segment] = []
|
||||
self._render_hooks: List[RenderHook] = []
|
||||
self._live: Optional["Live"] = None
|
||||
self._live_stack: List[Live] = []
|
||||
self._is_alt_screen = False
|
||||
|
||||
def __repr__(self) -> str:
|
||||
|
@ -823,24 +825,26 @@ class Console:
|
|||
self._buffer_index -= 1
|
||||
self._check_buffer()
|
||||
|
||||
def set_live(self, live: "Live") -> None:
|
||||
"""Set Live instance. Used by Live context manager.
|
||||
def set_live(self, live: "Live") -> bool:
|
||||
"""Set Live instance. Used by Live context manager (no need to call directly).
|
||||
|
||||
Args:
|
||||
live (Live): Live instance using this Console.
|
||||
|
||||
Returns:
|
||||
Boolean that indicates if the live is the topmost of the stack.
|
||||
|
||||
Raises:
|
||||
errors.LiveError: If this Console has a Live context currently active.
|
||||
"""
|
||||
with self._lock:
|
||||
if self._live is not None:
|
||||
raise errors.LiveError("Only one live display may be active at once")
|
||||
self._live = live
|
||||
self._live_stack.append(live)
|
||||
return len(self._live_stack) == 1
|
||||
|
||||
def clear_live(self) -> None:
|
||||
"""Clear the Live instance."""
|
||||
"""Clear the Live instance. Used by the Live context manager (no need to call directly)."""
|
||||
with self._lock:
|
||||
self._live = None
|
||||
self._live_stack.pop()
|
||||
|
||||
def push_render_hook(self, hook: RenderHook) -> None:
|
||||
"""Add a new render hook to the stack.
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
import sys
|
||||
import time
|
||||
from typing import TYPE_CHECKING, Callable, Dict, Iterable, List, Union
|
||||
|
||||
if sys.version_info >= (3, 8):
|
||||
from typing import Final
|
||||
else:
|
||||
from typing_extensions import Final # pragma: no cover
|
||||
from typing import TYPE_CHECKING, Callable, Dict, Iterable, List, Union, Final
|
||||
|
||||
from .segment import ControlCode, ControlType, Segment
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ def report() -> None: # pragma: no cover
|
|||
"TERM_PROGRAM",
|
||||
"TERM",
|
||||
"TTY_COMPATIBLE",
|
||||
"TTY_INTERACTIVE",
|
||||
"VSCODE_VERBOSE_LOGGING",
|
||||
)
|
||||
env = {name: os.getenv(name) for name in env_names}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import sys
|
||||
from typing import TYPE_CHECKING, Optional, Union
|
||||
from typing import TYPE_CHECKING, Optional, Union, Literal
|
||||
|
||||
from .jupyter import JupyterMixin
|
||||
from .segment import Segment
|
||||
|
@ -7,11 +7,6 @@ from .style import Style
|
|||
from ._emoji_codes import EMOJI
|
||||
from ._emoji_replace import _emoji_replace
|
||||
|
||||
if sys.version_info >= (3, 8):
|
||||
from typing import Literal
|
||||
else:
|
||||
from typing_extensions import Literal # pragma: no cover
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .console import Console, ConsoleOptions, RenderResult
|
||||
|
|
29
rich/live.py
29
rich/live.py
|
@ -4,7 +4,7 @@ from types import TracebackType
|
|||
from typing import IO, Any, Callable, List, Optional, TextIO, Type, cast
|
||||
|
||||
from . import get_console
|
||||
from .console import Console, ConsoleRenderable, RenderableType, RenderHook
|
||||
from .console import Console, ConsoleRenderable, Group, RenderableType, RenderHook
|
||||
from .control import Control
|
||||
from .file_proxy import FileProxy
|
||||
from .jupyter import JupyterMixin
|
||||
|
@ -87,6 +87,7 @@ class Live(JupyterMixin, RenderHook):
|
|||
self._live_render = LiveRender(
|
||||
self.get_renderable(), vertical_overflow=vertical_overflow
|
||||
)
|
||||
self._nested = False
|
||||
|
||||
@property
|
||||
def is_started(self) -> bool:
|
||||
|
@ -110,8 +111,12 @@ class Live(JupyterMixin, RenderHook):
|
|||
with self._lock:
|
||||
if self._started:
|
||||
return
|
||||
self.console.set_live(self)
|
||||
self._started = True
|
||||
|
||||
if not self.console.set_live(self):
|
||||
self._nested = True
|
||||
return
|
||||
|
||||
if self._screen:
|
||||
self._alt_screen = self.console.set_alt_screen(True)
|
||||
self.console.show_cursor(False)
|
||||
|
@ -136,8 +141,12 @@ class Live(JupyterMixin, RenderHook):
|
|||
with self._lock:
|
||||
if not self._started:
|
||||
return
|
||||
self.console.clear_live()
|
||||
self._started = False
|
||||
self.console.clear_live()
|
||||
if self._nested:
|
||||
if not self.transient:
|
||||
self.console.print(self.renderable)
|
||||
return
|
||||
|
||||
if self.auto_refresh and self._refresh_thread is not None:
|
||||
self._refresh_thread.stop()
|
||||
|
@ -156,7 +165,6 @@ class Live(JupyterMixin, RenderHook):
|
|||
self.console.show_cursor(True)
|
||||
if self._alt_screen:
|
||||
self.console.set_alt_screen(False)
|
||||
|
||||
if self.transient and not self._alt_screen:
|
||||
self.console.control(self._live_render.restore_cursor())
|
||||
if self.ipy_widget is not None and self.transient:
|
||||
|
@ -200,7 +208,13 @@ class Live(JupyterMixin, RenderHook):
|
|||
Returns:
|
||||
RenderableType: Displayed renderable.
|
||||
"""
|
||||
renderable = self.get_renderable()
|
||||
live_stack = self.console._live_stack
|
||||
renderable: RenderableType
|
||||
if live_stack and self is live_stack[0]:
|
||||
# The first Live instance will render everything in the Live stack
|
||||
renderable = Group(*[live.get_renderable() for live in live_stack])
|
||||
else:
|
||||
renderable = self.get_renderable()
|
||||
return Screen(renderable) if self._alt_screen else renderable
|
||||
|
||||
def update(self, renderable: RenderableType, *, refresh: bool = False) -> None:
|
||||
|
@ -221,6 +235,11 @@ class Live(JupyterMixin, RenderHook):
|
|||
"""Update the display of the Live Render."""
|
||||
with self._lock:
|
||||
self._live_render.set_renderable(self.renderable)
|
||||
if self._nested:
|
||||
if self.console._live_stack:
|
||||
self.console._live_stack[0].refresh()
|
||||
return
|
||||
|
||||
if self.console.is_jupyter: # pragma: no cover
|
||||
try:
|
||||
from IPython.display import display
|
||||
|
|
|
@ -1,10 +1,4 @@
|
|||
import sys
|
||||
from typing import Optional, Tuple
|
||||
|
||||
if sys.version_info >= (3, 8):
|
||||
from typing import Literal
|
||||
else:
|
||||
from typing_extensions import Literal # pragma: no cover
|
||||
from typing import Optional, Tuple, Literal
|
||||
|
||||
|
||||
from ._loop import loop_last
|
||||
|
|
|
@ -76,7 +76,7 @@ class RichHandler(Handler):
|
|||
markup: bool = False,
|
||||
rich_tracebacks: bool = False,
|
||||
tracebacks_width: Optional[int] = None,
|
||||
tracebacks_code_width: int = 88,
|
||||
tracebacks_code_width: Optional[int] = 88,
|
||||
tracebacks_extra_lines: int = 3,
|
||||
tracebacks_theme: Optional[str] = None,
|
||||
tracebacks_word_wrap: bool = True,
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from typing import ClassVar, Iterable
|
||||
from typing import ClassVar, Iterable, get_args
|
||||
|
||||
from markdown_it import MarkdownIt
|
||||
from markdown_it.token import Token
|
||||
|
||||
if sys.version_info >= (3, 8):
|
||||
from typing import get_args
|
||||
else:
|
||||
from typing_extensions import get_args # pragma: no cover
|
||||
|
||||
from rich.table import Table
|
||||
|
||||
from . import box
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
import sys
|
||||
import typing
|
||||
import warnings
|
||||
from abc import ABC, abstractmethod
|
||||
|
@ -14,6 +15,7 @@ from os import PathLike, stat
|
|||
from threading import Event, RLock, Thread
|
||||
from types import TracebackType
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
BinaryIO,
|
||||
Callable,
|
||||
|
@ -23,10 +25,10 @@ from typing import (
|
|||
Generic,
|
||||
Iterable,
|
||||
List,
|
||||
Literal,
|
||||
NamedTuple,
|
||||
NewType,
|
||||
Optional,
|
||||
Sequence,
|
||||
TextIO,
|
||||
Tuple,
|
||||
Type,
|
||||
|
@ -34,14 +36,8 @@ from typing import (
|
|||
Union,
|
||||
)
|
||||
|
||||
if sys.version_info >= (3, 8):
|
||||
from typing import Literal
|
||||
else:
|
||||
from typing_extensions import Literal # pragma: no cover
|
||||
|
||||
if sys.version_info >= (3, 11):
|
||||
from typing import Self
|
||||
else:
|
||||
if TYPE_CHECKING:
|
||||
# Can be replaced with `from typing import Self` in Python 3.11+
|
||||
from typing_extensions import Self # pragma: no cover
|
||||
|
||||
from . import filesize, get_console
|
||||
|
@ -106,7 +102,7 @@ class _TrackThread(Thread):
|
|||
|
||||
|
||||
def track(
|
||||
sequence: Union[Sequence[ProgressType], Iterable[ProgressType]],
|
||||
sequence: Iterable[ProgressType],
|
||||
description: str = "Working...",
|
||||
total: Optional[float] = None,
|
||||
completed: int = 0,
|
||||
|
@ -125,8 +121,10 @@ def track(
|
|||
) -> Iterable[ProgressType]:
|
||||
"""Track progress by iterating over a sequence.
|
||||
|
||||
You can also track progress of an iterable, which might require that you additionally specify ``total``.
|
||||
|
||||
Args:
|
||||
sequence (Iterable[ProgressType]): A sequence (must support "len") you wish to iterate over.
|
||||
sequence (Iterable[ProgressType]): Values you wish to iterate over and track progress.
|
||||
description (str, optional): Description of task show next to progress bar. Defaults to "Working".
|
||||
total: (float, optional): Total number of steps. Default is len(sequence).
|
||||
completed (int, optional): Number of steps completed so far. Defaults to 0.
|
||||
|
@ -1192,7 +1190,7 @@ class Progress(JupyterMixin):
|
|||
|
||||
def track(
|
||||
self,
|
||||
sequence: Union[Iterable[ProgressType], Sequence[ProgressType]],
|
||||
sequence: Iterable[ProgressType],
|
||||
total: Optional[float] = None,
|
||||
completed: int = 0,
|
||||
task_id: Optional[TaskID] = None,
|
||||
|
@ -1201,8 +1199,10 @@ class Progress(JupyterMixin):
|
|||
) -> Iterable[ProgressType]:
|
||||
"""Track progress by iterating over a sequence.
|
||||
|
||||
You can also track progress of an iterable, which might require that you additionally specify ``total``.
|
||||
|
||||
Args:
|
||||
sequence (Sequence[ProgressType]): A sequence of values you want to iterate over and track progress.
|
||||
sequence (Iterable[ProgressType]): Values you want to iterate over and track progress.
|
||||
total: (float, optional): Total number of steps. Default is len(sequence).
|
||||
completed (int, optional): Number of steps completed so far. Defaults to 0.
|
||||
task_id: (TaskID): Task to track. Default is new task.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import cast, List, Optional, TYPE_CHECKING, Union
|
||||
from typing import TYPE_CHECKING, List, Optional, Union, cast
|
||||
|
||||
from ._spinners import SPINNERS
|
||||
from .measure import Measurement
|
||||
|
@ -6,7 +6,7 @@ from .table import Table
|
|||
from .text import Text
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .console import Console, ConsoleOptions, RenderResult, RenderableType
|
||||
from .console import Console, ConsoleOptions, RenderableType, RenderResult
|
||||
from .style import StyleType
|
||||
|
||||
|
||||
|
@ -117,22 +117,16 @@ class Spinner:
|
|||
if __name__ == "__main__": # pragma: no cover
|
||||
from time import sleep
|
||||
|
||||
from .columns import Columns
|
||||
from .panel import Panel
|
||||
from .console import Group
|
||||
from .live import Live
|
||||
|
||||
all_spinners = Columns(
|
||||
[
|
||||
all_spinners = Group(
|
||||
*[
|
||||
Spinner(spinner_name, text=Text(repr(spinner_name), style="green"))
|
||||
for spinner_name in sorted(SPINNERS.keys())
|
||||
],
|
||||
column_first=True,
|
||||
expand=True,
|
||||
]
|
||||
)
|
||||
|
||||
with Live(
|
||||
Panel(all_spinners, title="Spinners", border_style="blue"),
|
||||
refresh_per_second=20,
|
||||
) as live:
|
||||
with Live(all_spinners, refresh_per_second=20) as live:
|
||||
while True:
|
||||
sleep(0.1)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import os.path
|
||||
import re
|
||||
import sys
|
||||
|
@ -224,6 +226,17 @@ class _SyntaxHighlightRange(NamedTuple):
|
|||
style_before: bool = False
|
||||
|
||||
|
||||
class PaddingProperty:
|
||||
"""Descriptor to get and set padding."""
|
||||
|
||||
def __get__(self, obj: Syntax, objtype: Type[Syntax]) -> Tuple[int, int, int, int]:
|
||||
"""Space around the Syntax."""
|
||||
return obj._padding
|
||||
|
||||
def __set__(self, obj: Syntax, padding: PaddingDimensions) -> None:
|
||||
obj._padding = Padding.unpack(padding)
|
||||
|
||||
|
||||
class Syntax(JupyterMixin):
|
||||
"""Construct a Syntax object to render syntax highlighted code.
|
||||
|
||||
|
@ -293,11 +306,13 @@ class Syntax(JupyterMixin):
|
|||
Style(bgcolor=background_color) if background_color else Style()
|
||||
)
|
||||
self.indent_guides = indent_guides
|
||||
self.padding = padding
|
||||
self._padding = Padding.unpack(padding)
|
||||
|
||||
self._theme = self.get_theme(theme)
|
||||
self._stylized_ranges: List[_SyntaxHighlightRange] = []
|
||||
|
||||
padding = PaddingProperty()
|
||||
|
||||
@classmethod
|
||||
def from_path(
|
||||
cls,
|
||||
|
@ -371,8 +386,8 @@ class Syntax(JupyterMixin):
|
|||
is supplied, the lexer will be chosen based on the file extension..
|
||||
|
||||
Args:
|
||||
path (AnyStr): The path to the file containing the code you wish to know the lexer for.
|
||||
code (str, optional): Optional string of code that will be used as a fallback if no lexer
|
||||
path (AnyStr): The path to the file containing the code you wish to know the lexer for.
|
||||
code (str, optional): Optional string of code that will be used as a fallback if no lexer
|
||||
is found for the supplied path.
|
||||
|
||||
Returns:
|
||||
|
@ -607,7 +622,7 @@ class Syntax(JupyterMixin):
|
|||
def __rich_measure__(
|
||||
self, console: "Console", options: "ConsoleOptions"
|
||||
) -> "Measurement":
|
||||
_, right, _, left = Padding.unpack(self.padding)
|
||||
_, right, _, left = self.padding
|
||||
padding = left + right
|
||||
if self.code_width is not None:
|
||||
width = self.code_width + self._numbers_column_width + padding + 1
|
||||
|
@ -626,7 +641,7 @@ class Syntax(JupyterMixin):
|
|||
self, console: Console, options: ConsoleOptions
|
||||
) -> RenderResult:
|
||||
segments = Segments(self._get_syntax(console, options))
|
||||
if self.padding:
|
||||
if any(self.padding):
|
||||
yield Padding(segments, style=self._get_base_style(), pad=self.padding)
|
||||
else:
|
||||
yield segments
|
||||
|
@ -640,15 +655,19 @@ class Syntax(JupyterMixin):
|
|||
Get the Segments for the Syntax object, excluding any vertical/horizontal padding
|
||||
"""
|
||||
transparent_background = self._get_base_style().transparent_background
|
||||
_pad_top, pad_right, _pad_bottom, pad_left = self.padding
|
||||
horizontal_padding = pad_left + pad_right
|
||||
code_width = (
|
||||
(
|
||||
(options.max_width - self._numbers_column_width - 1)
|
||||
if self.line_numbers
|
||||
else options.max_width
|
||||
)
|
||||
- horizontal_padding
|
||||
if self.code_width is None
|
||||
else self.code_width
|
||||
)
|
||||
code_width = max(0, code_width)
|
||||
|
||||
ends_on_nl, processed_code = self._process_code(self.code)
|
||||
text = self.highlight(processed_code, self.line_range)
|
||||
|
|
|
@ -14,6 +14,7 @@ from typing import (
|
|||
List,
|
||||
Optional,
|
||||
Sequence,
|
||||
Set,
|
||||
Tuple,
|
||||
Type,
|
||||
Union,
|
||||
|
@ -418,6 +419,7 @@ class Traceback:
|
|||
locals_max_string: int = LOCALS_MAX_STRING,
|
||||
locals_hide_dunder: bool = True,
|
||||
locals_hide_sunder: bool = False,
|
||||
_visited_exceptions: Optional[Set[BaseException]] = None,
|
||||
) -> Trace:
|
||||
"""Extract traceback information.
|
||||
|
||||
|
@ -443,6 +445,10 @@ class Traceback:
|
|||
|
||||
notes: List[str] = getattr(exc_value, "__notes__", None) or []
|
||||
|
||||
grouped_exceptions: Set[BaseException] = (
|
||||
set() if _visited_exceptions is None else _visited_exceptions
|
||||
)
|
||||
|
||||
def safe_str(_object: Any) -> str:
|
||||
"""Don't allow exceptions from __str__ to propagate."""
|
||||
try:
|
||||
|
@ -462,6 +468,9 @@ class Traceback:
|
|||
if isinstance(exc_value, (BaseExceptionGroup, ExceptionGroup)):
|
||||
stack.is_group = True
|
||||
for exception in exc_value.exceptions:
|
||||
if exception in grouped_exceptions:
|
||||
continue
|
||||
grouped_exceptions.add(exception)
|
||||
stack.exceptions.append(
|
||||
Traceback.extract(
|
||||
type(exception),
|
||||
|
@ -471,6 +480,7 @@ class Traceback:
|
|||
locals_max_length=locals_max_length,
|
||||
locals_hide_dunder=locals_hide_dunder,
|
||||
locals_hide_sunder=locals_hide_sunder,
|
||||
_visited_exceptions=grouped_exceptions,
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -561,23 +571,26 @@ class Traceback:
|
|||
if frame_summary.f_locals.get("_rich_traceback_guard", False):
|
||||
del stack.frames[:]
|
||||
|
||||
cause = getattr(exc_value, "__cause__", None)
|
||||
if cause:
|
||||
exc_type = cause.__class__
|
||||
exc_value = cause
|
||||
# __traceback__ can be None, e.g. for exceptions raised by the
|
||||
# 'multiprocessing' module
|
||||
traceback = cause.__traceback__
|
||||
is_cause = True
|
||||
continue
|
||||
if not grouped_exceptions:
|
||||
cause = getattr(exc_value, "__cause__", None)
|
||||
if cause is not None and cause is not exc_value:
|
||||
exc_type = cause.__class__
|
||||
exc_value = cause
|
||||
# __traceback__ can be None, e.g. for exceptions raised by the
|
||||
# 'multiprocessing' module
|
||||
traceback = cause.__traceback__
|
||||
is_cause = True
|
||||
continue
|
||||
|
||||
cause = exc_value.__context__
|
||||
if cause and not getattr(exc_value, "__suppress_context__", False):
|
||||
exc_type = cause.__class__
|
||||
exc_value = cause
|
||||
traceback = cause.__traceback__
|
||||
is_cause = False
|
||||
continue
|
||||
cause = exc_value.__context__
|
||||
if cause is not None and not getattr(
|
||||
exc_value, "__suppress_context__", False
|
||||
):
|
||||
exc_type = cause.__class__
|
||||
exc_value = cause
|
||||
traceback = cause.__traceback__
|
||||
is_cause = False
|
||||
continue
|
||||
# No cover, code is reached but coverage doesn't recognize it.
|
||||
break # pragma: no cover
|
||||
|
||||
|
|
|
@ -713,14 +713,6 @@ def test_quiet() -> None:
|
|||
assert console.file.getvalue() == ""
|
||||
|
||||
|
||||
def test_no_nested_live() -> None:
|
||||
console = Console()
|
||||
with pytest.raises(errors.LiveError):
|
||||
with console.status("foo"):
|
||||
with console.status("bar"):
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows")
|
||||
def test_screen() -> None:
|
||||
console = Console(
|
||||
|
@ -1046,6 +1038,31 @@ def test_capture_and_record() -> None:
|
|||
assert recorded_content == "Print 0\n"
|
||||
|
||||
|
||||
def test_tty_interactive() -> None:
|
||||
"""Check TTY_INTERACTIVE environment var."""
|
||||
|
||||
# Bytes file, not interactive
|
||||
console = Console(file=io.BytesIO())
|
||||
assert not console.is_interactive
|
||||
|
||||
# Bytes file, force interactive
|
||||
console = Console(file=io.BytesIO(), _environ={"TTY_INTERACTIVE": "1"})
|
||||
assert console.is_interactive
|
||||
|
||||
# Force tty compatible, should be interactive
|
||||
console = Console(file=io.BytesIO(), _environ={"TTY_COMPATIBLE": "1"})
|
||||
assert console.is_interactive
|
||||
|
||||
# Force tty compatible, force not interactive
|
||||
console = Console(
|
||||
file=io.BytesIO(), _environ={"TTY_COMPATIBLE": "1", "TTY_INTERACTIVE": "0"}
|
||||
)
|
||||
|
||||
# Bytes file, Unknown value of TTY_INTERACTIVE should still auto-detect
|
||||
console = Console(file=io.BytesIO(), _environ={"TTY_INTERACTIVE": "foo"})
|
||||
assert not console.is_interactive
|
||||
|
||||
|
||||
def test_tty_compatible() -> None:
|
||||
"""Check TTY_COMPATIBLE environment var."""
|
||||
|
||||
|
@ -1087,7 +1104,7 @@ def test_tty_compatible() -> None:
|
|||
console = Console(file=FakeTTY())
|
||||
# Should report True
|
||||
assert console.is_terminal
|
||||
# SHould have auto-detected
|
||||
# Should have auto-detected
|
||||
assert console.file.called_isatty
|
||||
|
||||
# File is a fake TTY
|
||||
|
|
|
@ -26,7 +26,7 @@ def test_live_state() -> None:
|
|||
assert live._started
|
||||
live.start()
|
||||
|
||||
assert live.renderable == ""
|
||||
assert live.get_renderable() == ""
|
||||
|
||||
assert live._started
|
||||
live.stop()
|
||||
|
|
|
@ -160,9 +160,3 @@ def test_markup_and_highlight():
|
|||
render_plain = handler.console.file.getvalue()
|
||||
assert "FORMATTER" in render_plain
|
||||
assert log_message in render_plain
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
render = make_log()
|
||||
print(render)
|
||||
print(repr(render))
|
||||
|
|
|
@ -110,7 +110,7 @@ def test_inline_code():
|
|||
inline_code_theme="emacs",
|
||||
)
|
||||
result = render(markdown)
|
||||
expected = "inline \x1b[1;38;2;170;34;255;48;2;248;248;248mimport\x1b[0m\x1b[38;2;0;0;0;48;2;248;248;248m \x1b[0m\x1b[1;38;2;0;0;255;48;2;248;248;248mthis\x1b[0m code \n"
|
||||
expected = "inline \x1b[1;38;2;170;34;255;48;2;248;248;248mimport\x1b[0m\x1b[38;2;187;187;187;48;2;248;248;248m \x1b[0m\x1b[1;38;2;0;0;255;48;2;248;248;248mthis\x1b[0m code \n"
|
||||
print(result)
|
||||
print(repr(result))
|
||||
assert result == expected
|
||||
|
|
|
@ -2,6 +2,7 @@ import io
|
|||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
from importlib.metadata import Distribution
|
||||
|
||||
import pytest
|
||||
from pygments.lexers import PythonLexer
|
||||
|
@ -20,11 +21,6 @@ from rich.syntax import (
|
|||
|
||||
from .render import render
|
||||
|
||||
if sys.version_info >= (3, 8):
|
||||
from importlib.metadata import Distribution
|
||||
else:
|
||||
from importlib_metadata import Distribution
|
||||
|
||||
PYGMENTS_VERSION = Distribution.from_name("pygments").version
|
||||
OLD_PYGMENTS = PYGMENTS_VERSION == "2.13.0"
|
||||
|
||||
|
@ -44,7 +40,7 @@ def loop_first_last(values: Iterable[T]) -> Iterable[Tuple[bool, bool, T]]:
|
|||
yield first, True, previous_value'''
|
||||
|
||||
|
||||
def test_blank_lines():
|
||||
def test_blank_lines() -> None:
|
||||
code = "\n\nimport this\n\n"
|
||||
syntax = Syntax(
|
||||
code, lexer="python", theme="ascii_light", code_width=30, line_numbers=True
|
||||
|
@ -53,11 +49,11 @@ def test_blank_lines():
|
|||
print(repr(result))
|
||||
assert (
|
||||
result
|
||||
== "\x1b[1;38;2;24;24;24;48;2;248;248;248m \x1b[0m\x1b[38;2;173;173;173;48;2;248;248;248m1 \x1b[0m\x1b[48;2;248;248;248m \x1b[0m\n\x1b[1;38;2;24;24;24;48;2;248;248;248m \x1b[0m\x1b[38;2;173;173;173;48;2;248;248;248m2 \x1b[0m\x1b[48;2;248;248;248m \x1b[0m\n\x1b[1;38;2;24;24;24;48;2;248;248;248m \x1b[0m\x1b[38;2;173;173;173;48;2;248;248;248m3 \x1b[0m\x1b[1;38;2;0;128;0;48;2;248;248;248mimport\x1b[0m\x1b[38;2;0;0;0;48;2;248;248;248m \x1b[0m\x1b[1;38;2;0;0;255;48;2;248;248;248mthis\x1b[0m\x1b[48;2;248;248;248m \x1b[0m\n\x1b[1;38;2;24;24;24;48;2;248;248;248m \x1b[0m\x1b[38;2;173;173;173;48;2;248;248;248m4 \x1b[0m\x1b[48;2;248;248;248m \x1b[0m\n\x1b[1;38;2;24;24;24;48;2;248;248;248m \x1b[0m\x1b[38;2;173;173;173;48;2;248;248;248m5 \x1b[0m\x1b[48;2;248;248;248m \x1b[0m\n"
|
||||
== "\x1b[1;38;2;24;24;24;48;2;248;248;248m \x1b[0m\x1b[38;2;173;173;173;48;2;248;248;248m1 \x1b[0m\x1b[48;2;248;248;248m \x1b[0m\n\x1b[1;38;2;24;24;24;48;2;248;248;248m \x1b[0m\x1b[38;2;173;173;173;48;2;248;248;248m2 \x1b[0m\x1b[48;2;248;248;248m \x1b[0m\n\x1b[1;38;2;24;24;24;48;2;248;248;248m \x1b[0m\x1b[38;2;173;173;173;48;2;248;248;248m3 \x1b[0m\x1b[1;38;2;0;128;0;48;2;248;248;248mimport\x1b[0m\x1b[38;2;187;187;187;48;2;248;248;248m \x1b[0m\x1b[1;38;2;0;0;255;48;2;248;248;248mthis\x1b[0m\x1b[48;2;248;248;248m \x1b[0m\n\x1b[1;38;2;24;24;24;48;2;248;248;248m \x1b[0m\x1b[38;2;173;173;173;48;2;248;248;248m4 \x1b[0m\x1b[48;2;248;248;248m \x1b[0m\n\x1b[1;38;2;24;24;24;48;2;248;248;248m \x1b[0m\x1b[38;2;173;173;173;48;2;248;248;248m5 \x1b[0m\x1b[48;2;248;248;248m \x1b[0m\n"
|
||||
)
|
||||
|
||||
|
||||
def test_python_render():
|
||||
def test_python_render() -> None:
|
||||
syntax = Panel.fit(
|
||||
Syntax(
|
||||
CODE,
|
||||
|
@ -76,7 +72,7 @@ def test_python_render():
|
|||
assert rendered_syntax == expected
|
||||
|
||||
|
||||
def test_python_render_simple():
|
||||
def test_python_render_simple() -> None:
|
||||
syntax = Syntax(
|
||||
CODE,
|
||||
lexer="python",
|
||||
|
@ -91,7 +87,7 @@ def test_python_render_simple():
|
|||
assert rendered_syntax == expected
|
||||
|
||||
|
||||
def test_python_render_simple_passing_lexer_instance():
|
||||
def test_python_render_simple_passing_lexer_instance() -> None:
|
||||
syntax = Syntax(
|
||||
CODE,
|
||||
lexer=PythonLexer(),
|
||||
|
@ -107,7 +103,7 @@ def test_python_render_simple_passing_lexer_instance():
|
|||
|
||||
|
||||
@pytest.mark.skipif(OLD_PYGMENTS, reason="Pygments changed their tokenizer")
|
||||
def test_python_render_simple_indent_guides():
|
||||
def test_python_render_simple_indent_guides() -> None:
|
||||
syntax = Syntax(
|
||||
CODE,
|
||||
lexer="python",
|
||||
|
@ -119,12 +115,12 @@ def test_python_render_simple_indent_guides():
|
|||
)
|
||||
rendered_syntax = render(syntax)
|
||||
print(repr(rendered_syntax))
|
||||
expected = '\x1b[34mdef\x1b[0m \x1b[32mloop_first_last\x1b[0m(values: Iterable[T]) -> Iterable[Tuple[\x1b[36mb\x1b[0m\n\x1b[2;37m│ \x1b[0m\x1b[33m"""Iterate and generate a tuple with a flag for first an\x1b[0m\n\x1b[2m│ \x1b[0miter_values = \x1b[36miter\x1b[0m(values)\n\x1b[2m│ \x1b[0m\x1b[34mtry\x1b[0m:\n\x1b[2m│ │ \x1b[0mprevious_value = \x1b[36mnext\x1b[0m(iter_values)\n\x1b[2m│ \x1b[0m\x1b[34mexcept\x1b[0m \x1b[36mStopIteration\x1b[0m:\n\x1b[2m│ │ \x1b[0m\x1b[34mreturn\x1b[0m\n\x1b[2m│ \x1b[0mfirst = \x1b[34mTrue\x1b[0m\n\x1b[2m│ \x1b[0m\x1b[34mfor\x1b[0m value \x1b[35min\x1b[0m iter_values:\n\x1b[2m│ │ \x1b[0m\x1b[34myield\x1b[0m first, \x1b[34mFalse\x1b[0m, previous_value\n\x1b[2m│ │ \x1b[0mfirst = \x1b[34mFalse\x1b[0m\n\x1b[2m│ │ \x1b[0mprevious_value = value\n\x1b[2m│ \x1b[0m\x1b[34myield\x1b[0m first, \x1b[34mTrue\x1b[0m, previous_value\n'
|
||||
expected = '\x1b[34mdef\x1b[0m\x1b[37m \x1b[0m\x1b[32mloop_first_last\x1b[0m(values: Iterable[T]) -> Iterable[Tuple[\x1b[36mb\x1b[0m\n\x1b[2;37m│ \x1b[0m\x1b[33m"""Iterate and generate a tuple with a flag for first an\x1b[0m\n\x1b[2m│ \x1b[0miter_values = \x1b[36miter\x1b[0m(values)\n\x1b[2m│ \x1b[0m\x1b[34mtry\x1b[0m:\n\x1b[2m│ │ \x1b[0mprevious_value = \x1b[36mnext\x1b[0m(iter_values)\n\x1b[2m│ \x1b[0m\x1b[34mexcept\x1b[0m \x1b[36mStopIteration\x1b[0m:\n\x1b[2m│ │ \x1b[0m\x1b[34mreturn\x1b[0m\n\x1b[2m│ \x1b[0mfirst = \x1b[34mTrue\x1b[0m\n\x1b[2m│ \x1b[0m\x1b[34mfor\x1b[0m value \x1b[35min\x1b[0m iter_values:\n\x1b[2m│ │ \x1b[0m\x1b[34myield\x1b[0m first, \x1b[34mFalse\x1b[0m, previous_value\n\x1b[2m│ │ \x1b[0mfirst = \x1b[34mFalse\x1b[0m\n\x1b[2m│ │ \x1b[0mprevious_value = value\n\x1b[2m│ \x1b[0m\x1b[34myield\x1b[0m first, \x1b[34mTrue\x1b[0m, previous_value\n'
|
||||
assert rendered_syntax == expected
|
||||
|
||||
|
||||
@pytest.mark.skipif(OLD_PYGMENTS, reason="Pygments changed their tokenizer")
|
||||
def test_python_render_line_range_indent_guides():
|
||||
def test_python_render_line_range_indent_guides() -> None:
|
||||
syntax = Syntax(
|
||||
CODE,
|
||||
lexer="python",
|
||||
|
@ -141,7 +137,7 @@ def test_python_render_line_range_indent_guides():
|
|||
assert rendered_syntax == expected
|
||||
|
||||
|
||||
def test_python_render_indent_guides():
|
||||
def test_python_render_indent_guides() -> None:
|
||||
syntax = Panel.fit(
|
||||
Syntax(
|
||||
CODE,
|
||||
|
@ -161,19 +157,19 @@ def test_python_render_indent_guides():
|
|||
assert rendered_syntax == expected
|
||||
|
||||
|
||||
def test_pygments_syntax_theme_non_str():
|
||||
def test_pygments_syntax_theme_non_str() -> None:
|
||||
from pygments.style import Style as PygmentsStyle
|
||||
|
||||
style = PygmentsSyntaxTheme(PygmentsStyle())
|
||||
assert style.get_background_style().bgcolor == Color.parse("#ffffff")
|
||||
|
||||
|
||||
def test_pygments_syntax_theme():
|
||||
def test_pygments_syntax_theme() -> None:
|
||||
style = PygmentsSyntaxTheme("default")
|
||||
assert style.get_style_for_token("abc") == Style.parse("none")
|
||||
|
||||
|
||||
def test_get_line_color_none():
|
||||
def test_get_line_color_none() -> None:
|
||||
style = PygmentsSyntaxTheme("default")
|
||||
style._background_style = Style(bgcolor=None)
|
||||
syntax = Syntax(
|
||||
|
@ -189,7 +185,7 @@ def test_get_line_color_none():
|
|||
assert syntax._get_line_numbers_color() == Color.default()
|
||||
|
||||
|
||||
def test_highlight_background_color():
|
||||
def test_highlight_background_color() -> None:
|
||||
syntax = Syntax(
|
||||
CODE,
|
||||
lexer="python",
|
||||
|
@ -203,7 +199,7 @@ def test_highlight_background_color():
|
|||
assert syntax.highlight(CODE).style == Style.parse("on red")
|
||||
|
||||
|
||||
def test_get_number_styles():
|
||||
def test_get_number_styles() -> None:
|
||||
syntax = Syntax(CODE, "python", theme="monokai", line_numbers=True)
|
||||
console = Console(color_system="windows")
|
||||
assert syntax._get_number_styles(console=console) == (
|
||||
|
@ -213,7 +209,7 @@ def test_get_number_styles():
|
|||
)
|
||||
|
||||
|
||||
def test_get_style_for_token():
|
||||
def test_get_style_for_token() -> None:
|
||||
# from pygments.style import Style as PygmentsStyle
|
||||
# pygments_style = PygmentsStyle()
|
||||
from pygments.style import Token
|
||||
|
@ -234,7 +230,7 @@ def test_get_style_for_token():
|
|||
assert syntax._get_line_numbers_color() == Color.default()
|
||||
|
||||
|
||||
def test_option_no_wrap():
|
||||
def test_option_no_wrap() -> None:
|
||||
syntax = Syntax(
|
||||
CODE,
|
||||
lexer="python",
|
||||
|
@ -251,7 +247,7 @@ def test_option_no_wrap():
|
|||
assert rendered_syntax == expected
|
||||
|
||||
|
||||
def test_syntax_highlight_ranges():
|
||||
def test_syntax_highlight_ranges() -> None:
|
||||
syntax = Syntax(
|
||||
CODE,
|
||||
lexer="python",
|
||||
|
@ -306,7 +302,7 @@ def test_syntax_highlight_ranges():
|
|||
assert rendered_syntax == expected
|
||||
|
||||
|
||||
def test_ansi_theme():
|
||||
def test_ansi_theme() -> None:
|
||||
style = Style(color="red")
|
||||
theme = ANSISyntaxTheme({("foo", "bar"): style})
|
||||
assert theme.get_style_for_token(("foo", "bar", "baz")) == style
|
||||
|
@ -319,7 +315,7 @@ skip_windows_permission_error = pytest.mark.skipif(
|
|||
|
||||
|
||||
@skip_windows_permission_error
|
||||
def test_from_path():
|
||||
def test_from_path() -> None:
|
||||
fh, path = tempfile.mkstemp("example.py")
|
||||
try:
|
||||
os.write(fh, b"import this\n")
|
||||
|
@ -332,7 +328,7 @@ def test_from_path():
|
|||
|
||||
|
||||
@skip_windows_permission_error
|
||||
def test_from_path_unknown_lexer():
|
||||
def test_from_path_unknown_lexer() -> None:
|
||||
fh, path = tempfile.mkstemp("example.nosuchtype")
|
||||
try:
|
||||
os.write(fh, b"import this\n")
|
||||
|
@ -344,7 +340,7 @@ def test_from_path_unknown_lexer():
|
|||
|
||||
|
||||
@skip_windows_permission_error
|
||||
def test_from_path_lexer_override():
|
||||
def test_from_path_lexer_override() -> None:
|
||||
fh, path = tempfile.mkstemp("example.nosuchtype")
|
||||
try:
|
||||
os.write(fh, b"import this\n")
|
||||
|
@ -356,7 +352,7 @@ def test_from_path_lexer_override():
|
|||
|
||||
|
||||
@skip_windows_permission_error
|
||||
def test_from_path_lexer_override_invalid_lexer():
|
||||
def test_from_path_lexer_override_invalid_lexer() -> None:
|
||||
fh, path = tempfile.mkstemp("example.nosuchtype")
|
||||
try:
|
||||
os.write(fh, b"import this\n")
|
||||
|
@ -367,7 +363,7 @@ def test_from_path_lexer_override_invalid_lexer():
|
|||
os.remove(path)
|
||||
|
||||
|
||||
def test_syntax_guess_lexer():
|
||||
def test_syntax_guess_lexer() -> None:
|
||||
assert Syntax.guess_lexer("banana.py") == "python"
|
||||
assert Syntax.guess_lexer("banana.py", "import this") == "python"
|
||||
assert Syntax.guess_lexer("banana.html", "<a href='#'>hello</a>") == "html"
|
||||
|
@ -375,7 +371,7 @@ def test_syntax_guess_lexer():
|
|||
assert Syntax.guess_lexer("banana.html", "{{something|filter:3}}") == "html+django"
|
||||
|
||||
|
||||
def test_syntax_padding():
|
||||
def test_syntax_padding() -> None:
|
||||
syntax = Syntax("x = 1", lexer="python", padding=(1, 3))
|
||||
console = Console(
|
||||
width=20,
|
||||
|
@ -391,7 +387,7 @@ def test_syntax_padding():
|
|||
)
|
||||
|
||||
|
||||
def test_syntax_measure():
|
||||
def test_syntax_measure() -> None:
|
||||
console = Console()
|
||||
code = Syntax("Hello, World", "python")
|
||||
assert code.__rich_measure__(console, console.options) == Measurement(0, 12)
|
||||
|
@ -406,7 +402,7 @@ def test_syntax_measure():
|
|||
assert code.__rich_measure__(console, console.options) == Measurement(3, 24)
|
||||
|
||||
|
||||
def test_background_color_override_includes_padding():
|
||||
def test_background_color_override_includes_padding() -> None:
|
||||
"""Regression test for https://github.com/Textualize/rich/issues/3295"""
|
||||
|
||||
syntax = Syntax(
|
||||
|
@ -423,6 +419,22 @@ def test_background_color_override_includes_padding():
|
|||
)
|
||||
|
||||
|
||||
def test_padding_plus_wrap() -> None:
|
||||
"""Regression test for https://github.com/Textualize/rich/issues/3727"""
|
||||
console = Console(width=24, file=io.StringIO(), legacy_windows=False)
|
||||
syntax = Syntax(
|
||||
"'Hello, World. This should wrap.'",
|
||||
lexer="python",
|
||||
padding=(0, 3),
|
||||
word_wrap=True,
|
||||
)
|
||||
console.print(syntax)
|
||||
output = console.file.getvalue()
|
||||
print(repr(output))
|
||||
expected = " 'Hello, World. \n This should wrap.' \n"
|
||||
assert output == expected
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
syntax = Panel.fit(
|
||||
Syntax(
|
||||
|
|
|
@ -373,3 +373,27 @@ def test_notes() -> None:
|
|||
traceback = Traceback()
|
||||
|
||||
assert traceback.trace.stacks[0].notes == ["Hello", "World"]
|
||||
|
||||
|
||||
def test_recursive_exception() -> None:
|
||||
"""Regression test for https://github.com/Textualize/rich/issues/3708
|
||||
|
||||
Test this doesn't create an infinite loop.
|
||||
|
||||
"""
|
||||
console = Console()
|
||||
|
||||
def foo() -> None:
|
||||
try:
|
||||
raise RuntimeError("Hello")
|
||||
except Exception as e:
|
||||
raise e from e
|
||||
|
||||
def bar() -> None:
|
||||
try:
|
||||
foo()
|
||||
except Exception as e:
|
||||
assert e is e.__cause__
|
||||
console.print_exception(show_locals=True)
|
||||
|
||||
bar()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue