Merge branch 'master' of github.com:Textualize/rich

This commit is contained in:
Darren Burns 2022-03-21 09:51:09 +00:00
commit a8d2bb2004
No known key found for this signature in database
GPG key ID: B0939B45037DC345
12 changed files with 126 additions and 92 deletions

View file

@ -0,0 +1,24 @@
on:
release:
types: [ released ]
jobs:
asv-publish-and-copy:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: '3.10.2'
- run: 'pip install asv'
- run: 'asv publish'
- uses: pina/github-action-push-to-another-repository@v1.4.1
name: 'Copy files to Textualize/rich-benchmarks repo'
env:
API_TOKEN_GITHUB: ${{ secrets.PUBLISH_ASV }}
with:
source-directory: /benchmarks/html
destination-github-username: Textualize
destination-repository-name: rich-benchmarks
user-email: darren@textualize.io

View file

@ -10,12 +10,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- Improve performance of cell_length https://github.com/Textualize/rich/pull/2061 - Improve performance of cell_length https://github.com/Textualize/rich/pull/2061
- Improve performance of chop_cells https://github.com/Textualize/rich/pull/2077
## [12.0.1] - 2022-03-14 ## [12.0.1] - 2022-03-14
### Fixed ### Fixed
- Fix capturing stdout on legacy Windows https://github.com/Textualize/rich/pull/2055 - Fix capturing stdout on legacy Windows https://github.com/Textualize/rich/pull/2066
## [12.0.0] - 2022-03-10 ## [12.0.0] - 2022-03-10

76
poetry.lock generated
View file

@ -356,7 +356,7 @@ python-versions = "*"
[[package]] [[package]]
name = "ipywidgets" name = "ipywidgets"
version = "7.6.5" version = "7.7.0"
description = "IPython HTML widgets for Jupyter" description = "IPython HTML widgets for Jupyter"
category = "main" category = "main"
optional = true optional = true
@ -369,7 +369,7 @@ ipython-genutils = ">=0.2.0,<0.3.0"
jupyterlab-widgets = {version = ">=1.0.0", markers = "python_version >= \"3.6\""} jupyterlab-widgets = {version = ">=1.0.0", markers = "python_version >= \"3.6\""}
nbformat = ">=4.2.0" nbformat = ">=4.2.0"
traitlets = ">=4.3.1" traitlets = ">=4.3.1"
widgetsnbextension = ">=3.5.0,<3.6.0" widgetsnbextension = ">=3.6.0,<3.7.0"
[package.extras] [package.extras]
test = ["pytest (>=3.6.0)", "pytest-cov", "mock"] test = ["pytest (>=3.6.0)", "pytest-cov", "mock"]
@ -466,7 +466,7 @@ pygments = ">=2.4.1,<3"
[[package]] [[package]]
name = "jupyterlab-widgets" name = "jupyterlab-widgets"
version = "1.0.2" version = "1.1.0"
description = "A JupyterLab extension." description = "A JupyterLab extension."
category = "main" category = "main"
optional = true optional = true
@ -490,7 +490,7 @@ python-versions = "*"
[[package]] [[package]]
name = "mypy" name = "mypy"
version = "0.931" version = "0.941"
description = "Optional static typing for Python" description = "Optional static typing for Python"
category = "dev" category = "dev"
optional = false optional = false
@ -505,6 +505,7 @@ typing-extensions = ">=3.10"
[package.extras] [package.extras]
dmypy = ["psutil (>=4.0)"] dmypy = ["psutil (>=4.0)"]
python2 = ["typed-ast (>=1.4.0,<2)"] python2 = ["typed-ast (>=1.4.0,<2)"]
reports = ["lxml"]
[[package]] [[package]]
name = "mypy-extensions" name = "mypy-extensions"
@ -600,7 +601,7 @@ python-versions = "*"
[[package]] [[package]]
name = "notebook" name = "notebook"
version = "6.4.8" version = "6.4.10"
description = "A web-based notebook environment for interactive computing" description = "A web-based notebook environment for interactive computing"
category = "main" category = "main"
optional = true optional = true
@ -613,7 +614,7 @@ ipython-genutils = "*"
jinja2 = "*" jinja2 = "*"
jupyter-client = ">=5.3.4" jupyter-client = ">=5.3.4"
jupyter-core = ">=4.6.1" jupyter-core = ">=4.6.1"
nbconvert = "*" nbconvert = ">=5"
nbformat = "*" nbformat = "*"
nest-asyncio = ">=1.5" nest-asyncio = ">=1.5"
prometheus-client = "*" prometheus-client = "*"
@ -1037,7 +1038,7 @@ python-versions = "*"
[[package]] [[package]]
name = "widgetsnbextension" name = "widgetsnbextension"
version = "3.5.2" version = "3.6.0"
description = "IPython HTML widgets for Jupyter" description = "IPython HTML widgets for Jupyter"
category = "main" category = "main"
optional = true optional = true
@ -1064,7 +1065,7 @@ jupyter = ["ipywidgets"]
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.6.2" python-versions = "^3.6.2"
content-hash = "5ce16f2949f71818ef5552c9001615a07b6e604a6291ff34b0f5fdc29a684cdc" content-hash = "9d010fc1dade302bb784d0607a4c23d00e89f6709572310452428d347ff8b89a"
[metadata.files] [metadata.files]
appnope = [ appnope = [
@ -1316,8 +1317,8 @@ ipython-genutils = [
{file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"}, {file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"},
] ]
ipywidgets = [ ipywidgets = [
{file = "ipywidgets-7.6.5-py2.py3-none-any.whl", hash = "sha256:d258f582f915c62ea91023299603be095de19afb5ee271698f88327b9fe9bf43"}, {file = "ipywidgets-7.7.0-py2.py3-none-any.whl", hash = "sha256:e58ff58bc94d481e91ecb6e13a5cb96a87b6b8ade135e055603d0ca24593df38"},
{file = "ipywidgets-7.6.5.tar.gz", hash = "sha256:00974f7cb4d5f8d494c19810fedb9fa9b64bffd3cda7c2be23c133a1ad3c99c5"}, {file = "ipywidgets-7.7.0.tar.gz", hash = "sha256:ab4a5596855a88b83761921c768707d65e5847068139bc1729ddfe834703542a"},
] ]
jedi = [ jedi = [
{file = "jedi-0.17.2-py2.py3-none-any.whl", hash = "sha256:98cc583fa0f2f8304968199b01b6b4b94f469a1f4a74c1560506ca2a211378b5"}, {file = "jedi-0.17.2-py2.py3-none-any.whl", hash = "sha256:98cc583fa0f2f8304968199b01b6b4b94f469a1f4a74c1560506ca2a211378b5"},
@ -1344,8 +1345,8 @@ jupyterlab-pygments = [
{file = "jupyterlab_pygments-0.1.2.tar.gz", hash = "sha256:cfcda0873626150932f438eccf0f8bf22bfa92345b814890ab360d666b254146"}, {file = "jupyterlab_pygments-0.1.2.tar.gz", hash = "sha256:cfcda0873626150932f438eccf0f8bf22bfa92345b814890ab360d666b254146"},
] ]
jupyterlab-widgets = [ jupyterlab-widgets = [
{file = "jupyterlab_widgets-1.0.2-py3-none-any.whl", hash = "sha256:f5d9efface8ec62941173ba1cffb2edd0ecddc801c11ae2931e30b50492eb8f7"}, {file = "jupyterlab_widgets-1.1.0-py3-none-any.whl", hash = "sha256:c2a9bd3789f120f64d73268c066ed3b000c56bc1dda217be5cdc43e7b4ebad3f"},
{file = "jupyterlab_widgets-1.0.2.tar.gz", hash = "sha256:7885092b2b96bf189c3a705cc3c412a4472ec5e8382d0b47219a66cccae73cfa"}, {file = "jupyterlab_widgets-1.1.0.tar.gz", hash = "sha256:d5f41bc1713795385f718d44dcba47e1e1473c6289f28a95aa6b2c0782ee372a"},
] ]
markupsafe = [ markupsafe = [
{file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"},
@ -1423,26 +1424,29 @@ mistune = [
{file = "mistune-0.8.4.tar.gz", hash = "sha256:59a3429db53c50b5c6bcc8a07f8848cb00d7dc8bdb431a4ab41920d201d4756e"}, {file = "mistune-0.8.4.tar.gz", hash = "sha256:59a3429db53c50b5c6bcc8a07f8848cb00d7dc8bdb431a4ab41920d201d4756e"},
] ]
mypy = [ mypy = [
{file = "mypy-0.931-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3c5b42d0815e15518b1f0990cff7a705805961613e701db60387e6fb663fe78a"}, {file = "mypy-0.941-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:98f61aad0bb54f797b17da5b82f419e6ce214de0aa7e92211ebee9e40eb04276"},
{file = "mypy-0.931-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c89702cac5b302f0c5d33b172d2b55b5df2bede3344a2fbed99ff96bddb2cf00"}, {file = "mypy-0.941-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6a8e1f63357851444940351e98fb3252956a15f2cabe3d698316d7a2d1f1f896"},
{file = "mypy-0.931-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:300717a07ad09525401a508ef5d105e6b56646f7942eb92715a1c8d610149714"}, {file = "mypy-0.941-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b30d29251dff4c59b2e5a1fa1bab91ff3e117b4658cb90f76d97702b7a2ae699"},
{file = "mypy-0.931-cp310-cp310-win_amd64.whl", hash = "sha256:7b3f6f557ba4afc7f2ce6d3215d5db279bcf120b3cfd0add20a5d4f4abdae5bc"}, {file = "mypy-0.941-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8eaf55fdf99242a1c8c792247c455565447353914023878beadb79600aac4a2a"},
{file = "mypy-0.931-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:1bf752559797c897cdd2c65f7b60c2b6969ffe458417b8d947b8340cc9cec08d"}, {file = "mypy-0.941-cp310-cp310-win_amd64.whl", hash = "sha256:080097eee5393fd740f32c63f9343580aaa0fb1cda0128fd859dfcf081321c3d"},
{file = "mypy-0.931-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4365c60266b95a3f216a3047f1d8e3f895da6c7402e9e1ddfab96393122cc58d"}, {file = "mypy-0.941-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f79137d012ff3227866222049af534f25354c07a0d6b9a171dba9f1d6a1fdef4"},
{file = "mypy-0.931-cp36-cp36m-win_amd64.whl", hash = "sha256:1b65714dc296a7991000b6ee59a35b3f550e0073411ac9d3202f6516621ba66c"}, {file = "mypy-0.941-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8e5974583a77d630a5868eee18f85ac3093caf76e018c510aeb802b9973304ce"},
{file = "mypy-0.931-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e839191b8da5b4e5d805f940537efcaa13ea5dd98418f06dc585d2891d228cf0"}, {file = "mypy-0.941-cp36-cp36m-win_amd64.whl", hash = "sha256:0dd441fbacf48e19dc0c5c42fafa72b8e1a0ba0a39309c1af9c84b9397d9b15a"},
{file = "mypy-0.931-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:50c7346a46dc76a4ed88f3277d4959de8a2bd0a0fa47fa87a4cde36fe247ac05"}, {file = "mypy-0.941-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0d3bcbe146247997e03bf030122000998b076b3ac6925b0b6563f46d1ce39b50"},
{file = "mypy-0.931-cp37-cp37m-win_amd64.whl", hash = "sha256:d8f1ff62f7a879c9fe5917b3f9eb93a79b78aad47b533911b853a757223f72e7"}, {file = "mypy-0.941-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3bada0cf7b6965627954b3a128903a87cac79a79ccd83b6104912e723ef16c7b"},
{file = "mypy-0.931-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f9fe20d0872b26c4bba1c1be02c5340de1019530302cf2dcc85c7f9fc3252ae0"}, {file = "mypy-0.941-cp37-cp37m-win_amd64.whl", hash = "sha256:eea10982b798ff0ccc3b9e7e42628f932f552c5845066970e67cd6858655d52c"},
{file = "mypy-0.931-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1b06268df7eb53a8feea99cbfff77a6e2b205e70bf31743e786678ef87ee8069"}, {file = "mypy-0.941-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:108f3c7e14a038cf097d2444fa0155462362c6316e3ecb2d70f6dd99cd36084d"},
{file = "mypy-0.931-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8c11003aaeaf7cc2d0f1bc101c1cc9454ec4cc9cb825aef3cafff8a5fdf4c799"}, {file = "mypy-0.941-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d61b73c01fc1de799226963f2639af831307fe1556b04b7c25e2b6c267a3bc76"},
{file = "mypy-0.931-cp38-cp38-win_amd64.whl", hash = "sha256:d9d2b84b2007cea426e327d2483238f040c49405a6bf4074f605f0156c91a47a"}, {file = "mypy-0.941-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:42c216a33d2bdba08098acaf5bae65b0c8196afeb535ef4b870919a788a27259"},
{file = "mypy-0.931-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ff3bf387c14c805ab1388185dd22d6b210824e164d4bb324b195ff34e322d166"}, {file = "mypy-0.941-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fc5ecff5a3bbfbe20091b1cad82815507f5ae9c380a3a9bf40f740c70ce30a9b"},
{file = "mypy-0.931-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5b56154f8c09427bae082b32275a21f500b24d93c88d69a5e82f3978018a0266"}, {file = "mypy-0.941-cp38-cp38-win_amd64.whl", hash = "sha256:bf446223b2e0e4f0a4792938e8d885e8a896834aded5f51be5c3c69566495540"},
{file = "mypy-0.931-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8ca7f8c4b1584d63c9a0f827c37ba7a47226c19a23a753d52e5b5eddb201afcd"}, {file = "mypy-0.941-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:745071762f32f65e77de6df699366d707fad6c132a660d1342077cbf671ef589"},
{file = "mypy-0.931-cp39-cp39-win_amd64.whl", hash = "sha256:74f7eccbfd436abe9c352ad9fb65872cc0f1f0a868e9d9c44db0893440f0c697"}, {file = "mypy-0.941-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:465a6ce9ca6268cadfbc27a2a94ddf0412568a6b27640ced229270be4f5d394d"},
{file = "mypy-0.931-py3-none-any.whl", hash = "sha256:1171f2e0859cfff2d366da2c7092b06130f232c636a3f7301e3feb8b41f6377d"}, {file = "mypy-0.941-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d051ce0946521eba48e19b25f27f98e5ce4dbc91fff296de76240c46b4464df0"},
{file = "mypy-0.931.tar.gz", hash = "sha256:0038b21890867793581e4cb0d810829f5fd4441aa75796b53033af3aa30430ce"}, {file = "mypy-0.941-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:818cfc51c25a5dbfd0705f3ac1919fff6971eb0c02e6f1a1f6a017a42405a7c0"},
{file = "mypy-0.941-cp39-cp39-win_amd64.whl", hash = "sha256:b2ce2788df0c066c2ff4ba7190fa84f18937527c477247e926abeb9b1168b8cc"},
{file = "mypy-0.941-py3-none-any.whl", hash = "sha256:3cf77f138efb31727ee7197bc824c9d6d7039204ed96756cc0f9ca7d8e8fc2a4"},
{file = "mypy-0.941.tar.gz", hash = "sha256:cbcc691d8b507d54cb2b8521f0a2a3d4daa477f62fe77f0abba41e5febb377b7"},
] ]
mypy-extensions = [ mypy-extensions = [
{file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
@ -1469,8 +1473,8 @@ nodeenv = [
{file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"}, {file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"},
] ]
notebook = [ notebook = [
{file = "notebook-6.4.8-py3-none-any.whl", hash = "sha256:3e702fcc54b8ae597533c3864793b7a1e971dec9e112f67235828d8a798fd654"}, {file = "notebook-6.4.10-py3-none-any.whl", hash = "sha256:49cead814bff0945fcb2ee07579259418672ac175d3dc3d8102a4b0a656ed4df"},
{file = "notebook-6.4.8.tar.gz", hash = "sha256:1e985c9dc6f678bdfffb9dc657306b5469bfa62d73e03f74e8defbf76d284312"}, {file = "notebook-6.4.10.tar.gz", hash = "sha256:2408a76bc6289283a8eecfca67e298ec83c67db51a4c2e1b713dd180bb39e90e"},
] ]
packaging = [ packaging = [
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
@ -1794,8 +1798,8 @@ webencodings = [
{file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"},
] ]
widgetsnbextension = [ widgetsnbextension = [
{file = "widgetsnbextension-3.5.2-py2.py3-none-any.whl", hash = "sha256:763a9fdc836d141fa080005a886d63f66f73d56dba1fb5961afc239c77708569"}, {file = "widgetsnbextension-3.6.0-py2.py3-none-any.whl", hash = "sha256:4fd321cad39fdcf8a8e248a657202d42917ada8e8ed5dd3f60f073e0d54ceabd"},
{file = "widgetsnbextension-3.5.2.tar.gz", hash = "sha256:e0731a60ba540cd19bbbefe771a9076dcd2dde90713a8f87f27f53f2d1db7727"}, {file = "widgetsnbextension-3.6.0.tar.gz", hash = "sha256:e84a7a9fcb9baf3d57106e184a7389a8f8eb935bf741a5eb9d60aa18cc029a80"},
] ]
zipp = [ zipp = [
{file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"}, {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"},

View file

@ -40,7 +40,7 @@ jupyter = ["ipywidgets"]
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
pytest = "^7.0.0" pytest = "^7.0.0"
black = "^22.1" black = "^22.1"
mypy = "^0.931" mypy = "^0.941"
pytest-cov = "^3.0.0" pytest-cov = "^3.0.0"
attrs = "^21.4.0" attrs = "^21.4.0"
types-dataclasses = "^0.6.4" types-dataclasses = "^0.6.4"

View file

@ -334,7 +334,7 @@ class LegacyWindowsTerm:
15, # bright white 15, # bright white
] ]
def __init__(self, file: IO[str]) -> None: def __init__(self, file: "IO[str]") -> None:
handle = GetStdHandle(STDOUT) handle = GetStdHandle(STDOUT)
self._handle = handle self._handle = handle
default_text = GetConsoleScreenBufferInfo(handle).wAttributes default_text = GetConsoleScreenBufferInfo(handle).wAttributes

View file

@ -11,9 +11,7 @@ def legacy_windows_render(buffer: Iterable[Segment], term: LegacyWindowsTerm) ->
buffer (Iterable[Segment]): Iterable of Segments to convert to Win32 API calls. buffer (Iterable[Segment]): Iterable of Segments to convert to Win32 API calls.
term (LegacyWindowsTerm): Used to call the Windows Console API. term (LegacyWindowsTerm): Used to call the Windows Console API.
""" """
for segment in buffer: for text, style, control in buffer:
text, style, control = segment
if not control: if not control:
if style: if style:
term.write_styled(text, style) term.write_styled(text, style)

View file

@ -1,5 +1,6 @@
from contextlib import suppress
import re import re
import sys
from contextlib import suppress
from typing import Iterable, NamedTuple from typing import Iterable, NamedTuple
from .color import Color from .color import Color
@ -198,10 +199,10 @@ class AnsiDecoder:
return text return text
if __name__ == "__main__": # pragma: no cover if sys.platform != "win32" and __name__ == "__main__": # pragma: no cover
import pty
import io import io
import os import os
import pty
import sys import sys
decoder = AnsiDecoder() decoder = AnsiDecoder()

View file

@ -113,14 +113,12 @@ def chop_cells(text: str, max_size: int, position: int = 0) -> List[str]:
_get_character_cell_size = get_character_cell_size _get_character_cell_size = get_character_cell_size
characters = [ characters = [
(character, _get_character_cell_size(character)) for character in text (character, _get_character_cell_size(character)) for character in text
][::-1] ]
total_size = position total_size = position
lines: List[List[str]] = [[]] lines: List[List[str]] = [[]]
append = lines[-1].append append = lines[-1].append
pop = characters.pop for character, size in reversed(characters):
while characters:
character, size = pop()
if total_size + size > max_size: if total_size + size > max_size:
lines.append([character]) lines.append([character])
append = lines[-1].append append = lines[-1].append
@ -128,6 +126,7 @@ def chop_cells(text: str, max_size: int, position: int = 0) -> List[str]:
else: else:
total_size += size total_size += size
append(character) append(character)
return ["".join(line) for line in lines] return ["".join(line) for line in lines]

View file

@ -82,6 +82,17 @@ class NoChange:
NO_CHANGE = NoChange() NO_CHANGE = NoChange()
try:
_STDOUT_FILENO = sys.__stdout__.fileno()
except Exception:
_STDOUT_FILENO = 1
try:
_STDERR_FILENO = sys.__stderr__.fileno()
except Exception:
_STDERR_FILENO = 2
_STD_STREAMS = (_STDOUT_FILENO, _STDERR_FILENO)
CONSOLE_HTML_FORMAT = """\ CONSOLE_HTML_FORMAT = """\
<!DOCTYPE html> <!DOCTYPE html>
@ -1909,12 +1920,21 @@ class Console:
buffer_extend(line) buffer_extend(line)
def _check_buffer(self) -> None: def _check_buffer(self) -> None:
"""Check if the buffer may be rendered.""" """Check if the buffer may be rendered. Render it if it can (e.g. Console.quiet is False)
Rendering is supported on Windows, Unix and Jupyter environments. For
legacy Windows consoles, the win32 API is called directly.
This method will also record what it renders if recording is enabled via Console.record.
"""
if self.quiet: if self.quiet:
del self._buffer[:] del self._buffer[:]
return return
with self._lock: with self._lock:
if self._buffer_index == 0: if self._buffer_index == 0:
if self.record:
with self._record_buffer_lock:
self._record_buffer.extend(self._buffer[:])
if self.is_jupyter: # pragma: no cover if self.is_jupyter: # pragma: no cover
from .jupyter import display from .jupyter import display
@ -1922,23 +1942,24 @@ class Console:
del self._buffer[:] del self._buffer[:]
else: else:
if WINDOWS: if WINDOWS:
try: use_legacy_windows_render = False
file_no = self.file.fileno() if self.legacy_windows:
except (ValueError, io.UnsupportedOperation): try:
file_no = -1 use_legacy_windows_render = (
self.file.fileno() in _STD_STREAMS
)
except (ValueError, io.UnsupportedOperation):
pass
legacy_windows_stdout = self.legacy_windows and file_no == 1 if use_legacy_windows_render:
if legacy_windows_stdout:
from rich._win32_console import LegacyWindowsTerm from rich._win32_console import LegacyWindowsTerm
from rich._windows_renderer import legacy_windows_render from rich._windows_renderer import legacy_windows_render
with open(file_no, "w") as output_file: legacy_windows_render(
legacy_windows_render( self._buffer[:], LegacyWindowsTerm(self.file)
self._buffer[:], LegacyWindowsTerm(output_file) )
) else:
# Either a non-std stream on legacy Windows, or modern Windows.
output_capture_enabled = bool(self._buffer_index)
if not legacy_windows_stdout or output_capture_enabled:
text = self._render_buffer(self._buffer[:]) text = self._render_buffer(self._buffer[:])
# https://bugs.python.org/issue37871 # https://bugs.python.org/issue37871
write = self.file.write write = self.file.write
@ -1965,9 +1986,6 @@ class Console:
append = output.append append = output.append
color_system = self._color_system color_system = self._color_system
legacy_windows = self.legacy_windows legacy_windows = self.legacy_windows
if self.record:
with self._record_buffer_lock:
self._record_buffer.extend(buffer)
not_terminal = not self.is_terminal not_terminal = not self.is_terminal
if self.no_color and color_system: if self.no_color and color_system:
buffer = Segment.remove_color(buffer) buffer = Segment.remove_color(buffer)

View file

@ -90,13 +90,13 @@ class ReprHighlighter(RegexHighlighter):
r"(?P<ipv6>([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})", r"(?P<ipv6>([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})",
r"(?P<eui64>(?:[0-9A-Fa-f]{1,2}-){7}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{1,2}:){7}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{4}\.){3}[0-9A-Fa-f]{4})", r"(?P<eui64>(?:[0-9A-Fa-f]{1,2}-){7}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{1,2}:){7}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{4}\.){3}[0-9A-Fa-f]{4})",
r"(?P<eui48>(?:[0-9A-Fa-f]{1,2}-){5}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{1,2}:){5}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{4}\.){2}[0-9A-Fa-f]{4})", r"(?P<eui48>(?:[0-9A-Fa-f]{1,2}-){5}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{1,2}:){5}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{4}\.){2}[0-9A-Fa-f]{4})",
r"(?P<uuid>[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})",
r"(?P<call>[\w.]*?)\(", r"(?P<call>[\w.]*?)\(",
r"\b(?P<bool_true>True)\b|\b(?P<bool_false>False)\b|\b(?P<none>None)\b", r"\b(?P<bool_true>True)\b|\b(?P<bool_false>False)\b|\b(?P<none>None)\b",
r"(?P<ellipsis>\.\.\.)", r"(?P<ellipsis>\.\.\.)",
r"(?P<number>(?<!\w)\-?[0-9]+\.?[0-9]*(e[-+]?\d+?)?\b|0x[0-9a-fA-F]*)", r"(?P<number>(?<!\w)\-?[0-9]+\.?[0-9]*(e[-+]?\d+?)?\b|0x[0-9a-fA-F]*)",
r"(?P<path>\B(/[-\w._+]+)*\/)(?P<filename>[-\w._+]*)?", r"(?P<path>\B(/[-\w._+]+)*\/)(?P<filename>[-\w._+]*)?",
r"(?<![\\\w])(?P<str>b?'''.*?(?<!\\)'''|b?'.*?(?<!\\)'|b?\"\"\".*?(?<!\\)\"\"\"|b?\".*?(?<!\\)\")", r"(?<![\\\w])(?P<str>b?'''.*?(?<!\\)'''|b?'.*?(?<!\\)'|b?\"\"\".*?(?<!\\)\"\"\"|b?\".*?(?<!\\)\")",
r"(?P<uuid>[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})",
r"(?P<url>(file|https|http|ws|wss)://[-0-9a-zA-Z$_+!`(),.?/;:&=%#]*)", r"(?P<url>(file|https|http|ws|wss)://[-0-9a-zA-Z$_+!`(),.?/;:&=%#]*)",
), ),
] ]

View file

@ -11,6 +11,7 @@ from typing import (
Iterator, Iterator,
List, List,
Optional, Optional,
NamedTuple,
Sequence, Sequence,
Tuple, Tuple,
Type, Type,
@ -58,7 +59,7 @@ ControlCode = Union[
@rich_repr() @rich_repr()
class Segment: class Segment(NamedTuple):
"""A piece of text with associated style. Segments are produced by the Console render process and """A piece of text with associated style. Segments are produced by the Console render process and
are ultimately converted in to strings to be written to the terminal. are ultimately converted in to strings to be written to the terminal.
@ -71,32 +72,19 @@ class Segment:
cell_length (int): The cell length of this Segment. cell_length (int): The cell length of this Segment.
""" """
__slots__ = ["text", "style", "control", "cell_length", "_tuple"] text: str
style: Optional[Style] = None
control: Optional[Sequence[ControlCode]] = None
def __init__( @property
self, def cell_length(self) -> int:
text: str = "", """The number of terminal cells required to display self.text.
style: Optional[Style] = None,
control: Optional[Sequence[ControlCode]] = None,
):
self.text = text
self.style = style
self.control = control
self.cell_length = 0 if self.control else cell_len(self.text) Returns:
int: A number of cells.
self._tuple = text, style, control """
text, _style, control = self
def __iter__(self) -> Iterator[Any]: return 0 if control else cell_len(text)
return iter(self._tuple)
def __eq__(self, other: object) -> bool:
if isinstance(other, Segment):
return self._tuple == other._tuple
return self._tuple == other
def __hash__(self) -> int:
return hash(self._tuple)
def __rich_repr__(self) -> Result: def __rich_repr__(self) -> Result:
yield self.text yield self.text

View file

@ -83,6 +83,7 @@ highlight_tests = [
('"""hello"""', [Span(0, 11, "repr.str")]), ('"""hello"""', [Span(0, 11, "repr.str")]),
("\\'foo'", []), ("\\'foo'", []),
("it's no 'string'", [Span(8, 16, "repr.str")]), ("it's no 'string'", [Span(8, 16, "repr.str")]),
("78351748-9b32-4e08-ad3e-7e9ff124d541", [Span(0, 36, "repr.uuid")]),
] ]