From 4890c2edbc25ee678f8d8bd807e67cd4e9ce0a21 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Fri, 6 Nov 2020 18:32:07 +0000 Subject: [PATCH 01/14] Convert default output style over to Rich --- poetry.lock | 246 ++++++++++++++++++++++++++++--------------- pyproject.toml | 3 +- requirements.txt | 7 -- ward/diff.py | 4 +- ward/terminal.py | 265 +++++++++++++++++++++++++---------------------- ward/testing.py | 23 +++- 6 files changed, 328 insertions(+), 220 deletions(-) delete mode 100644 requirements.txt diff --git a/poetry.lock b/poetry.lock index e88b1df9..435e8aae 100644 --- a/poetry.lock +++ b/poetry.lock @@ -12,13 +12,13 @@ description = "Classes Without Boilerplate" name = "attrs" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "19.3.0" +version = "20.3.0" [package.extras] -azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"] -dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"] -docs = ["sphinx", "zope.interface"] -tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] +docs = ["furo", "sphinx", "zope.interface"] +tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] [[package]] category = "dev" @@ -64,8 +64,19 @@ category = "main" description = "Cross-platform colored terminal text." name = "colorama" optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.4.4" + +[[package]] +category = "main" +description = "Python parser for the CommonMark Markdown spec" +name = "commonmark" +optional = false python-versions = "*" -version = "0.3.9" +version = "0.9.1" + +[package.extras] +test = ["flake8 (3.7.8)", "hypothesis (3.55.3)"] [[package]] category = "dev" @@ -73,7 +84,7 @@ description = "Code coverage measurement for Python" name = "coverage" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "5.1" +version = "5.3" [package.extras] toml = ["toml"] @@ -92,7 +103,7 @@ develop = ["coverage", "pytest (>=3.2)", "pytest-html (>=1.19.0)", "tox (>=2.9)" [[package]] category = "main" description = "A backport of the dataclasses module for Python 3.6" -marker = "python_version == \"3.6\"" +marker = "python_version >= \"3.6\" and python_version < \"3.7\" or python_version == \"3.6\"" name = "dataclasses" optional = false python-versions = ">=3.6, <3.7" @@ -104,7 +115,7 @@ description = "the modular source code checker: pep8 pyflakes and co" name = "flake8" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" -version = "3.8.2" +version = "3.8.4" [package.dependencies] mccabe = ">=0.6.0,<0.7.0" @@ -122,14 +133,14 @@ marker = "python_version < \"3.8\"" name = "importlib-metadata" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -version = "1.6.0" +version = "2.0.0" [package.dependencies] zipp = ">=0.5" [package.extras] docs = ["sphinx", "rst.linker"] -testing = ["packaging", "importlib-resources"] +testing = ["packaging", "pep517", "importlib-resources (>=1.3)"] [[package]] category = "dev" @@ -177,7 +188,7 @@ description = "Pygments is a syntax highlighting package written in Python." name = "pygments" optional = false python-versions = ">=3.5" -version = "2.6.1" +version = "2.7.2" [[package]] category = "dev" @@ -185,7 +196,28 @@ description = "Alternative regular expression module, to replace re." name = "regex" optional = false python-versions = "*" -version = "2020.5.14" +version = "2020.10.28" + +[[package]] +category = "main" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +name = "rich" +optional = false +python-versions = ">=3.6,<4.0" +version = "9.1.0" + +[package.dependencies] +colorama = ">=0.4.0,<0.5.0" +commonmark = ">=0.9.0,<0.10.0" +pygments = ">=2.6.0,<3.0.0" +typing-extensions = ">=3.7.4,<4.0.0" + +[package.dependencies.dataclasses] +python = ">=3.6,<3.7" +version = ">=0.7,<0.8" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"] [[package]] category = "main" @@ -200,8 +232,8 @@ category = "main" description = "Python Library for Tom's Obvious, Minimal Language" name = "toml" optional = false -python-versions = "*" -version = "0.10.1" +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +version = "0.10.2" [[package]] category = "dev" @@ -211,6 +243,14 @@ optional = false python-versions = "*" version = "1.4.1" +[[package]] +category = "main" +description = "Backported and Experimental Type Hints for Python 3.5+" +name = "typing-extensions" +optional = false +python-versions = "*" +version = "3.7.4.3" + [[package]] category = "dev" description = "Backport of pathlib-compatible object wrapper for zip files" @@ -218,14 +258,14 @@ marker = "python_version < \"3.8\"" name = "zipp" optional = false python-versions = ">=3.6" -version = "3.1.0" +version = "3.4.0" [package.extras] docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -testing = ["jaraco.itertools", "func-timeout"] +testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [metadata] -content-hash = "aa880fc4f3cf48b63d0b616401024d22fe2646377686a4e7333a25954130f231" +content-hash = "f708d5230376832af36bdc620a2adecfe4d7aa4d2bfc505a892e48b83144649a" python-versions = "^3.6" [metadata.files] @@ -234,8 +274,8 @@ appdirs = [ {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, ] attrs = [ - {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, - {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, + {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"}, + {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, ] black = [ {file = "black-19.10b0-py36-none-any.whl", hash = "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"}, @@ -249,41 +289,48 @@ click-default-group = [ {file = "click-default-group-1.2.2.tar.gz", hash = "sha256:d9560e8e8dfa44b3562fbc9425042a0fd6d21956fcc2db0077f63f34253ab904"}, ] colorama = [ - {file = "colorama-0.3.9-py2.py3-none-any.whl", hash = "sha256:463f8483208e921368c9f306094eb6f725c6ca42b0f97e313cb5d5512459feda"}, - {file = "colorama-0.3.9.tar.gz", hash = "sha256:48eb22f4f8461b1df5734a074b57042430fb06e1d61bd1e11b078c0fe6d7a1f1"}, + {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, +] +commonmark = [ + {file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"}, + {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, ] coverage = [ - {file = "coverage-5.1-cp27-cp27m-macosx_10_12_x86_64.whl", hash = "sha256:0cb4be7e784dcdc050fc58ef05b71aa8e89b7e6636b99967fadbdba694cf2b65"}, - {file = "coverage-5.1-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:c317eaf5ff46a34305b202e73404f55f7389ef834b8dbf4da09b9b9b37f76dd2"}, - {file = "coverage-5.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b83835506dfc185a319031cf853fa4bb1b3974b1f913f5bb1a0f3d98bdcded04"}, - {file = "coverage-5.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5f2294dbf7875b991c381e3d5af2bcc3494d836affa52b809c91697449d0eda6"}, - {file = "coverage-5.1-cp27-cp27m-win32.whl", hash = "sha256:de807ae933cfb7f0c7d9d981a053772452217df2bf38e7e6267c9cbf9545a796"}, - {file = "coverage-5.1-cp27-cp27m-win_amd64.whl", hash = "sha256:bf9cb9a9fd8891e7efd2d44deb24b86d647394b9705b744ff6f8261e6f29a730"}, - {file = "coverage-5.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:acf3763ed01af8410fc36afea23707d4ea58ba7e86a8ee915dfb9ceff9ef69d0"}, - {file = "coverage-5.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:dec5202bfe6f672d4511086e125db035a52b00f1648d6407cc8e526912c0353a"}, - {file = "coverage-5.1-cp35-cp35m-macosx_10_12_x86_64.whl", hash = "sha256:7a5bdad4edec57b5fb8dae7d3ee58622d626fd3a0be0dfceda162a7035885ecf"}, - {file = "coverage-5.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1601e480b9b99697a570cea7ef749e88123c04b92d84cedaa01e117436b4a0a9"}, - {file = "coverage-5.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:dbe8c6ae7534b5b024296464f387d57c13caa942f6d8e6e0346f27e509f0f768"}, - {file = "coverage-5.1-cp35-cp35m-win32.whl", hash = "sha256:a027ef0492ede1e03a8054e3c37b8def89a1e3c471482e9f046906ba4f2aafd2"}, - {file = "coverage-5.1-cp35-cp35m-win_amd64.whl", hash = "sha256:0e61d9803d5851849c24f78227939c701ced6704f337cad0a91e0972c51c1ee7"}, - {file = "coverage-5.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:2d27a3f742c98e5c6b461ee6ef7287400a1956c11421eb574d843d9ec1f772f0"}, - {file = "coverage-5.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:66460ab1599d3cf894bb6baee8c684788819b71a5dc1e8fa2ecc152e5d752019"}, - {file = "coverage-5.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5c542d1e62eece33c306d66fe0a5c4f7f7b3c08fecc46ead86d7916684b36d6c"}, - {file = "coverage-5.1-cp36-cp36m-win32.whl", hash = "sha256:2742c7515b9eb368718cd091bad1a1b44135cc72468c731302b3d641895b83d1"}, - {file = "coverage-5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:dead2ddede4c7ba6cb3a721870f5141c97dc7d85a079edb4bd8d88c3ad5b20c7"}, - {file = "coverage-5.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:01333e1bd22c59713ba8a79f088b3955946e293114479bbfc2e37d522be03355"}, - {file = "coverage-5.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:e1ea316102ea1e1770724db01998d1603ed921c54a86a2efcb03428d5417e489"}, - {file = "coverage-5.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:adeb4c5b608574a3d647011af36f7586811a2c1197c861aedb548dd2453b41cd"}, - {file = "coverage-5.1-cp37-cp37m-win32.whl", hash = "sha256:782caea581a6e9ff75eccda79287daefd1d2631cc09d642b6ee2d6da21fc0a4e"}, - {file = "coverage-5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:00f1d23f4336efc3b311ed0d807feb45098fc86dee1ca13b3d6768cdab187c8a"}, - {file = "coverage-5.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:402e1744733df483b93abbf209283898e9f0d67470707e3c7516d84f48524f55"}, - {file = "coverage-5.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:a3f3654d5734a3ece152636aad89f58afc9213c6520062db3978239db122f03c"}, - {file = "coverage-5.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6402bd2fdedabbdb63a316308142597534ea8e1895f4e7d8bf7476c5e8751fef"}, - {file = "coverage-5.1-cp38-cp38-win32.whl", hash = "sha256:8fa0cbc7ecad630e5b0f4f35b0f6ad419246b02bc750de7ac66db92667996d24"}, - {file = "coverage-5.1-cp38-cp38-win_amd64.whl", hash = "sha256:79a3cfd6346ce6c13145731d39db47b7a7b859c0272f02cdb89a3bdcbae233a0"}, - {file = "coverage-5.1-cp39-cp39-win32.whl", hash = "sha256:a82b92b04a23d3c8a581fc049228bafde988abacba397d57ce95fe95e0338ab4"}, - {file = "coverage-5.1-cp39-cp39-win_amd64.whl", hash = "sha256:bb28a7245de68bf29f6fb199545d072d1036a1917dca17a1e75bbb919e14ee8e"}, - {file = "coverage-5.1.tar.gz", hash = "sha256:f90bfc4ad18450c80b024036eaf91e4a246ae287701aaa88eaebebf150868052"}, + {file = "coverage-5.3-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:bd3166bb3b111e76a4f8e2980fa1addf2920a4ca9b2b8ca36a3bc3dedc618270"}, + {file = "coverage-5.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9342dd70a1e151684727c9c91ea003b2fb33523bf19385d4554f7897ca0141d4"}, + {file = "coverage-5.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:63808c30b41f3bbf65e29f7280bf793c79f54fb807057de7e5238ffc7cc4d7b9"}, + {file = "coverage-5.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:4d6a42744139a7fa5b46a264874a781e8694bb32f1d76d8137b68138686f1729"}, + {file = "coverage-5.3-cp27-cp27m-win32.whl", hash = "sha256:86e9f8cd4b0cdd57b4ae71a9c186717daa4c5a99f3238a8723f416256e0b064d"}, + {file = "coverage-5.3-cp27-cp27m-win_amd64.whl", hash = "sha256:7858847f2d84bf6e64c7f66498e851c54de8ea06a6f96a32a1d192d846734418"}, + {file = "coverage-5.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:530cc8aaf11cc2ac7430f3614b04645662ef20c348dce4167c22d99bec3480e9"}, + {file = "coverage-5.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:381ead10b9b9af5f64646cd27107fb27b614ee7040bb1226f9c07ba96625cbb5"}, + {file = "coverage-5.3-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:71b69bd716698fa62cd97137d6f2fdf49f534decb23a2c6fc80813e8b7be6822"}, + {file = "coverage-5.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1d44bb3a652fed01f1f2c10d5477956116e9b391320c94d36c6bf13b088a1097"}, + {file = "coverage-5.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:1c6703094c81fa55b816f5ae542c6ffc625fec769f22b053adb42ad712d086c9"}, + {file = "coverage-5.3-cp35-cp35m-win32.whl", hash = "sha256:cedb2f9e1f990918ea061f28a0f0077a07702e3819602d3507e2ff98c8d20636"}, + {file = "coverage-5.3-cp35-cp35m-win_amd64.whl", hash = "sha256:7f43286f13d91a34fadf61ae252a51a130223c52bfefb50310d5b2deb062cf0f"}, + {file = "coverage-5.3-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:c851b35fc078389bc16b915a0a7c1d5923e12e2c5aeec58c52f4aa8085ac8237"}, + {file = "coverage-5.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:aac1ba0a253e17889550ddb1b60a2063f7474155465577caa2a3b131224cfd54"}, + {file = "coverage-5.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2b31f46bf7b31e6aa690d4c7a3d51bb262438c6dcb0d528adde446531d0d3bb7"}, + {file = "coverage-5.3-cp36-cp36m-win32.whl", hash = "sha256:c5f17ad25d2c1286436761b462e22b5020d83316f8e8fcb5deb2b3151f8f1d3a"}, + {file = "coverage-5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:aef72eae10b5e3116bac6957de1df4d75909fc76d1499a53fb6387434b6bcd8d"}, + {file = "coverage-5.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:e8caf961e1b1a945db76f1b5fa9c91498d15f545ac0ababbe575cfab185d3bd8"}, + {file = "coverage-5.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:29a6272fec10623fcbe158fdf9abc7a5fa032048ac1d8631f14b50fbfc10d17f"}, + {file = "coverage-5.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2d43af2be93ffbad25dd959899b5b809618a496926146ce98ee0b23683f8c51c"}, + {file = "coverage-5.3-cp37-cp37m-win32.whl", hash = "sha256:c3888a051226e676e383de03bf49eb633cd39fc829516e5334e69b8d81aae751"}, + {file = "coverage-5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9669179786254a2e7e57f0ecf224e978471491d660aaca833f845b72a2df3709"}, + {file = "coverage-5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0203acd33d2298e19b57451ebb0bed0ab0c602e5cf5a818591b4918b1f97d516"}, + {file = "coverage-5.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:582ddfbe712025448206a5bc45855d16c2e491c2dd102ee9a2841418ac1c629f"}, + {file = "coverage-5.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:0f313707cdecd5cd3e217fc68c78a960b616604b559e9ea60cc16795c4304259"}, + {file = "coverage-5.3-cp38-cp38-win32.whl", hash = "sha256:78e93cc3571fd928a39c0b26767c986188a4118edc67bc0695bc7a284da22e82"}, + {file = "coverage-5.3-cp38-cp38-win_amd64.whl", hash = "sha256:8f264ba2701b8c9f815b272ad568d555ef98dfe1576802ab3149c3629a9f2221"}, + {file = "coverage-5.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:50691e744714856f03a86df3e2bff847c2acede4c191f9a1da38f088df342978"}, + {file = "coverage-5.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9361de40701666b034c59ad9e317bae95c973b9ff92513dd0eced11c6adf2e21"}, + {file = "coverage-5.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:c1b78fb9700fc961f53386ad2fd86d87091e06ede5d118b8a50dea285a071c24"}, + {file = "coverage-5.3-cp39-cp39-win32.whl", hash = "sha256:cb7df71de0af56000115eafd000b867d1261f786b5eebd88a0ca6360cccfaca7"}, + {file = "coverage-5.3-cp39-cp39-win_amd64.whl", hash = "sha256:47a11bdbd8ada9b7ee628596f9d97fbd3851bd9999d398e9436bd67376dbece7"}, + {file = "coverage-5.3.tar.gz", hash = "sha256:280baa8ec489c4f542f8940f9c4c2181f0306a8ee1a54eceba071a449fb870a0"}, ] cucumber-tag-expressions = [ {file = "cucumber-tag-expressions-2.0.4.tar.gz", hash = "sha256:72197b9330c023ce2643847fd6659c5c000f7f286f5b42cbcfd19adb3be92d30"}, @@ -293,12 +340,12 @@ dataclasses = [ {file = "dataclasses-0.7.tar.gz", hash = "sha256:494a6dcae3b8bcf80848eea2ef64c0cc5cd307ffc263e17cdf42f3e5420808e6"}, ] flake8 = [ - {file = "flake8-3.8.2-py2.py3-none-any.whl", hash = "sha256:ccaa799ef9893cebe69fdfefed76865aeaefbb94cb8545617b2298786a4de9a5"}, - {file = "flake8-3.8.2.tar.gz", hash = "sha256:c69ac1668e434d37a2d2880b3ca9aafd54b3a10a3ac1ab101d22f29e29cf8634"}, + {file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"}, + {file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"}, ] importlib-metadata = [ - {file = "importlib_metadata-1.6.0-py2.py3-none-any.whl", hash = "sha256:2a688cbaa90e0cc587f1df48bdc97a6eadccdcd9c35fb3f976a09e3b5016d90f"}, - {file = "importlib_metadata-1.6.0.tar.gz", hash = "sha256:34513a8a0c4962bc66d35b359558fd8a5e10cd472d37aec5f66858addef32c1e"}, + {file = "importlib_metadata-2.0.0-py2.py3-none-any.whl", hash = "sha256:cefa1a2f919b866c5beb7c9f7b0ebb4061f30a8a9bf16d609b000e2dfaceb9c3"}, + {file = "importlib_metadata-2.0.0.tar.gz", hash = "sha256:77a540690e24b0305878c37ffd421785a6f7e53c8b5720d211b211de8d0e95da"}, ] mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, @@ -321,38 +368,64 @@ pyflakes = [ {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, ] pygments = [ - {file = "Pygments-2.6.1-py3-none-any.whl", hash = "sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324"}, - {file = "Pygments-2.6.1.tar.gz", hash = "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44"}, + {file = "Pygments-2.7.2-py3-none-any.whl", hash = "sha256:88a0bbcd659fcb9573703957c6b9cff9fab7295e6e76db54c9d00ae42df32773"}, + {file = "Pygments-2.7.2.tar.gz", hash = "sha256:381985fcc551eb9d37c52088a32914e00517e57f4a21609f48141ba08e193fa0"}, ] regex = [ - {file = "regex-2020.5.14-cp27-cp27m-win32.whl", hash = "sha256:e565569fc28e3ba3e475ec344d87ed3cd8ba2d575335359749298a0899fe122e"}, - {file = "regex-2020.5.14-cp27-cp27m-win_amd64.whl", hash = "sha256:d466967ac8e45244b9dfe302bbe5e3337f8dc4dec8d7d10f5e950d83b140d33a"}, - {file = "regex-2020.5.14-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:27ff7325b297fb6e5ebb70d10437592433601c423f5acf86e5bc1ee2919b9561"}, - {file = "regex-2020.5.14-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ea55b80eb0d1c3f1d8d784264a6764f931e172480a2f1868f2536444c5f01e01"}, - {file = "regex-2020.5.14-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:c9bce6e006fbe771a02bda468ec40ffccbf954803b470a0345ad39c603402577"}, - {file = "regex-2020.5.14-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:d881c2e657c51d89f02ae4c21d9adbef76b8325fe4d5cf0e9ad62f850f3a98fd"}, - {file = "regex-2020.5.14-cp36-cp36m-win32.whl", hash = "sha256:99568f00f7bf820c620f01721485cad230f3fb28f57d8fbf4a7967ec2e446994"}, - {file = "regex-2020.5.14-cp36-cp36m-win_amd64.whl", hash = "sha256:70c14743320a68c5dac7fc5a0f685be63bc2024b062fe2aaccc4acc3d01b14a1"}, - {file = "regex-2020.5.14-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:a7c37f048ec3920783abab99f8f4036561a174f1314302ccfa4e9ad31cb00eb4"}, - {file = "regex-2020.5.14-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:89d76ce33d3266173f5be80bd4efcbd5196cafc34100fdab814f9b228dee0fa4"}, - {file = "regex-2020.5.14-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:51f17abbe973c7673a61863516bdc9c0ef467407a940f39501e786a07406699c"}, - {file = "regex-2020.5.14-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:ce5cc53aa9fbbf6712e92c7cf268274eaff30f6bd12a0754e8133d85a8fb0f5f"}, - {file = "regex-2020.5.14-cp37-cp37m-win32.whl", hash = "sha256:8044d1c085d49673aadb3d7dc20ef5cb5b030c7a4fa253a593dda2eab3059929"}, - {file = "regex-2020.5.14-cp37-cp37m-win_amd64.whl", hash = "sha256:c2062c7d470751b648f1cacc3f54460aebfc261285f14bc6da49c6943bd48bdd"}, - {file = "regex-2020.5.14-cp38-cp38-manylinux1_i686.whl", hash = "sha256:329ba35d711e3428db6b45a53b1b13a0a8ba07cbbcf10bbed291a7da45f106c3"}, - {file = "regex-2020.5.14-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:579ea215c81d18da550b62ff97ee187b99f1b135fd894a13451e00986a080cad"}, - {file = "regex-2020.5.14-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:3a9394197664e35566242686d84dfd264c07b20f93514e2e09d3c2b3ffdf78fe"}, - {file = "regex-2020.5.14-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ce367d21f33e23a84fb83a641b3834dd7dd8e9318ad8ff677fbfae5915a239f7"}, - {file = "regex-2020.5.14-cp38-cp38-win32.whl", hash = "sha256:1386e75c9d1574f6aa2e4eb5355374c8e55f9aac97e224a8a5a6abded0f9c927"}, - {file = "regex-2020.5.14-cp38-cp38-win_amd64.whl", hash = "sha256:7e61be8a2900897803c293247ef87366d5df86bf701083b6c43119c7c6c99108"}, - {file = "regex-2020.5.14.tar.gz", hash = "sha256:ce450ffbfec93821ab1fea94779a8440e10cf63819be6e176eb1973a6017aff5"}, + {file = "regex-2020.10.28-cp27-cp27m-win32.whl", hash = "sha256:4b5a9bcb56cc146c3932c648603b24514447eafa6ce9295234767bf92f69b504"}, + {file = "regex-2020.10.28-cp27-cp27m-win_amd64.whl", hash = "sha256:c13d311a4c4a8d671f5860317eb5f09591fbe8259676b86a85769423b544451e"}, + {file = "regex-2020.10.28-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c454ad88e56e80e44f824ef8366bb7e4c3def12999151fd5c0ea76a18fe9aa3e"}, + {file = "regex-2020.10.28-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:c8a2b7ccff330ae4c460aff36626f911f918555660cc28163417cb84ffb25789"}, + {file = "regex-2020.10.28-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4afa350f162551cf402bfa3cd8302165c8e03e689c897d185f16a167328cc6dd"}, + {file = "regex-2020.10.28-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:b88fa3b8a3469f22b4f13d045d9bd3eda797aa4e406fde0a2644bc92bbdd4bdd"}, + {file = "regex-2020.10.28-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:f43109822df2d3faac7aad79613f5f02e4eab0fc8ad7932d2e70e2a83bd49c26"}, + {file = "regex-2020.10.28-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:de7fd57765398d141949946c84f3590a68cf5887dac3fc52388df0639b01eda4"}, + {file = "regex-2020.10.28-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:9b6305295b6591e45f069d3553c54d50cc47629eb5c218aac99e0f7fafbf90a1"}, + {file = "regex-2020.10.28-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:bd904c0dec29bbd0769887a816657491721d5f545c29e30fd9d7a1a275dc80ab"}, + {file = "regex-2020.10.28-cp36-cp36m-win32.whl", hash = "sha256:8092a5a06ad9a7a247f2a76ace121183dc4e1a84c259cf9c2ce3bbb69fac3582"}, + {file = "regex-2020.10.28-cp36-cp36m-win_amd64.whl", hash = "sha256:49461446b783945597c4076aea3f49aee4b4ce922bd241e4fcf62a3e7c61794c"}, + {file = "regex-2020.10.28-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:297116e79074ec2a2f885d22db00ce6e88b15f75162c5e8b38f66ea734e73c64"}, + {file = "regex-2020.10.28-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:8ca9dca965bd86ea3631b975d63b0693566d3cc347e55786d5514988b6f5b84c"}, + {file = "regex-2020.10.28-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ea37320877d56a7f0a1e6a625d892cf963aa7f570013499f5b8d5ab8402b5625"}, + {file = "regex-2020.10.28-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:3a5f08039eee9ea195a89e180c5762bfb55258bfb9abb61a20d3abee3b37fd12"}, + {file = "regex-2020.10.28-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:cb905f3d2e290a8b8f1579d3984f2cfa7c3a29cc7cba608540ceeed18513f520"}, + {file = "regex-2020.10.28-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:96f99219dddb33e235a37283306834700b63170d7bb2a1ee17e41c6d589c8eb9"}, + {file = "regex-2020.10.28-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:227a8d2e5282c2b8346e7f68aa759e0331a0b4a890b55a5cfbb28bd0261b84c0"}, + {file = "regex-2020.10.28-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:2564def9ce0710d510b1fc7e5178ce2d20f75571f788b5197b3c8134c366f50c"}, + {file = "regex-2020.10.28-cp37-cp37m-win32.whl", hash = "sha256:a62162be05edf64f819925ea88d09d18b09bebf20971b363ce0c24e8b4aa14c0"}, + {file = "regex-2020.10.28-cp37-cp37m-win_amd64.whl", hash = "sha256:03855ee22980c3e4863dc84c42d6d2901133362db5daf4c36b710dd895d78f0a"}, + {file = "regex-2020.10.28-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf4f896c42c63d1f22039ad57de2644c72587756c0cfb3cc3b7530cfe228277f"}, + {file = "regex-2020.10.28-cp38-cp38-manylinux1_i686.whl", hash = "sha256:625116aca6c4b57c56ea3d70369cacc4d62fead4930f8329d242e4fe7a58ce4b"}, + {file = "regex-2020.10.28-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2dc522e25e57e88b4980d2bdd334825dbf6fa55f28a922fc3bfa60cc09e5ef53"}, + {file = "regex-2020.10.28-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:119e0355dbdd4cf593b17f2fc5dbd4aec2b8899d0057e4957ba92f941f704bf5"}, + {file = "regex-2020.10.28-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:cfcf28ed4ce9ced47b9b9670a4f0d3d3c0e4d4779ad4dadb1ad468b097f808aa"}, + {file = "regex-2020.10.28-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:b45bab9f224de276b7bc916f6306b86283f6aa8afe7ed4133423efb42015a898"}, + {file = "regex-2020.10.28-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:52e83a5f28acd621ba8e71c2b816f6541af7144b69cc5859d17da76c436a5427"}, + {file = "regex-2020.10.28-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:aacc8623ffe7999a97935eeabbd24b1ae701d08ea8f874a6ff050e93c3e658cf"}, + {file = "regex-2020.10.28-cp38-cp38-win32.whl", hash = "sha256:06b52815d4ad38d6524666e0d50fe9173533c9cc145a5779b89733284e6f688f"}, + {file = "regex-2020.10.28-cp38-cp38-win_amd64.whl", hash = "sha256:c3466a84fce42c2016113101018a9981804097bacbab029c2d5b4fcb224b89de"}, + {file = "regex-2020.10.28-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:127a9e0c0d91af572fbb9e56d00a504dbd4c65e574ddda3d45b55722462210de"}, + {file = "regex-2020.10.28-cp39-cp39-manylinux1_i686.whl", hash = "sha256:c2c6c56ee97485a127555c9595c069201b5161de9d05495fbe2132b5ac104786"}, + {file = "regex-2020.10.28-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:1ec66700a10e3c75f1f92cbde36cca0d3aaee4c73dfa26699495a3a30b09093c"}, + {file = "regex-2020.10.28-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:11116d424734fe356d8777f89d625f0df783251ada95d6261b4c36ad27a394bb"}, + {file = "regex-2020.10.28-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f1fce1e4929157b2afeb4bb7069204d4370bab9f4fc03ca1fbec8bd601f8c87d"}, + {file = "regex-2020.10.28-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:3dfca201fa6b326239e1bccb00b915e058707028809b8ecc0cf6819ad233a740"}, + {file = "regex-2020.10.28-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:b8a686a6c98872007aa41fdbb2e86dc03b287d951ff4a7f1da77fb7f14113e4d"}, + {file = "regex-2020.10.28-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:c32c91a0f1ac779cbd73e62430de3d3502bbc45ffe5bb6c376015acfa848144b"}, + {file = "regex-2020.10.28-cp39-cp39-win32.whl", hash = "sha256:832339223b9ce56b7b15168e691ae654d345ac1635eeb367ade9ecfe0e66bee0"}, + {file = "regex-2020.10.28-cp39-cp39-win_amd64.whl", hash = "sha256:654c1635f2313d0843028487db2191530bca45af61ca85d0b16555c399625b0e"}, + {file = "regex-2020.10.28.tar.gz", hash = "sha256:dd3e6547ecf842a29cf25123fbf8d2461c53c8d37aa20d87ecee130c89b7079b"}, +] +rich = [ + {file = "rich-9.1.0-py3-none-any.whl", hash = "sha256:5dd934a0f8953b59d9a5d8d58864012174f0b5ad2de687fd04f4df195f7f7066"}, + {file = "rich-9.1.0.tar.gz", hash = "sha256:05f1cf4dc191c483867b098d8572546de266440d61911d8270069023e325d14a"}, ] termcolor = [ {file = "termcolor-1.1.0.tar.gz", hash = "sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b"}, ] toml = [ - {file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"}, - {file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"}, + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] typed-ast = [ {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"}, @@ -377,7 +450,12 @@ typed-ast = [ {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"}, {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, ] +typing-extensions = [ + {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, + {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, + {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, +] zipp = [ - {file = "zipp-3.1.0-py3-none-any.whl", hash = "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b"}, - {file = "zipp-3.1.0.tar.gz", hash = "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96"}, + {file = "zipp-3.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"}, + {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"}, ] diff --git a/pyproject.toml b/pyproject.toml index df546aec..c3da5659 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,9 +37,10 @@ classifiers = [ [tool.poetry.dependencies] python = "^3.6" dataclasses = { version = "^0.7", python = "3.6" } -colorama = "^0.3.3" +colorama = "^0.4.0" click = "^7.0" termcolor = "^1.1.0" +rich = "^9.1.0" toml = "^0.10.1" pygments = "^2.4.2" pprintpp = "^0.4.0" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 1212841a..00000000 --- a/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -colorama>=0.3.3 -termcolor>=1.1.0 -dataclasses>=0.1; python_version < '3.7' -click>=7.0 -toml>=0.9.4 -pprintpp==0.4.0 -cucumber-tag-expressions>=2.0.0 \ No newline at end of file diff --git a/ward/diff.py b/ward/diff.py index 7ee97664..ef4bf7bc 100644 --- a/ward/diff.py +++ b/ward/diff.py @@ -1,5 +1,5 @@ import difflib -from typing import Generator +from typing import Iterator import pprintpp from colorama import Style, Fore @@ -31,7 +31,7 @@ def bright_green(s: str) -> str: return f"{Fore.LIGHTGREEN_EX}{s}{Style.RESET_ALL}" -def raw_unified_diff(lhs_repr: str, rhs_repr: str) -> Generator[str, None, None]: +def raw_unified_diff(lhs_repr: str, rhs_repr: str) -> Iterator[str]: differ = difflib.Differ() lines_lhs = lhs_repr.splitlines() lines_rhs = rhs_repr.splitlines() diff --git a/ward/terminal.py b/ward/terminal.py index ba36de6f..f5bdad1c 100644 --- a/ward/terminal.py +++ b/ward/terminal.py @@ -1,9 +1,9 @@ import inspect +import itertools import os import platform import sys import traceback -import itertools from dataclasses import dataclass from enum import Enum from pathlib import Path @@ -19,10 +19,16 @@ Collection, ) -from colorama import Fore, Style from pygments import highlight from pygments.formatters.terminal import TerminalFormatter from pygments.lexers.python import PythonLexer +from rich.console import Console +from rich.highlighter import NullHighlighter +from rich.padding import Padding +from rich.rule import Rule +from rich.table import Table +from rich.text import Text +from rich.theme import Theme from termcolor import colored, cprint from ward._ward_version import __version__ @@ -48,9 +54,21 @@ def make_indent(depth=1): DOUBLE_INDENT = make_indent(depth=2) +theme = Theme({ + "heading": "bold", + "primary": "black on blue", + "pass": "black on green", + "warning": "black on yellow", + "fail": "black on red", + "xfail": "black on magenta", + "muted": "dim", + "info": "yellow italic", +}) +console = Console(theme=theme, highlighter=NullHighlighter()) + def print_no_break(e: Any): - print(e, end="") + console.print(e, end="") def multiline_description(s: str, indent: int, width: int) -> str: @@ -68,25 +86,32 @@ def format_test_id(test_result: TestResult) -> (str, str): """ Format module name, line number, and test case number """ - test_id = lightblack( - f"{format_test_location(test_result.test)}{format_test_case_number(test_result)}:" + f"{format_test_location(test_result.test)}{format_test_case_number(test_result.test)}:" ) return test_id def format_test_location(test: Test) -> str: + """ + Returns the location of a test as a string of the form '{test.module_name}:{test.line_number}' + """ return f"{test.module_name}:{test.line_number}" -def format_test_case_number(test_result: TestResult) -> str: - # If we're executing a parameterised test - param_meta = test_result.test.param_meta +def format_test_case_number(test: Test) -> str: + """ + Returns a string of the format '[{current_test_number}/{num_parameterised_instances}]'. + + For example, for the 3rd run of a test that is parameterised with 5 parameter sets the + return value is '[3/5]'. + """ + param_meta = test.param_meta if param_meta.group_size > 1: pad = len(str(param_meta.group_size)) iter_indicator = ( - f" [{param_meta.instance_index + 1:>{pad}}/{param_meta.group_size}]" + f"[{param_meta.instance_index + 1:>{pad}}/{param_meta.group_size}]" ) else: iter_indicator = "" @@ -95,46 +120,54 @@ def format_test_case_number(test_result: TestResult) -> str: def output_test_result_line(test_result: TestResult): - colour = outcome_to_colour(test_result.outcome) - bg = f"on_{colour}" - padded_outcome = f" {test_result.outcome.name[:4]} " - - iter_indicator = format_test_case_number(test_result) - mod_name = format_test_id(test_result) - if ( - test_result.outcome == TestOutcome.SKIP - or test_result.outcome == TestOutcome.XFAIL - ): - reason = test_result.test.marker.reason or "" - if reason: - reason = lightblack(f" [{reason}]") + """ + Outputs a single test result to the terminal in Ward's standard output + format which outputs a single test per line. + """ + outcome_tag = test_result.outcome.name[:4] + + test = test_result.test + test_location = format_test_location(test) + test_case_number = format_test_case_number(test) + + # Skip/Xfail tests may have a reason note attached that we'll print + if hasattr(test.marker, "reason"): + reason = test.marker.reason else: reason = "" - name_or_desc = test_result.test.description - indent = ( - len(padded_outcome) - + len(test_result.test.module_name) - + len(str(test_result.test.line_number)) - + len(iter_indicator) - + 4 - ) - width = get_terminal_size().width - indent - print( - colored(padded_outcome, color="grey", on_color=bg), - mod_name, - multiline_description(name_or_desc + reason, indent=indent, width=width), + grid = Table.grid() + grid.add_column() + grid.add_column() + grid.add_column() + + common_columns = ( + Padding(outcome_tag, style=outcome_to_style(test_result.outcome), pad=(0, 1, 0, 1)), + Padding(f"{test_location}{test_case_number}", style="muted", pad=(0, 1, 0, 1)), + test.description, ) + if reason: + grid.add_column(justify="right") + grid.add_row( + *common_columns, + Padding(reason, style="muted", pad=(0, 1, 0, 1)), + ) + else: + grid.add_row(*common_columns) + + console.print(grid) + def output_test_per_line(fail_limit, test_results_gen): num_failures = 0 all_results = [] - print() + + console.print() + try: for result in test_results_gen: output_test_result_line(result) - sys.stdout.write(Style.RESET_ALL) all_results.append(result) if result.outcome == TestOutcome.FAIL: num_failures += 1 @@ -147,26 +180,26 @@ def output_test_per_line(fail_limit, test_results_gen): def output_dots_global( - fail_limit: int, test_results_gen: Generator[TestResult, None, None] + fail_limit: int, test_results_gen: Generator[TestResult, None, None] ) -> List[TestResult]: column = 0 num_failures = 0 all_results = [] try: - print() + console.print() for result in test_results_gen: all_results.append(result) print_dot(result) column += 1 if column == get_terminal_size().width: - print() + console.print() column = 0 if result.outcome == TestOutcome.FAIL: num_failures += 1 if num_failures == fail_limit: break sys.stdout.flush() - print() + console.print() except KeyboardInterrupt: output_run_cancelled() finally: @@ -174,21 +207,12 @@ def output_dots_global( def print_dot(result): - colour = outcome_to_colour(result.outcome) - if result.outcome == TestOutcome.PASS: - print_no_break(colored(".", color=colour)) - elif result.outcome == TestOutcome.FAIL: - print_no_break(colored("F", color=colour)) - elif result.outcome == TestOutcome.XPASS: - print_no_break(colored("U", color=colour)) - elif result.outcome == TestOutcome.XFAIL: - print_no_break(colored("x", color=colour)) - elif result.outcome == TestOutcome.SKIP: - print_no_break(colored("s", color=colour)) + style = outcome_to_style(result.outcome) + console.print(result.outcome.display_char, style=style) def output_dots_module( - fail_limit: int, test_results_gen: Generator[TestResult, None, None] + fail_limit: int, test_results_gen: Generator[TestResult, None, None] ) -> List[TestResult]: current_path = Path("") rel_path = "" @@ -201,32 +225,28 @@ def output_dots_module( all_results.append(result) if result.test.path != current_path: dots_on_line = 0 - print() + console.print() current_path = result.test.path rel_path = str(current_path.relative_to(os.getcwd())) max_dots_per_line = ( - get_terminal_size().width - len(rel_path) - 2 + get_terminal_size().width - len(rel_path) - 2 ) # subtract 2 for ": " final_slash_idx = rel_path.rfind("/") if final_slash_idx != -1: - print_no_break( - lightblack(rel_path[: final_slash_idx + 1]) - + rel_path[final_slash_idx + 1 :] - + ": " - ) + console.print(rel_path[: final_slash_idx + 1], style="muted", end="") + console.print(rel_path[final_slash_idx + 1:] + ": ", end="") else: - print_no_break(f"\n{rel_path}: ") + console.print(f"\n{rel_path}: ", end="") print_dot(result) dots_on_line += 1 if dots_on_line == max_dots_per_line: - print_no_break("\n" + " " * (len(rel_path) + 2)) + console.print("\n" + " " * (len(rel_path) + 2), end="") dots_on_line = 0 if result.outcome == TestOutcome.FAIL: num_failures += 1 if num_failures == fail_limit: break - sys.stdout.flush() - print() + console.print() except KeyboardInterrupt: output_run_cancelled() finally: @@ -234,9 +254,9 @@ def output_dots_module( def output_run_cancelled(): - cprint( - "\n[WARD] Run cancelled - results for tests that ran shown below.", - color="yellow", + console.print( + "Run cancelled - results for tests that ran shown below.", + style="info", ) @@ -248,11 +268,11 @@ class TestResultWriterBase: } def __init__( - self, - suite, - test_output_style: str, - config_path: Optional[Path], - show_diff_symbols: bool = False, + self, + suite, + test_output_style: str, + config_path: Optional[Path], + show_diff_symbols: bool = False, ): self.suite = suite self.test_output_style = test_output_style @@ -263,23 +283,23 @@ def __init__( def output_header(self, time_to_collect): python_impl = platform.python_implementation() python_version = platform.python_version() - print(f"Ward {__version__}, {python_impl} {python_version}") + console.print(Text(f"Ward {__version__}, {python_impl} {python_version}", )) if self.config_path: try: path = self.config_path.relative_to(Path.cwd()) except ValueError: path = self.config_path.name - print(f"Using config from {path}") - print( + console.print(f"Using config from {path}") + console.print( f"Collected {self.suite.num_tests} tests " f"and {len(_DEFINED_FIXTURES)} fixtures " f"in {time_to_collect:.2f} seconds." ) def output_all_test_results( - self, - test_results_gen: Generator[TestResult, None, None], - fail_limit: Optional[int] = None, + self, + test_results_gen: Generator[TestResult, None, None], + fail_limit: Optional[int] = None, ) -> List[TestResult]: if not self.suite.num_tests: return [] @@ -300,11 +320,11 @@ def output_all_test_results( if failed_test_results: self.print_divider() else: - print() + console.print() return all_results def print_divider(self): - print(lightblack(f"{'_' * self.terminal_size.width}\n")) + console.print(Rule(style="muted")) def output_single_test_result(self, test_result: TestResult): """Indicate whether a test passed, failed, was skipped etc.""" @@ -317,7 +337,7 @@ def output_why_test_failed_header(self, test_result: TestResult): raise NotImplementedError() def output_test_result_summary( - self, test_results: List[TestResult], time_taken: float, duration: int + self, test_results: List[TestResult], time_taken: float, duration: int ): raise NotImplementedError() @@ -342,7 +362,7 @@ def output_test_failed_location(self, test_result: TestResult): def lightblack(s: str) -> str: - return f"{Fore.LIGHTBLACK_EX}{s}{Style.RESET_ALL}" + return s @dataclass @@ -372,7 +392,7 @@ def output_why_test_failed_header(self, test_result: TestResult): name_or_desc = colored(name_or_desc) failure_heading = ( - colored("Failure: ", color="cyan", attrs=["bold"]) + name_or_desc + "\n" + colored("Failure: ", color="cyan", attrs=["bold"]) + name_or_desc + "\n" ) print(indent(failure_heading, INDENT)) @@ -387,13 +407,13 @@ def output_why_test_failed(self, test_result: TestResult): gutter_width = len(str(len(src_lines) + line_num)) - def gutter(i): + def gutter(i: int) -> Text: offset_line_num = i + line_num rv = f"{str(offset_line_num):>{gutter_width}}" if offset_line_num == err.error_line: - return colored(f"{rv} ! ", color="red") + return Text(f"{rv} ! ", style="red") else: - return lightblack(f"{rv} | ") + return Text(f"{rv} | ", style="muted") if err.operator in Comparison: src = "".join(src_lines) @@ -401,15 +421,14 @@ def gutter(i): src = f"".join( [gutter(i) + l for i, l in enumerate(src.splitlines(keepends=True))] ) - print(indent(src, DOUBLE_INDENT)) + # pre-Rich: console.print(indent(src, DOUBLE_INDENT)) + console.print(Padding(src, (0, 0, 0, 4))) if err.operator == Comparison.Equals: self.print_failure_equals(err) else: self.print_traceback(err) - print(Style.RESET_ALL) - def print_failure_equals(self, err: TestFailure): diff_msg = ( f"{colored('Comparison:', color='cyan', attrs=['bold'])} {colored('LHS', color='green')}" @@ -439,15 +458,8 @@ def print_traceback(self, err): else: print(str(err)) - def result_checkbox(self, expect): - if expect.success: - result_marker = f"[ {Fore.GREEN}okay{Style.RESET_ALL} ]{Fore.GREEN}" - else: - result_marker = f"[ {Fore.RED}fail{Style.RESET_ALL} ]{Fore.RED}" - return result_marker - def output_test_result_summary( - self, test_results: List[TestResult], time_taken: float, show_slowest: int + self, test_results: List[TestResult], time_taken: float, show_slowest: int ): if show_slowest: self._output_slowest_tests(test_results, show_slowest) @@ -519,7 +531,7 @@ def output_captured_stdout(self, test_result: TestResult): def output_test_failed_location(self, test_result: TestResult): if isinstance(test_result.error, TestFailure) or isinstance( - test_result.error, AssertionError + test_result.error, AssertionError ): print( indent(colored("Location:", color="cyan", attrs=["bold"]), INDENT), @@ -530,7 +542,7 @@ def output_test_run_post_failure_summary(self, test_results: List[TestResult]): pass def _get_outcome_counts( - self, test_results: List[TestResult] + self, test_results: List[TestResult] ) -> Dict[TestOutcome, int]: return { TestOutcome.PASS: len( @@ -565,17 +577,28 @@ def outcome_to_colour(outcome: TestOutcome) -> str: }[outcome] +def outcome_to_style(outcome: TestOutcome) -> str: + return { + TestOutcome.PASS: "pass", + TestOutcome.SKIP: "primary", + TestOutcome.FAIL: "fail", + TestOutcome.XFAIL: "xfail", + TestOutcome.XPASS: "warning", + TestOutcome.DRYRUN: "dryrun", + }[outcome] + + def scope_to_colour(scope: Scope) -> str: return {Scope.Test: "green", Scope.Module: "blue", Scope.Global: "magenta"}[scope] def output_fixtures( - fixtures: List[Fixture], - tests: List[Test], - show_scopes: bool, - show_docstrings: bool, - show_dependencies: bool, - show_dependency_trees: bool, + fixtures: List[Fixture], + tests: List[Test], + show_scopes: bool, + show_docstrings: bool, + show_dependencies: bool, + show_dependency_trees: bool, ): generated_tests = itertools.chain.from_iterable( test.get_parameterised_instances() for test in tests @@ -599,14 +622,14 @@ def output_fixtures( def output_fixture_information( - fixture: Fixture, - used_by_tests: Collection[Test], - fixtures_to_children: _TYPE_FIXTURE_TO_FIXTURES, - fixtures_to_parents: _TYPE_FIXTURE_TO_FIXTURES, - show_scopes: bool, - show_docstrings: bool, - show_dependencies: bool, - show_dependency_trees: bool, + fixture: Fixture, + used_by_tests: Collection[Test], + fixtures_to_children: _TYPE_FIXTURE_TO_FIXTURES, + fixtures_to_parents: _TYPE_FIXTURE_TO_FIXTURES, + show_scopes: bool, + show_docstrings: bool, + show_dependencies: bool, + show_dependency_trees: bool, ): lines = [format_fixture(fixture, show_scope=show_scopes)] @@ -664,7 +687,7 @@ def output_fixture_information( print("\n".join(lines)) -def yield_fixture_usages_by_tests(used_by: List[Test]) -> Iterator[str]: +def yield_fixture_usages_by_tests(used_by: Iterable[Test]) -> Iterator[str]: grouped_used_by = group_by(used_by, key=lambda t: t.description) for idx, (description, tests) in enumerate(grouped_used_by.items()): test = tests[0] @@ -677,12 +700,12 @@ def yield_fixture_usages_by_tests(used_by: List[Test]) -> Iterator[str]: def yield_fixture_dependency_tree( - fixture: Fixture, - fixtures_to_parents_or_children: _TYPE_FIXTURE_TO_FIXTURES, - show_scopes: bool, - max_depth: Optional[int], - depth: int = 0, - prefix=INDENT, + fixture: Fixture, + fixtures_to_parents_or_children: _TYPE_FIXTURE_TO_FIXTURES, + show_scopes: bool, + max_depth: Optional[int], + depth: int = 0, + prefix=INDENT, ) -> Iterator[str]: if max_depth is not None and depth >= max_depth: return @@ -738,7 +761,7 @@ def get_exit_code(results: Iterable[TestResult]) -> ExitCode: return ExitCode.NO_TESTS_FOUND if any( - r.outcome == TestOutcome.FAIL or r.outcome == TestOutcome.XPASS for r in results + r.outcome == TestOutcome.FAIL or r.outcome == TestOutcome.XPASS for r in results ): exit_code = ExitCode.FAILED else: diff --git a/ward/testing.py b/ward/testing.py index b44e6feb..47cda83d 100644 --- a/ward/testing.py +++ b/ward/testing.py @@ -369,7 +369,7 @@ def fixtures(self) -> Dict[str, Fixture]: } def _get_default_args( - self, func: Optional[Union[Callable, Fixture]] = None + self, func: Optional[Union[Callable, Fixture]] = None ) -> Dict[str, Any]: """ Returns a mapping of test argument names to values. @@ -395,7 +395,7 @@ def _get_default_args( return default_binding.arguments def _resolve_single_arg( - self, arg: Callable, cache: FixtureCache + self, arg: Callable, cache: FixtureCache ) -> Union[Any, Fixture]: """ Get the fixture return value @@ -409,7 +409,7 @@ def _resolve_single_arg( fixture = Fixture(arg) if cache.contains( - fixture, fixture.scope, self.test.scope_key_from(fixture.scope) + fixture, fixture.scope, self.test.scope_key_from(fixture.scope) ): return cache.get( fixture.key, fixture.scope, self.test.scope_key_from(fixture.scope) @@ -479,7 +479,7 @@ def _unpack_resolved(self, fixture_dict: Dict[str, Any]) -> Dict[str, Any]: def fixtures_used_directly_by_tests( - tests: Iterable[Test], + tests: Iterable[Test], ) -> Mapping[Fixture, Collection[Test]]: test_to_fixtures = {test: test.resolver.fixtures for test in tests} @@ -545,7 +545,20 @@ class TestOutcome(Enum): SKIP = auto() XFAIL = auto() # expected fail XPASS = auto() # unexpected pass - DRYRUN = auto() + DRYRUN = auto() # tests arent executed during dryruns + + @property + def display_char(self): + display_chars = { + TestOutcome.PASS: ".", + TestOutcome.FAIL: "F", + TestOutcome.SKIP: "-", + TestOutcome.XPASS: "U", + TestOutcome.XFAIL: "x", + TestOutcome.DRYRUN: ".", + } + assert len(display_chars) == len(TestOutcome) + return display_chars[self] @dataclass From 761cdf90cf262a7dac53fcdc1213dfc1b3fb6da6 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Sat, 7 Nov 2020 00:34:56 +0000 Subject: [PATCH 02/14] More conversion over to rich --- ward/diff.py | 6 +- ward/terminal.py | 198 +++++++++++++++++-------------------- ward/testing.py | 13 +++ ward/tests/test_collect.py | 9 +- 4 files changed, 114 insertions(+), 112 deletions(-) diff --git a/ward/diff.py b/ward/diff.py index ef4bf7bc..d805923e 100644 --- a/ward/diff.py +++ b/ward/diff.py @@ -6,7 +6,7 @@ from termcolor import colored -def make_diff(lhs, rhs, width=80, show_symbols=False) -> str: +def make_diff(lhs, rhs, width=80, show_symbols=False): """Transform input into best format for diffing, then return output diff.""" if isinstance(lhs, str): lhs_repr = lhs @@ -107,14 +107,14 @@ def build_unified_diff(lhs_repr: str, rhs_repr: str) -> str: current_span = "" current_span += line_to_rewrite[ index - 2 - ] # Subtract 2 to account for code at start of line + ] # Subtract 2 to account for code at start of line prev_char = char index += 1 # Lines starting with ? aren't guaranteed to be the same length as the lines before them # so some characters may be left over. Add any leftover characters to the output remaining_index = ( - index - 3 + index - 3 ) # subtract 2 for code at start, and 1 to remove the newline char if prev_marker == "+": output_lines[last_output_idx] += colored( diff --git a/ward/terminal.py b/ward/terminal.py index f5bdad1c..9f155f2c 100644 --- a/ward/terminal.py +++ b/ward/terminal.py @@ -19,16 +19,17 @@ Collection, ) -from pygments import highlight -from pygments.formatters.terminal import TerminalFormatter -from pygments.lexers.python import PythonLexer -from rich.console import Console +from rich.console import Console, RenderableType, RenderGroup from rich.highlighter import NullHighlighter +from rich.markdown import Markdown from rich.padding import Padding +from rich.panel import Panel from rich.rule import Rule +from rich.syntax import Syntax from rich.table import Table from rich.text import Text from rich.theme import Theme +from rich.traceback import Traceback from termcolor import colored, cprint from ward._ward_version import __version__ @@ -45,7 +46,10 @@ from ward.testing import TestOutcome, TestResult from ward.util import group_by +HORIZONTAL_PAD = (0, 1, 0, 1) + INDENT = " " * 2 +BODY_INDENT_SIZE = 4 def make_indent(depth=1): @@ -55,14 +59,22 @@ def make_indent(depth=1): DOUBLE_INDENT = make_indent(depth=2) theme = Theme({ + "title": "bold", "heading": "bold", - "primary": "black on blue", - "pass": "black on green", - "warning": "black on yellow", - "fail": "black on red", - "xfail": "black on magenta", + "pass": "#ffffff on #137C39", + "pass.textonly": "#189F4A", + "fail": "#ffffff on #BF2D2D", + "fail.textonly": "#BF2D2D", + "fail.header": "bold #BF2D2D", + "skip": "#ffffff on #0E67B3", + "skip.textonly": "#0E67B3", + "xpass": "#162740 on #F4C041", + "xpass.textonly": "#F4C041", + "xfail": "#ffffff on #695CC8", + "xfail.textonly": "#695CC8", "muted": "dim", "info": "yellow italic", + "rule.line": "#189F4A", }) console = Console(theme=theme, highlighter=NullHighlighter()) @@ -129,6 +141,7 @@ def output_test_result_line(test_result: TestResult): test = test_result.test test_location = format_test_location(test) test_case_number = format_test_case_number(test) + test_style = outcome_to_style(test_result.outcome) # Skip/Xfail tests may have a reason note attached that we'll print if hasattr(test.marker, "reason"): @@ -136,22 +149,21 @@ def output_test_result_line(test_result: TestResult): else: reason = "" - grid = Table.grid() + grid = Table.grid(expand=True) grid.add_column() grid.add_column() grid.add_column() - common_columns = ( - Padding(outcome_tag, style=outcome_to_style(test_result.outcome), pad=(0, 1, 0, 1)), + Padding(outcome_tag, style=test_style, pad=(0, 1, 0, 1)), Padding(f"{test_location}{test_case_number}", style="muted", pad=(0, 1, 0, 1)), - test.description, + Padding(Markdown(test.description, inline_code_theme="ansi_dark"), pad=(0, 1, 0, 0)), ) if reason: - grid.add_column(justify="right") + grid.add_column(justify="center", style=test_style) grid.add_row( *common_columns, - Padding(reason, style="muted", pad=(0, 1, 0, 1)), + Padding(Padding(reason, pad=(0, 1, 0, 1)), pad=(0, 1, 0, 1)), ) else: grid.add_row(*common_columns) @@ -208,7 +220,7 @@ def output_dots_global( def print_dot(result): style = outcome_to_style(result.outcome) - console.print(result.outcome.display_char, style=style) + console.print(result.outcome.display_char, style=style, end="") def output_dots_module( @@ -283,17 +295,19 @@ def __init__( def output_header(self, time_to_collect): python_impl = platform.python_implementation() python_version = platform.python_version() - console.print(Text(f"Ward {__version__}, {python_impl} {python_version}", )) + console.print( + Rule(Text(f"Ward {__version__}", style="title")), + ) if self.config_path: try: path = self.config_path.relative_to(Path.cwd()) except ValueError: path = self.config_path.name - console.print(f"Using config from {path}") + console.print(f"Loaded config from [b]{path}[/b].") console.print( - f"Collected {self.suite.num_tests} tests " - f"and {len(_DEFINED_FIXTURES)} fixtures " - f"in {time_to_collect:.2f} seconds." + f"Collected [b]{self.suite.num_tests}[/b] tests " + f"and [b]{len(_DEFINED_FIXTURES)}[/b] fixtures " + f"in [b]{time_to_collect:.2f}[/b] seconds." ) def output_all_test_results( @@ -307,16 +321,13 @@ def output_all_test_results( self.test_output_style, output_test_per_line ) all_results = output_tests(fail_limit, test_results_gen) - self.output_test_run_post_failure_summary(test_results=all_results) failed_test_results = [r for r in all_results if r.outcome == TestOutcome.FAIL] for failure in failed_test_results: - self.print_divider() self.output_why_test_failed_header(failure) + self.output_test_failed_location(failure) self.output_why_test_failed(failure) self.output_captured_stderr(failure) self.output_captured_stdout(failure) - self.output_test_failed_location(failure) - if failed_test_results: self.print_divider() else: @@ -348,9 +359,6 @@ def output_why_test_failed(self, test_result: TestResult): """ raise NotImplementedError() - def output_test_run_post_failure_summary(self, test_results: List[TestResult]): - raise NotImplementedError() - def output_captured_stderr(self, test_result: TestResult): raise NotImplementedError() @@ -384,45 +392,19 @@ def get_terminal_size() -> TerminalSize: class SimpleTestResultWrite(TestResultWriterBase): def output_why_test_failed_header(self, test_result: TestResult): test = test_result.test - - if test.description: - name_or_desc = test.description - else: - name_or_desc = test.qualified_name - - name_or_desc = colored(name_or_desc) - failure_heading = ( - colored("Failure: ", color="cyan", attrs=["bold"]) + name_or_desc + "\n" - ) - print(indent(failure_heading, INDENT)) + console.print(Rule(title=Text(test.description, style="fail.header"), style="fail.textonly")) def output_why_test_failed(self, test_result: TestResult): err = test_result.error if isinstance(err, TestFailure): src_lines, line_num = inspect.getsourcelines(test_result.test.fn) - # TODO: Only include lines up to where the failure occurs - if src_lines[-1].strip() == "": - src_lines = src_lines[:-1] - - gutter_width = len(str(len(src_lines) + line_num)) - - def gutter(i: int) -> Text: - offset_line_num = i + line_num - rv = f"{str(offset_line_num):>{gutter_width}}" - if offset_line_num == err.error_line: - return Text(f"{rv} ! ", style="red") - else: - return Text(f"{rv} | ", style="muted") - if err.operator in Comparison: src = "".join(src_lines) - src = highlight(src, PythonLexer(), TerminalFormatter()) - src = f"".join( - [gutter(i) + l for i, l in enumerate(src.splitlines(keepends=True))] - ) - # pre-Rich: console.print(indent(src, DOUBLE_INDENT)) - console.print(Padding(src, (0, 0, 0, 4))) + src = Syntax(src, "python", start_line=line_num, line_numbers=True, highlight_lines={err.error_line}, + background_color="default", theme="ansi_dark") + src = Padding(src, (1, 0, 1, 4)) + console.print(src) if err.operator == Comparison.Equals: self.print_failure_equals(err) @@ -430,11 +412,11 @@ def gutter(i: int) -> Text: self.print_traceback(err) def print_failure_equals(self, err: TestFailure): - diff_msg = ( - f"{colored('Comparison:', color='cyan', attrs=['bold'])} {colored('LHS', color='green')}" - f" vs {colored('RHS', color='red')} shown below\n" - ) - print(indent(diff_msg, INDENT)) + diff_msg = Text("LHS", style="pass.textonly") + diff_msg.append(" vs ", style="default") + diff_msg.append("RHS", style="fail.textonly") + diff_msg.append(" shown below", style="default") + console.print(Padding(diff_msg, pad=(0, 0, 1, 2))) diff = make_diff( err.lhs, err.rhs, @@ -446,15 +428,8 @@ def print_failure_equals(self, err: TestFailure): def print_traceback(self, err): trace = getattr(err, "__traceback__", "") if trace: - trc = traceback.format_exception(None, err, trace) - for line in trc: - sublines = line.split("\n") - for subline in sublines: - content = " " * 4 + subline - if subline.lstrip().startswith('File "'): - cprint(content, color="blue") - else: - print(content) + tb = Traceback.from_exception(err.__class__, err, trace, theme="ansi_dark") + console.print(tb) else: print(str(err)) @@ -463,35 +438,41 @@ def output_test_result_summary( ): if show_slowest: self._output_slowest_tests(test_results, show_slowest) + + result_table = Table.grid() + result_table.add_column(justify="right") + result_table.add_column() + result_table.add_column() + outcome_counts = self._get_outcome_counts(test_results) + test_count = sum(outcome_counts.values()) + result_table.add_row( + Padding(str(test_count), pad=HORIZONTAL_PAD, style="bold"), + Padding("Tests Found", pad=HORIZONTAL_PAD), + style="default" + ) + for outcome, count in outcome_counts.items(): + if count > 0: + result_table.add_row( + Padding(str(count), pad=HORIZONTAL_PAD, style="bold"), + Padding(outcome.display_name, pad=HORIZONTAL_PAD), + Padding(f"({100 * count / test_count:.1f}%)", pad=HORIZONTAL_PAD), + style=outcome_to_style(outcome) + ) exit_code = get_exit_code(test_results) if exit_code == ExitCode.SUCCESS: - result = colored(exit_code.name, color="green") + result_style = "pass.textonly" else: - result = colored(exit_code.name, color="red") - - output = f"{result} in {time_taken:.2f} seconds" - if test_results: - output += " [ " - - if outcome_counts[TestOutcome.FAIL]: - output += f"{colored(str(outcome_counts[TestOutcome.FAIL]) + ' failed', color='red')} " - if outcome_counts[TestOutcome.XPASS]: - output += f"{colored(str(outcome_counts[TestOutcome.XPASS]) + ' xpassed', color='yellow')} " - if outcome_counts[TestOutcome.XFAIL]: - output += f"{colored(str(outcome_counts[TestOutcome.XFAIL]) + ' xfailed', color='magenta')} " - if outcome_counts[TestOutcome.SKIP]: - output += f"{colored(str(outcome_counts[TestOutcome.SKIP]) + ' skipped', color='blue')} " - if outcome_counts[TestOutcome.PASS]: - output += f"{colored(str(outcome_counts[TestOutcome.PASS]) + ' passed', color='green')}" - if outcome_counts[TestOutcome.DRYRUN]: - output += f"{colored(str(outcome_counts[TestOutcome.DRYRUN]) + ' printed', color='green')}" - - if test_results: - output += " ] " - - print(output) + result_style = "fail.textonly" + + result_summary_panel = Panel(result_table, title="Summary", style="none", expand=False, + border_style=result_style) + console.print(result_summary_panel) + + console.print( + Rule(f"[b]{exit_code.clean_name}[/b] in [b]{time_taken:.2f}[/b] seconds", style=result_style) + ) def _output_slowest_tests(self, test_results: List[TestResult], num_tests: int): test_results = sorted( @@ -533,14 +514,17 @@ def output_test_failed_location(self, test_result: TestResult): if isinstance(test_result.error, TestFailure) or isinstance( test_result.error, AssertionError ): - print( - indent(colored("Location:", color="cyan", attrs=["bold"]), INDENT), - f"{test_result.test.path.relative_to(Path.cwd())}:{test_result.error.error_line}", + # print( + # indent(colored("Location:", color="cyan", attrs=["bold"]), INDENT), + # f"{test_result.test.path.relative_to(Path.cwd())}:{test_result.error.error_line}", + # ) + console.print( + Padding( + Text(f"Failed at {test_result.test.path.relative_to(Path.cwd())}:{test_result.error.error_line}"), + pad=(1, 0, 0, 2) + ) ) - def output_test_run_post_failure_summary(self, test_results: List[TestResult]): - pass - def _get_outcome_counts( self, test_results: List[TestResult] ) -> Dict[TestOutcome, int]: @@ -580,10 +564,10 @@ def outcome_to_colour(outcome: TestOutcome) -> str: def outcome_to_style(outcome: TestOutcome) -> str: return { TestOutcome.PASS: "pass", - TestOutcome.SKIP: "primary", + TestOutcome.SKIP: "skip", TestOutcome.FAIL: "fail", TestOutcome.XFAIL: "xfail", - TestOutcome.XPASS: "warning", + TestOutcome.XPASS: "xpass", TestOutcome.DRYRUN: "dryrun", }[outcome] @@ -755,6 +739,10 @@ class ExitCode(Enum): ERROR = 2 NO_TESTS_FOUND = 3 + @property + def clean_name(self): + return self.name.replace("_", " ") + def get_exit_code(results: Iterable[TestResult]) -> ExitCode: if not results: diff --git a/ward/testing.py b/ward/testing.py index 47cda83d..7bee185e 100644 --- a/ward/testing.py +++ b/ward/testing.py @@ -560,6 +560,19 @@ def display_char(self): assert len(display_chars) == len(TestOutcome) return display_chars[self] + @property + def display_name(self): + display_names = { + TestOutcome.PASS: "Passes", + TestOutcome.FAIL: "Failures", + TestOutcome.SKIP: "Skips", + TestOutcome.XPASS: "Unexpected Passes", + TestOutcome.XFAIL: "Expected Failures", + TestOutcome.DRYRUN: "Dry-runs", + } + assert len(display_names) == len(TestOutcome) + return display_names[self] + @dataclass class TestResult: diff --git a/ward/tests/test_collect.py b/ward/tests/test_collect.py index 31e25511..f781cd13 100644 --- a/ward/tests/test_collect.py +++ b/ward/tests/test_collect.py @@ -34,19 +34,20 @@ def tests_to_search(named_test=named_test): return [named_test] -@test("filter_tests matches on qualified test name") +@test("__filter_tests__ matches on qualified test name") def _(tests=tests_to_search, named=named_test): results = filter_tests(tests, query="my_module.named") - assert list(results) == [named] + assert list(results) == [1] @test("filter_tests matches on test name alone") def _(tests=tests_to_search, named=named_test): results = filter_tests(tests, query="named") - assert list(results) == [named] + raise ZeroDivisionError("asdas") + assert list(results) == [1] -@test("filter_tests query='fox' returns tests with 'fox' in the body") +@test("filter_tests `query='fox'` returns tests with `'fox'` in the body") def _(tests=tests_to_search, named=named_test): results = filter_tests(tests, query="fox") assert list(results) == [named] From 9618b9f874d3b9d9db657eb029b211a24bfb2ae5 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Sat, 7 Nov 2020 00:39:00 +0000 Subject: [PATCH 03/14] Fix tests --- ward/tests/test_collect.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ward/tests/test_collect.py b/ward/tests/test_collect.py index f781cd13..30c900be 100644 --- a/ward/tests/test_collect.py +++ b/ward/tests/test_collect.py @@ -37,14 +37,13 @@ def tests_to_search(named_test=named_test): @test("__filter_tests__ matches on qualified test name") def _(tests=tests_to_search, named=named_test): results = filter_tests(tests, query="my_module.named") - assert list(results) == [1] + assert list(results) == [named] @test("filter_tests matches on test name alone") def _(tests=tests_to_search, named=named_test): results = filter_tests(tests, query="named") - raise ZeroDivisionError("asdas") - assert list(results) == [1] + assert list(results) == [named] @test("filter_tests `query='fox'` returns tests with `'fox'` in the body") From a4212fbe86d4059b81fd2322828cede52b7acfac Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Sat, 7 Nov 2020 11:46:56 +0000 Subject: [PATCH 04/14] Add dry-run styling to Rich theme --- ward/terminal.py | 3 ++- ward/testing.py | 11 ++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/ward/terminal.py b/ward/terminal.py index 9f155f2c..651705b1 100644 --- a/ward/terminal.py +++ b/ward/terminal.py @@ -74,6 +74,7 @@ def make_indent(depth=1): "xfail.textonly": "#695CC8", "muted": "dim", "info": "yellow italic", + "dryrun": "#ffffff on #162740", "rule.line": "#189F4A", }) console = Console(theme=theme, highlighter=NullHighlighter()) @@ -557,7 +558,7 @@ def outcome_to_colour(outcome: TestOutcome) -> str: TestOutcome.FAIL: "red", TestOutcome.XFAIL: "magenta", TestOutcome.XPASS: "yellow", - TestOutcome.DRYRUN: "green", + TestOutcome.DRYRUN: "pass", }[outcome] diff --git a/ward/testing.py b/ward/testing.py index 7bee185e..24a189ef 100644 --- a/ward/testing.py +++ b/ward/testing.py @@ -135,20 +135,17 @@ def run(self, cache: FixtureCache, dry_run=False) -> "TestResult": stack.enter_context(redirect_stdout(self.sout)) stack.enter_context(redirect_stderr(self.serr)) - if isinstance(self.marker, SkipMarker): + if dry_run: with closing(self.sout), closing(self.serr): - result = TestResult(self, TestOutcome.SKIP) + result = TestResult(self, TestOutcome.DRYRUN) return result - if dry_run: + if isinstance(self.marker, SkipMarker): with closing(self.sout), closing(self.serr): - result = TestResult(self, TestOutcome.DRYRUN) + result = TestResult(self, TestOutcome.SKIP) return result try: - # TODO:onlyanegg: I don't love this. We're setting up the - # fixture within the testing module, but cleaning it up in the - # suite module. resolved_args = self.resolver.resolve_args(cache) self.format_description(resolved_args) if self.is_async_test: From 6a6241ed81496550ace196a30999fe47c5689474 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Sat, 7 Nov 2020 12:15:02 +0000 Subject: [PATCH 05/14] LongestRunningTestsDisplay Rich component --- ward/terminal.py | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/ward/terminal.py b/ward/terminal.py index 651705b1..37c31076 100644 --- a/ward/terminal.py +++ b/ward/terminal.py @@ -3,7 +3,6 @@ import os import platform import sys -import traceback from dataclasses import dataclass from enum import Enum from pathlib import Path @@ -19,7 +18,7 @@ Collection, ) -from rich.console import Console, RenderableType, RenderGroup +from rich.console import Console, ConsoleOptions, RenderResult from rich.highlighter import NullHighlighter from rich.markdown import Markdown from rich.padding import Padding @@ -30,7 +29,7 @@ from rich.text import Text from rich.theme import Theme from rich.traceback import Traceback -from termcolor import colored, cprint +from termcolor import colored from ward._ward_version import __version__ from ward.diff import make_diff @@ -273,6 +272,34 @@ def output_run_cancelled(): ) +@dataclass +class LongestRunningTestsDisplay: + all_tests_in_session: List[TestResult] + num_tests_to_show: int + + def __rich_console__(self, c: Console, options: ConsoleOptions) -> RenderResult: + test_results = sorted( + self.all_tests_in_session, key=lambda r: r.test.timer.duration, reverse=True + ) + grid = Table.grid() + grid.add_column() # Time taken + grid.add_column() # Test ID + grid.add_column() # Test description + + for result in test_results[:self.num_tests_to_show]: + time_taken_millis = result.test.timer.duration * 1000 + test_id = format_test_id(result) + description = result.test.description + grid.add_row(f"{time_taken_millis:.0f}ms", test_id, description) + + panel = Panel( + grid, + title="[b white]Slowest Tests[/b white]", + ) + + yield panel + + class TestResultWriterBase: runtime_output_strategies = { "test-per-line": output_test_per_line, @@ -449,7 +476,7 @@ def output_test_result_summary( test_count = sum(outcome_counts.values()) result_table.add_row( Padding(str(test_count), pad=HORIZONTAL_PAD, style="bold"), - Padding("Tests Found", pad=HORIZONTAL_PAD), + Padding("Tests Encountered", pad=HORIZONTAL_PAD), style="default" ) for outcome, count in outcome_counts.items(): @@ -467,7 +494,7 @@ def output_test_result_summary( else: result_style = "fail.textonly" - result_summary_panel = Panel(result_table, title="Summary", style="none", expand=False, + result_summary_panel = Panel(result_table, title="[b white]Summary[/b white]", style="none", expand=False, border_style=result_style) console.print(result_summary_panel) @@ -479,9 +506,9 @@ def _output_slowest_tests(self, test_results: List[TestResult], num_tests: int): test_results = sorted( test_results, key=lambda r: r.test.timer.duration, reverse=True ) - self.print_divider() heading = f"{colored('Longest Running Tests:', color='cyan', attrs=['bold'])}\n" print(indent(heading, INDENT)) + for result in test_results[:num_tests]: test_id = format_test_id(result) message = f"{result.test.timer.duration:.2f} sec {test_id} {result.test.description} " @@ -558,7 +585,7 @@ def outcome_to_colour(outcome: TestOutcome) -> str: TestOutcome.FAIL: "red", TestOutcome.XFAIL: "magenta", TestOutcome.XPASS: "yellow", - TestOutcome.DRYRUN: "pass", + TestOutcome.DRYRUN: "green", }[outcome] From 4665adcaa93908bb38a0f06685a4d5ae4ebe15d8 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Sat, 7 Nov 2020 13:22:11 +0000 Subject: [PATCH 06/14] Complete slowest tests panel component --- ward/terminal.py | 59 ++++++++++++++++++++++++++++------------ ward/tests/test_suite.py | 2 +- 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/ward/terminal.py b/ward/terminal.py index 37c31076..0a391105 100644 --- a/ward/terminal.py +++ b/ward/terminal.py @@ -1,7 +1,9 @@ import inspect import itertools +import math import os import platform +import statistics import sys from dataclasses import dataclass from enum import Enum @@ -18,7 +20,7 @@ Collection, ) -from rich.console import Console, ConsoleOptions, RenderResult +from rich.console import Console, ConsoleOptions, RenderResult, RenderGroup from rich.highlighter import NullHighlighter from rich.markdown import Markdown from rich.padding import Padding @@ -94,15 +96,11 @@ def multiline_description(s: str, indent: int, width: int) -> str: return rv -def format_test_id(test_result: TestResult) -> (str, str): +def format_test_id(test_result: TestResult) -> str: """ Format module name, line number, and test case number """ - test_id = lightblack( - f"{format_test_location(test_result.test)}{format_test_case_number(test_result.test)}:" - ) - - return test_id + return f"{format_test_location(test_result.test)}{format_test_case_number(test_result.test)}" def format_test_location(test: Test) -> str: @@ -273,28 +271,55 @@ def output_run_cancelled(): @dataclass -class LongestRunningTestsDisplay: +class TestTimingStats: all_tests_in_session: List[TestResult] num_tests_to_show: int - def __rich_console__(self, c: Console, options: ConsoleOptions) -> RenderResult: + @property + def _raw_test_durations_secs(self): + return [r.test.timer.duration for r in self.all_tests_in_session] + + @property + def median_secs(self): + return statistics.median(self._raw_test_durations_secs) + + @property + def percentile99_secs(self): + data = self._raw_test_durations_secs + size = len(data) + percentile = 99 + return sorted(data)[int(math.ceil((size * percentile) / 100)) - 1] + + def __rich_console__(self, c: Console, co: ConsoleOptions) -> RenderResult: test_results = sorted( self.all_tests_in_session, key=lambda r: r.test.timer.duration, reverse=True ) - grid = Table.grid() - grid.add_column() # Time taken + grid = Table.grid(padding=(0, 2, 0, 0)) + grid.add_column(justify="right") # Time taken grid.add_column() # Test ID grid.add_column() # Test description for result in test_results[:self.num_tests_to_show]: - time_taken_millis = result.test.timer.duration * 1000 + time_taken_secs = result.test.timer.duration + time_taken_millis = time_taken_secs * 1000 test_id = format_test_id(result) description = result.test.description - grid.add_row(f"{time_taken_millis:.0f}ms", test_id, description) + grid.add_row(f"[b]{time_taken_millis:.0f}[/b]ms", Text(test_id, style="muted"), description) + num_slowest_displayed = min(len(self.all_tests_in_session), self.num_tests_to_show) panel = Panel( - grid, - title="[b white]Slowest Tests[/b white]", + RenderGroup( + Padding( + f"Median: [b]{self.median_secs * 1000:.2f}[/b]ms" + f" [muted]|[/muted] " + f"99th Percentile: [b]{self.percentile99_secs * 1000:.2f}[/b]ms", + pad=(0, 0, 1, 0) + ), + grid, + ), + title=f"[b white]{num_slowest_displayed} Slowest Tests[/b white]", + style="none", + border_style="rule.line", ) yield panel @@ -465,7 +490,7 @@ def output_test_result_summary( self, test_results: List[TestResult], time_taken: float, show_slowest: int ): if show_slowest: - self._output_slowest_tests(test_results, show_slowest) + console.print(TestTimingStats(test_results, show_slowest)) result_table = Table.grid() result_table.add_column(justify="right") @@ -494,7 +519,7 @@ def output_test_result_summary( else: result_style = "fail.textonly" - result_summary_panel = Panel(result_table, title="[b white]Summary[/b white]", style="none", expand=False, + result_summary_panel = Panel(result_table, title="[b white]Results[/b white]", style="none", expand=False, border_style=result_style) console.print(result_summary_panel) diff --git a/ward/tests/test_suite.py b/ward/tests/test_suite.py index 24a24b69..a8497ced 100644 --- a/ward/tests/test_suite.py +++ b/ward/tests/test_suite.py @@ -90,7 +90,7 @@ def _(skipped=skipped_test, example=example_test): expected_runs = [ TestResult(example, TestOutcome.DRYRUN, None, ""), - TestResult(skipped, TestOutcome.SKIP, None, ""), + TestResult(skipped, TestOutcome.DRYRUN, None, ""), ] assert test_runs == expected_runs From cf96622522cab4a15a857750cb30d40150e6de05 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Sat, 7 Nov 2020 13:28:10 +0000 Subject: [PATCH 07/14] Bump version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c3da5659..245c95ac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ path = ["ward/tests"] [tool.poetry] name = "ward" -version = "0.48.0b0" +version = "0.49.0b0" description = "A modern Python testing framework" exclude = ["ward/tests"] authors = ["Darren Burns "] From 6445f85cc2bf50e0253aaf8b195509825c655476 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Fri, 19 Feb 2021 12:24:38 +0000 Subject: [PATCH 08/14] Move all test output to Rich --- poetry.lock | 417 +++++++++++++++++++++------------------- pyproject.toml | 2 +- ward/terminal.py | 56 ++---- ward/tests/test_util.py | 20 +- 4 files changed, 248 insertions(+), 247 deletions(-) diff --git a/poetry.lock b/poetry.lock index 435e8aae..127b6b9c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,32 +1,32 @@ [[package]] -category = "dev" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." name = "appdirs" +version = "1.4.4" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" optional = false python-versions = "*" -version = "1.4.4" [[package]] -category = "dev" -description = "Classes Without Boilerplate" name = "attrs" +version = "20.3.0" +description = "Classes Without Boilerplate" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "20.3.0" [package.extras] -dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] docs = ["furo", "sphinx", "zope.interface"] -tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] -tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] [[package]] -category = "dev" -description = "The uncompromising code formatter." name = "black" +version = "19.10b0" +description = "The uncompromising code formatter." +category = "dev" optional = false python-versions = ">=3.6" -version = "19.10b0" [package.dependencies] appdirs = "*" @@ -41,232 +41,225 @@ typed-ast = ">=1.4.0" d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] [[package]] -category = "main" -description = "Composable command line interface toolkit" name = "click" +version = "7.1.2" +description = "Composable command line interface toolkit" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "7.1.2" [[package]] -category = "main" -description = "Extends click.Group to invoke a command without explicit subcommand name" name = "click-default-group" +version = "1.2.2" +description = "Extends click.Group to invoke a command without explicit subcommand name" +category = "main" optional = false python-versions = "*" -version = "1.2.2" [package.dependencies] click = "*" [[package]] -category = "main" -description = "Cross-platform colored terminal text." name = "colorama" +version = "0.4.4" +description = "Cross-platform colored terminal text." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "0.4.4" [[package]] -category = "main" -description = "Python parser for the CommonMark Markdown spec" name = "commonmark" +version = "0.9.1" +description = "Python parser for the CommonMark Markdown spec" +category = "main" optional = false python-versions = "*" -version = "0.9.1" [package.extras] -test = ["flake8 (3.7.8)", "hypothesis (3.55.3)"] +test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"] [[package]] -category = "dev" -description = "Code coverage measurement for Python" name = "coverage" +version = "5.4" +description = "Code coverage measurement for Python" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "5.3" [package.extras] toml = ["toml"] [[package]] -category = "main" -description = "Provides tag-expression parser for cucumber/behave" name = "cucumber-tag-expressions" +version = "2.0.4" +description = "Provides tag-expression parser for cucumber/behave" +category = "main" optional = false python-versions = ">=2.7" -version = "2.0.4" [package.extras] develop = ["coverage", "pytest (>=3.2)", "pytest-html (>=1.19.0)", "tox (>=2.9)", "invoke", "path.py", "pylint"] [[package]] -category = "main" -description = "A backport of the dataclasses module for Python 3.6" -marker = "python_version >= \"3.6\" and python_version < \"3.7\" or python_version == \"3.6\"" name = "dataclasses" +version = "0.7" +description = "A backport of the dataclasses module for Python 3.6" +category = "main" optional = false python-versions = ">=3.6, <3.7" -version = "0.7" [[package]] -category = "dev" -description = "the modular source code checker: pep8 pyflakes and co" name = "flake8" +version = "3.8.4" +description = "the modular source code checker: pep8 pyflakes and co" +category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" -version = "3.8.4" [package.dependencies] +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} mccabe = ">=0.6.0,<0.7.0" pycodestyle = ">=2.6.0a1,<2.7.0" pyflakes = ">=2.2.0,<2.3.0" -[package.dependencies.importlib-metadata] -python = "<3.8" -version = "*" - [[package]] -category = "dev" -description = "Read metadata from Python packages" -marker = "python_version < \"3.8\"" name = "importlib-metadata" +version = "3.4.0" +description = "Read metadata from Python packages" +category = "dev" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -version = "2.0.0" +python-versions = ">=3.6" [package.dependencies] +typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} zipp = ">=0.5" [package.extras] -docs = ["sphinx", "rst.linker"] -testing = ["packaging", "pep517", "importlib-resources (>=1.3)"] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] [[package]] -category = "dev" -description = "McCabe checker, plugin for flake8" name = "mccabe" +version = "0.6.1" +description = "McCabe checker, plugin for flake8" +category = "dev" optional = false python-versions = "*" -version = "0.6.1" [[package]] -category = "dev" -description = "Utility library for gitignore style pattern matching of file paths." name = "pathspec" +version = "0.8.1" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "0.8.0" [[package]] -category = "main" -description = "A drop-in replacement for pprint that's actually pretty" name = "pprintpp" +version = "0.4.0" +description = "A drop-in replacement for pprint that's actually pretty" +category = "main" optional = false python-versions = "*" -version = "0.4.0" [[package]] -category = "dev" -description = "Python style guide checker" name = "pycodestyle" +version = "2.6.0" +description = "Python style guide checker" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.6.0" [[package]] -category = "dev" -description = "passive checker of Python programs" name = "pyflakes" +version = "2.2.0" +description = "passive checker of Python programs" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.2.0" [[package]] -category = "main" -description = "Pygments is a syntax highlighting package written in Python." name = "pygments" +version = "2.8.0" +description = "Pygments is a syntax highlighting package written in Python." +category = "main" optional = false python-versions = ">=3.5" -version = "2.7.2" [[package]] -category = "dev" -description = "Alternative regular expression module, to replace re." name = "regex" +version = "2020.11.13" +description = "Alternative regular expression module, to replace re." +category = "dev" optional = false python-versions = "*" -version = "2020.10.28" [[package]] -category = "main" -description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" name = "rich" +version = "9.11.0" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +category = "main" optional = false python-versions = ">=3.6,<4.0" -version = "9.1.0" [package.dependencies] colorama = ">=0.4.0,<0.5.0" commonmark = ">=0.9.0,<0.10.0" +dataclasses = {version = ">=0.7,<0.9", markers = "python_version >= \"3.6\" and python_version < \"3.7\""} pygments = ">=2.6.0,<3.0.0" typing-extensions = ">=3.7.4,<4.0.0" -[package.dependencies.dataclasses] -python = ">=3.6,<3.7" -version = ">=0.7,<0.8" - [package.extras] jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"] [[package]] -category = "main" -description = "ANSII Color formatting for output in terminal." name = "termcolor" +version = "1.1.0" +description = "ANSII Color formatting for output in terminal." +category = "main" optional = false python-versions = "*" -version = "1.1.0" [[package]] -category = "main" -description = "Python Library for Tom's Obvious, Minimal Language" name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -version = "0.10.2" [[package]] -category = "dev" -description = "a fork of Python 2 and 3 ast modules with type comment support" name = "typed-ast" +version = "1.4.2" +description = "a fork of Python 2 and 3 ast modules with type comment support" +category = "dev" optional = false python-versions = "*" -version = "1.4.1" [[package]] -category = "main" -description = "Backported and Experimental Type Hints for Python 3.5+" name = "typing-extensions" +version = "3.7.4.3" +description = "Backported and Experimental Type Hints for Python 3.5+" +category = "main" optional = false python-versions = "*" -version = "3.7.4.3" [[package]] -category = "dev" -description = "Backport of pathlib-compatible object wrapper for zip files" -marker = "python_version < \"3.8\"" name = "zipp" +version = "3.4.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "dev" optional = false python-versions = ">=3.6" -version = "3.4.0" [package.extras] docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [metadata] -content-hash = "f708d5230376832af36bdc620a2adecfe4d7aa4d2bfc505a892e48b83144649a" +lock-version = "1.1" python-versions = "^3.6" +content-hash = "f708d5230376832af36bdc620a2adecfe4d7aa4d2bfc505a892e48b83144649a" [metadata.files] appdirs = [ @@ -297,40 +290,55 @@ commonmark = [ {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, ] coverage = [ - {file = "coverage-5.3-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:bd3166bb3b111e76a4f8e2980fa1addf2920a4ca9b2b8ca36a3bc3dedc618270"}, - {file = "coverage-5.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9342dd70a1e151684727c9c91ea003b2fb33523bf19385d4554f7897ca0141d4"}, - {file = "coverage-5.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:63808c30b41f3bbf65e29f7280bf793c79f54fb807057de7e5238ffc7cc4d7b9"}, - {file = "coverage-5.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:4d6a42744139a7fa5b46a264874a781e8694bb32f1d76d8137b68138686f1729"}, - {file = "coverage-5.3-cp27-cp27m-win32.whl", hash = "sha256:86e9f8cd4b0cdd57b4ae71a9c186717daa4c5a99f3238a8723f416256e0b064d"}, - {file = "coverage-5.3-cp27-cp27m-win_amd64.whl", hash = "sha256:7858847f2d84bf6e64c7f66498e851c54de8ea06a6f96a32a1d192d846734418"}, - {file = "coverage-5.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:530cc8aaf11cc2ac7430f3614b04645662ef20c348dce4167c22d99bec3480e9"}, - {file = "coverage-5.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:381ead10b9b9af5f64646cd27107fb27b614ee7040bb1226f9c07ba96625cbb5"}, - {file = "coverage-5.3-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:71b69bd716698fa62cd97137d6f2fdf49f534decb23a2c6fc80813e8b7be6822"}, - {file = "coverage-5.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1d44bb3a652fed01f1f2c10d5477956116e9b391320c94d36c6bf13b088a1097"}, - {file = "coverage-5.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:1c6703094c81fa55b816f5ae542c6ffc625fec769f22b053adb42ad712d086c9"}, - {file = "coverage-5.3-cp35-cp35m-win32.whl", hash = "sha256:cedb2f9e1f990918ea061f28a0f0077a07702e3819602d3507e2ff98c8d20636"}, - {file = "coverage-5.3-cp35-cp35m-win_amd64.whl", hash = "sha256:7f43286f13d91a34fadf61ae252a51a130223c52bfefb50310d5b2deb062cf0f"}, - {file = "coverage-5.3-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:c851b35fc078389bc16b915a0a7c1d5923e12e2c5aeec58c52f4aa8085ac8237"}, - {file = "coverage-5.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:aac1ba0a253e17889550ddb1b60a2063f7474155465577caa2a3b131224cfd54"}, - {file = "coverage-5.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2b31f46bf7b31e6aa690d4c7a3d51bb262438c6dcb0d528adde446531d0d3bb7"}, - {file = "coverage-5.3-cp36-cp36m-win32.whl", hash = "sha256:c5f17ad25d2c1286436761b462e22b5020d83316f8e8fcb5deb2b3151f8f1d3a"}, - {file = "coverage-5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:aef72eae10b5e3116bac6957de1df4d75909fc76d1499a53fb6387434b6bcd8d"}, - {file = "coverage-5.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:e8caf961e1b1a945db76f1b5fa9c91498d15f545ac0ababbe575cfab185d3bd8"}, - {file = "coverage-5.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:29a6272fec10623fcbe158fdf9abc7a5fa032048ac1d8631f14b50fbfc10d17f"}, - {file = "coverage-5.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2d43af2be93ffbad25dd959899b5b809618a496926146ce98ee0b23683f8c51c"}, - {file = "coverage-5.3-cp37-cp37m-win32.whl", hash = "sha256:c3888a051226e676e383de03bf49eb633cd39fc829516e5334e69b8d81aae751"}, - {file = "coverage-5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9669179786254a2e7e57f0ecf224e978471491d660aaca833f845b72a2df3709"}, - {file = "coverage-5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0203acd33d2298e19b57451ebb0bed0ab0c602e5cf5a818591b4918b1f97d516"}, - {file = "coverage-5.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:582ddfbe712025448206a5bc45855d16c2e491c2dd102ee9a2841418ac1c629f"}, - {file = "coverage-5.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:0f313707cdecd5cd3e217fc68c78a960b616604b559e9ea60cc16795c4304259"}, - {file = "coverage-5.3-cp38-cp38-win32.whl", hash = "sha256:78e93cc3571fd928a39c0b26767c986188a4118edc67bc0695bc7a284da22e82"}, - {file = "coverage-5.3-cp38-cp38-win_amd64.whl", hash = "sha256:8f264ba2701b8c9f815b272ad568d555ef98dfe1576802ab3149c3629a9f2221"}, - {file = "coverage-5.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:50691e744714856f03a86df3e2bff847c2acede4c191f9a1da38f088df342978"}, - {file = "coverage-5.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9361de40701666b034c59ad9e317bae95c973b9ff92513dd0eced11c6adf2e21"}, - {file = "coverage-5.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:c1b78fb9700fc961f53386ad2fd86d87091e06ede5d118b8a50dea285a071c24"}, - {file = "coverage-5.3-cp39-cp39-win32.whl", hash = "sha256:cb7df71de0af56000115eafd000b867d1261f786b5eebd88a0ca6360cccfaca7"}, - {file = "coverage-5.3-cp39-cp39-win_amd64.whl", hash = "sha256:47a11bdbd8ada9b7ee628596f9d97fbd3851bd9999d398e9436bd67376dbece7"}, - {file = "coverage-5.3.tar.gz", hash = "sha256:280baa8ec489c4f542f8940f9c4c2181f0306a8ee1a54eceba071a449fb870a0"}, + {file = "coverage-5.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:6d9c88b787638a451f41f97446a1c9fd416e669b4d9717ae4615bd29de1ac135"}, + {file = "coverage-5.4-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:66a5aae8233d766a877c5ef293ec5ab9520929c2578fd2069308a98b7374ea8c"}, + {file = "coverage-5.4-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9754a5c265f991317de2bac0c70a746efc2b695cf4d49f5d2cddeac36544fb44"}, + {file = "coverage-5.4-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:fbb17c0d0822684b7d6c09915677a32319f16ff1115df5ec05bdcaaee40b35f3"}, + {file = "coverage-5.4-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:b7f7421841f8db443855d2854e25914a79a1ff48ae92f70d0a5c2f8907ab98c9"}, + {file = "coverage-5.4-cp27-cp27m-win32.whl", hash = "sha256:4a780807e80479f281d47ee4af2eb2df3e4ccf4723484f77da0bb49d027e40a1"}, + {file = "coverage-5.4-cp27-cp27m-win_amd64.whl", hash = "sha256:87c4b38288f71acd2106f5d94f575bc2136ea2887fdb5dfe18003c881fa6b370"}, + {file = "coverage-5.4-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:c6809ebcbf6c1049002b9ac09c127ae43929042ec1f1dbd8bb1615f7cd9f70a0"}, + {file = "coverage-5.4-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ba7ca81b6d60a9f7a0b4b4e175dcc38e8fef4992673d9d6e6879fd6de00dd9b8"}, + {file = "coverage-5.4-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:89fc12c6371bf963809abc46cced4a01ca4f99cba17be5e7d416ed7ef1245d19"}, + {file = "coverage-5.4-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4a8eb7785bd23565b542b01fb39115a975fefb4a82f23d407503eee2c0106247"}, + {file = "coverage-5.4-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:7e40d3f8eb472c1509b12ac2a7e24158ec352fc8567b77ab02c0db053927e339"}, + {file = "coverage-5.4-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1ccae21a076d3d5f471700f6d30eb486da1626c380b23c70ae32ab823e453337"}, + {file = "coverage-5.4-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:755c56beeacac6a24c8e1074f89f34f4373abce8b662470d3aa719ae304931f3"}, + {file = "coverage-5.4-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:322549b880b2d746a7672bf6ff9ed3f895e9c9f108b714e7360292aa5c5d7cf4"}, + {file = "coverage-5.4-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:60a3307a84ec60578accd35d7f0c71a3a971430ed7eca6567399d2b50ef37b8c"}, + {file = "coverage-5.4-cp35-cp35m-win32.whl", hash = "sha256:1375bb8b88cb050a2d4e0da901001347a44302aeadb8ceb4b6e5aa373b8ea68f"}, + {file = "coverage-5.4-cp35-cp35m-win_amd64.whl", hash = "sha256:16baa799ec09cc0dcb43a10680573269d407c159325972dd7114ee7649e56c66"}, + {file = "coverage-5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2f2cf7a42d4b7654c9a67b9d091ec24374f7c58794858bff632a2039cb15984d"}, + {file = "coverage-5.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:b62046592b44263fa7570f1117d372ae3f310222af1fc1407416f037fb3af21b"}, + {file = "coverage-5.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:812eaf4939ef2284d29653bcfee9665f11f013724f07258928f849a2306ea9f9"}, + {file = "coverage-5.4-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:859f0add98707b182b4867359e12bde806b82483fb12a9ae868a77880fc3b7af"}, + {file = "coverage-5.4-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:04b14e45d6a8e159c9767ae57ecb34563ad93440fc1b26516a89ceb5b33c1ad5"}, + {file = "coverage-5.4-cp36-cp36m-win32.whl", hash = "sha256:ebfa374067af240d079ef97b8064478f3bf71038b78b017eb6ec93ede1b6bcec"}, + {file = "coverage-5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:84df004223fd0550d0ea7a37882e5c889f3c6d45535c639ce9802293b39cd5c9"}, + {file = "coverage-5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1b811662ecf72eb2d08872731636aee6559cae21862c36f74703be727b45df90"}, + {file = "coverage-5.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6b588b5cf51dc0fd1c9e19f622457cc74b7d26fe295432e434525f1c0fae02bc"}, + {file = "coverage-5.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:3fe50f1cac369b02d34ad904dfe0771acc483f82a1b54c5e93632916ba847b37"}, + {file = "coverage-5.4-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:32ab83016c24c5cf3db2943286b85b0a172dae08c58d0f53875235219b676409"}, + {file = "coverage-5.4-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:68fb816a5dd901c6aff352ce49e2a0ffadacdf9b6fae282a69e7a16a02dad5fb"}, + {file = "coverage-5.4-cp37-cp37m-win32.whl", hash = "sha256:a636160680c6e526b84f85d304e2f0bb4e94f8284dd765a1911de9a40450b10a"}, + {file = "coverage-5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:bb32ca14b4d04e172c541c69eec5f385f9a075b38fb22d765d8b0ce3af3a0c22"}, + {file = "coverage-5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4d7165a4e8f41eca6b990c12ee7f44fef3932fac48ca32cecb3a1b2223c21f"}, + {file = "coverage-5.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:a565f48c4aae72d1d3d3f8e8fb7218f5609c964e9c6f68604608e5958b9c60c3"}, + {file = "coverage-5.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:fff1f3a586246110f34dc762098b5afd2de88de507559e63553d7da643053786"}, + {file = "coverage-5.4-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:a839e25f07e428a87d17d857d9935dd743130e77ff46524abb992b962eb2076c"}, + {file = "coverage-5.4-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:6625e52b6f346a283c3d563d1fd8bae8956daafc64bb5bbd2b8f8a07608e3994"}, + {file = "coverage-5.4-cp38-cp38-win32.whl", hash = "sha256:5bee3970617b3d74759b2d2df2f6a327d372f9732f9ccbf03fa591b5f7581e39"}, + {file = "coverage-5.4-cp38-cp38-win_amd64.whl", hash = "sha256:03ed2a641e412e42cc35c244508cf186015c217f0e4d496bf6d7078ebe837ae7"}, + {file = "coverage-5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:14a9f1887591684fb59fdba8feef7123a0da2424b0652e1b58dd5b9a7bb1188c"}, + {file = "coverage-5.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9564ac7eb1652c3701ac691ca72934dd3009997c81266807aef924012df2f4b3"}, + {file = "coverage-5.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:0f48fc7dc82ee14aeaedb986e175a429d24129b7eada1b7e94a864e4f0644dde"}, + {file = "coverage-5.4-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:107d327071061fd4f4a2587d14c389a27e4e5c93c7cba5f1f59987181903902f"}, + {file = "coverage-5.4-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:0cdde51bfcf6b6bd862ee9be324521ec619b20590787d1655d005c3fb175005f"}, + {file = "coverage-5.4-cp39-cp39-win32.whl", hash = "sha256:c67734cff78383a1f23ceba3b3239c7deefc62ac2b05fa6a47bcd565771e5880"}, + {file = "coverage-5.4-cp39-cp39-win_amd64.whl", hash = "sha256:c669b440ce46ae3abe9b2d44a913b5fd86bb19eb14a8701e88e3918902ecd345"}, + {file = "coverage-5.4-pp36-none-any.whl", hash = "sha256:c0ff1c1b4d13e2240821ef23c1efb1f009207cb3f56e16986f713c2b0e7cd37f"}, + {file = "coverage-5.4-pp37-none-any.whl", hash = "sha256:cd601187476c6bed26a0398353212684c427e10a903aeafa6da40c63309d438b"}, + {file = "coverage-5.4.tar.gz", hash = "sha256:6d2e262e5e8da6fa56e774fb8e2643417351427604c2b177f8e8c5f75fc928ca"}, ] cucumber-tag-expressions = [ {file = "cucumber-tag-expressions-2.0.4.tar.gz", hash = "sha256:72197b9330c023ce2643847fd6659c5c000f7f286f5b42cbcfd19adb3be92d30"}, @@ -344,16 +352,16 @@ flake8 = [ {file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"}, ] importlib-metadata = [ - {file = "importlib_metadata-2.0.0-py2.py3-none-any.whl", hash = "sha256:cefa1a2f919b866c5beb7c9f7b0ebb4061f30a8a9bf16d609b000e2dfaceb9c3"}, - {file = "importlib_metadata-2.0.0.tar.gz", hash = "sha256:77a540690e24b0305878c37ffd421785a6f7e53c8b5720d211b211de8d0e95da"}, + {file = "importlib_metadata-3.4.0-py3-none-any.whl", hash = "sha256:ace61d5fc652dc280e7b6b4ff732a9c2d40db2c0f92bc6cb74e07b73d53a1771"}, + {file = "importlib_metadata-3.4.0.tar.gz", hash = "sha256:fa5daa4477a7414ae34e95942e4dd07f62adf589143c875c133c1e53c4eff38d"}, ] mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] pathspec = [ - {file = "pathspec-0.8.0-py2.py3-none-any.whl", hash = "sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0"}, - {file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"}, + {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, + {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"}, ] pprintpp = [ {file = "pprintpp-0.4.0-py2.py3-none-any.whl", hash = "sha256:b6b4dcdd0c0c0d75e4d7b2f21a9e933e5b2ce62b26e1a54537f9651ae5a5c01d"}, @@ -368,57 +376,55 @@ pyflakes = [ {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, ] pygments = [ - {file = "Pygments-2.7.2-py3-none-any.whl", hash = "sha256:88a0bbcd659fcb9573703957c6b9cff9fab7295e6e76db54c9d00ae42df32773"}, - {file = "Pygments-2.7.2.tar.gz", hash = "sha256:381985fcc551eb9d37c52088a32914e00517e57f4a21609f48141ba08e193fa0"}, + {file = "Pygments-2.8.0-py3-none-any.whl", hash = "sha256:b21b072d0ccdf29297a82a2363359d99623597b8a265b8081760e4d0f7153c88"}, + {file = "Pygments-2.8.0.tar.gz", hash = "sha256:37a13ba168a02ac54cc5891a42b1caec333e59b66addb7fa633ea8a6d73445c0"}, ] regex = [ - {file = "regex-2020.10.28-cp27-cp27m-win32.whl", hash = "sha256:4b5a9bcb56cc146c3932c648603b24514447eafa6ce9295234767bf92f69b504"}, - {file = "regex-2020.10.28-cp27-cp27m-win_amd64.whl", hash = "sha256:c13d311a4c4a8d671f5860317eb5f09591fbe8259676b86a85769423b544451e"}, - {file = "regex-2020.10.28-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c454ad88e56e80e44f824ef8366bb7e4c3def12999151fd5c0ea76a18fe9aa3e"}, - {file = "regex-2020.10.28-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:c8a2b7ccff330ae4c460aff36626f911f918555660cc28163417cb84ffb25789"}, - {file = "regex-2020.10.28-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4afa350f162551cf402bfa3cd8302165c8e03e689c897d185f16a167328cc6dd"}, - {file = "regex-2020.10.28-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:b88fa3b8a3469f22b4f13d045d9bd3eda797aa4e406fde0a2644bc92bbdd4bdd"}, - {file = "regex-2020.10.28-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:f43109822df2d3faac7aad79613f5f02e4eab0fc8ad7932d2e70e2a83bd49c26"}, - {file = "regex-2020.10.28-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:de7fd57765398d141949946c84f3590a68cf5887dac3fc52388df0639b01eda4"}, - {file = "regex-2020.10.28-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:9b6305295b6591e45f069d3553c54d50cc47629eb5c218aac99e0f7fafbf90a1"}, - {file = "regex-2020.10.28-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:bd904c0dec29bbd0769887a816657491721d5f545c29e30fd9d7a1a275dc80ab"}, - {file = "regex-2020.10.28-cp36-cp36m-win32.whl", hash = "sha256:8092a5a06ad9a7a247f2a76ace121183dc4e1a84c259cf9c2ce3bbb69fac3582"}, - {file = "regex-2020.10.28-cp36-cp36m-win_amd64.whl", hash = "sha256:49461446b783945597c4076aea3f49aee4b4ce922bd241e4fcf62a3e7c61794c"}, - {file = "regex-2020.10.28-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:297116e79074ec2a2f885d22db00ce6e88b15f75162c5e8b38f66ea734e73c64"}, - {file = "regex-2020.10.28-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:8ca9dca965bd86ea3631b975d63b0693566d3cc347e55786d5514988b6f5b84c"}, - {file = "regex-2020.10.28-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ea37320877d56a7f0a1e6a625d892cf963aa7f570013499f5b8d5ab8402b5625"}, - {file = "regex-2020.10.28-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:3a5f08039eee9ea195a89e180c5762bfb55258bfb9abb61a20d3abee3b37fd12"}, - {file = "regex-2020.10.28-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:cb905f3d2e290a8b8f1579d3984f2cfa7c3a29cc7cba608540ceeed18513f520"}, - {file = "regex-2020.10.28-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:96f99219dddb33e235a37283306834700b63170d7bb2a1ee17e41c6d589c8eb9"}, - {file = "regex-2020.10.28-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:227a8d2e5282c2b8346e7f68aa759e0331a0b4a890b55a5cfbb28bd0261b84c0"}, - {file = "regex-2020.10.28-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:2564def9ce0710d510b1fc7e5178ce2d20f75571f788b5197b3c8134c366f50c"}, - {file = "regex-2020.10.28-cp37-cp37m-win32.whl", hash = "sha256:a62162be05edf64f819925ea88d09d18b09bebf20971b363ce0c24e8b4aa14c0"}, - {file = "regex-2020.10.28-cp37-cp37m-win_amd64.whl", hash = "sha256:03855ee22980c3e4863dc84c42d6d2901133362db5daf4c36b710dd895d78f0a"}, - {file = "regex-2020.10.28-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf4f896c42c63d1f22039ad57de2644c72587756c0cfb3cc3b7530cfe228277f"}, - {file = "regex-2020.10.28-cp38-cp38-manylinux1_i686.whl", hash = "sha256:625116aca6c4b57c56ea3d70369cacc4d62fead4930f8329d242e4fe7a58ce4b"}, - {file = "regex-2020.10.28-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2dc522e25e57e88b4980d2bdd334825dbf6fa55f28a922fc3bfa60cc09e5ef53"}, - {file = "regex-2020.10.28-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:119e0355dbdd4cf593b17f2fc5dbd4aec2b8899d0057e4957ba92f941f704bf5"}, - {file = "regex-2020.10.28-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:cfcf28ed4ce9ced47b9b9670a4f0d3d3c0e4d4779ad4dadb1ad468b097f808aa"}, - {file = "regex-2020.10.28-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:b45bab9f224de276b7bc916f6306b86283f6aa8afe7ed4133423efb42015a898"}, - {file = "regex-2020.10.28-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:52e83a5f28acd621ba8e71c2b816f6541af7144b69cc5859d17da76c436a5427"}, - {file = "regex-2020.10.28-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:aacc8623ffe7999a97935eeabbd24b1ae701d08ea8f874a6ff050e93c3e658cf"}, - {file = "regex-2020.10.28-cp38-cp38-win32.whl", hash = "sha256:06b52815d4ad38d6524666e0d50fe9173533c9cc145a5779b89733284e6f688f"}, - {file = "regex-2020.10.28-cp38-cp38-win_amd64.whl", hash = "sha256:c3466a84fce42c2016113101018a9981804097bacbab029c2d5b4fcb224b89de"}, - {file = "regex-2020.10.28-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:127a9e0c0d91af572fbb9e56d00a504dbd4c65e574ddda3d45b55722462210de"}, - {file = "regex-2020.10.28-cp39-cp39-manylinux1_i686.whl", hash = "sha256:c2c6c56ee97485a127555c9595c069201b5161de9d05495fbe2132b5ac104786"}, - {file = "regex-2020.10.28-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:1ec66700a10e3c75f1f92cbde36cca0d3aaee4c73dfa26699495a3a30b09093c"}, - {file = "regex-2020.10.28-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:11116d424734fe356d8777f89d625f0df783251ada95d6261b4c36ad27a394bb"}, - {file = "regex-2020.10.28-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f1fce1e4929157b2afeb4bb7069204d4370bab9f4fc03ca1fbec8bd601f8c87d"}, - {file = "regex-2020.10.28-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:3dfca201fa6b326239e1bccb00b915e058707028809b8ecc0cf6819ad233a740"}, - {file = "regex-2020.10.28-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:b8a686a6c98872007aa41fdbb2e86dc03b287d951ff4a7f1da77fb7f14113e4d"}, - {file = "regex-2020.10.28-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:c32c91a0f1ac779cbd73e62430de3d3502bbc45ffe5bb6c376015acfa848144b"}, - {file = "regex-2020.10.28-cp39-cp39-win32.whl", hash = "sha256:832339223b9ce56b7b15168e691ae654d345ac1635eeb367ade9ecfe0e66bee0"}, - {file = "regex-2020.10.28-cp39-cp39-win_amd64.whl", hash = "sha256:654c1635f2313d0843028487db2191530bca45af61ca85d0b16555c399625b0e"}, - {file = "regex-2020.10.28.tar.gz", hash = "sha256:dd3e6547ecf842a29cf25123fbf8d2461c53c8d37aa20d87ecee130c89b7079b"}, + {file = "regex-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6"}, + {file = "regex-2020.11.13-cp36-cp36m-win32.whl", hash = "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e"}, + {file = "regex-2020.11.13-cp36-cp36m-win_amd64.whl", hash = "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884"}, + {file = "regex-2020.11.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538"}, + {file = "regex-2020.11.13-cp37-cp37m-win32.whl", hash = "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4"}, + {file = "regex-2020.11.13-cp37-cp37m-win_amd64.whl", hash = "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444"}, + {file = "regex-2020.11.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b"}, + {file = "regex-2020.11.13-cp38-cp38-win32.whl", hash = "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c"}, + {file = "regex-2020.11.13-cp38-cp38-win_amd64.whl", hash = "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683"}, + {file = "regex-2020.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c"}, + {file = "regex-2020.11.13-cp39-cp39-win32.whl", hash = "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"}, + {file = "regex-2020.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d"}, + {file = "regex-2020.11.13.tar.gz", hash = "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562"}, ] rich = [ - {file = "rich-9.1.0-py3-none-any.whl", hash = "sha256:5dd934a0f8953b59d9a5d8d58864012174f0b5ad2de687fd04f4df195f7f7066"}, - {file = "rich-9.1.0.tar.gz", hash = "sha256:05f1cf4dc191c483867b098d8572546de266440d61911d8270069023e325d14a"}, + {file = "rich-9.11.0-py3-none-any.whl", hash = "sha256:a8ee22199562278d2f78148cacb2f9460ccac362cd4a40f705505b41daae60e0"}, + {file = "rich-9.11.0.tar.gz", hash = "sha256:f8f08fdac6bd67dc2dd7fe976da702d748487aa9eb5d050c48b2321bc67ed659"}, ] termcolor = [ {file = "termcolor-1.1.0.tar.gz", hash = "sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b"}, @@ -428,27 +434,36 @@ toml = [ {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] typed-ast = [ - {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"}, - {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb"}, - {file = "typed_ast-1.4.1-cp35-cp35m-win32.whl", hash = "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919"}, - {file = "typed_ast-1.4.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01"}, - {file = "typed_ast-1.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75"}, - {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652"}, - {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"}, - {file = "typed_ast-1.4.1-cp36-cp36m-win32.whl", hash = "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1"}, - {file = "typed_ast-1.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa"}, - {file = "typed_ast-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614"}, - {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41"}, - {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b"}, - {file = "typed_ast-1.4.1-cp37-cp37m-win32.whl", hash = "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe"}, - {file = "typed_ast-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355"}, - {file = "typed_ast-1.4.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6"}, - {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907"}, - {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d"}, - {file = "typed_ast-1.4.1-cp38-cp38-win32.whl", hash = "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c"}, - {file = "typed_ast-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4"}, - {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"}, - {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, + {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70"}, + {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487"}, + {file = "typed_ast-1.4.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412"}, + {file = "typed_ast-1.4.2-cp35-cp35m-win32.whl", hash = "sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400"}, + {file = "typed_ast-1.4.2-cp35-cp35m-win_amd64.whl", hash = "sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606"}, + {file = "typed_ast-1.4.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64"}, + {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07"}, + {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc"}, + {file = "typed_ast-1.4.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a"}, + {file = "typed_ast-1.4.2-cp36-cp36m-win32.whl", hash = "sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151"}, + {file = "typed_ast-1.4.2-cp36-cp36m-win_amd64.whl", hash = "sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3"}, + {file = "typed_ast-1.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41"}, + {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f"}, + {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581"}, + {file = "typed_ast-1.4.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37"}, + {file = "typed_ast-1.4.2-cp37-cp37m-win32.whl", hash = "sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd"}, + {file = "typed_ast-1.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496"}, + {file = "typed_ast-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc"}, + {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10"}, + {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea"}, + {file = "typed_ast-1.4.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787"}, + {file = "typed_ast-1.4.2-cp38-cp38-win32.whl", hash = "sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2"}, + {file = "typed_ast-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937"}, + {file = "typed_ast-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1"}, + {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6"}, + {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166"}, + {file = "typed_ast-1.4.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d"}, + {file = "typed_ast-1.4.2-cp39-cp39-win32.whl", hash = "sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b"}, + {file = "typed_ast-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440"}, + {file = "typed_ast-1.4.2.tar.gz", hash = "sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a"}, ] typing-extensions = [ {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, diff --git a/pyproject.toml b/pyproject.toml index 245c95ac..86746e30 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ path = ["ward/tests"] [tool.poetry] name = "ward" -version = "0.49.0b0" +version = "0.50.0b0" description = "A modern Python testing framework" exclude = ["ward/tests"] authors = ["Darren Burns "] diff --git a/ward/terminal.py b/ward/terminal.py index 0a391105..914949b0 100644 --- a/ward/terminal.py +++ b/ward/terminal.py @@ -1,10 +1,7 @@ import inspect -import itertools -import math import os import platform import statistics -import sys from dataclasses import dataclass from enum import Enum from pathlib import Path @@ -20,6 +17,9 @@ Collection, ) +import itertools +import math +import sys from rich.console import Console, ConsoleOptions, RenderResult, RenderGroup from rich.highlighter import NullHighlighter from rich.markdown import Markdown @@ -161,7 +161,7 @@ def output_test_result_line(test_result: TestResult): grid.add_column(justify="center", style=test_style) grid.add_row( *common_columns, - Padding(Padding(reason, pad=(0, 1, 0, 1)), pad=(0, 1, 0, 1)), + Padding(reason, pad=(0, 1, 0, 1)), ) else: grid.add_row(*common_columns) @@ -358,7 +358,7 @@ def output_header(self, time_to_collect): path = self.config_path.name console.print(f"Loaded config from [b]{path}[/b].") console.print( - f"Collected [b]{self.suite.num_tests}[/b] tests " + f"Found [b]{self.suite.num_tests}[/b] tests " f"and [b]{len(_DEFINED_FIXTURES)}[/b] fixtures " f"in [b]{time_to_collect:.2f}[/b] seconds." ) @@ -445,7 +445,9 @@ def get_terminal_size() -> TerminalSize: class SimpleTestResultWrite(TestResultWriterBase): def output_why_test_failed_header(self, test_result: TestResult): test = test_result.test - console.print(Rule(title=Text(test.description, style="fail.header"), style="fail.textonly")) + console.print( + Padding(Rule(title=Text(test.description, style="fail.header"), style="fail.textonly"), pad=(1, 0, 0, 0)), + ) def output_why_test_failed(self, test_result: TestResult): err = test_result.error @@ -476,13 +478,13 @@ def print_failure_equals(self, err: TestFailure): width=self.terminal_size.width - 24, show_symbols=self.show_diff_symbols, ) - print(indent(diff, DOUBLE_INDENT)) + console.print(Padding(diff, pad=(0, 0, 1, 4))) def print_traceback(self, err): trace = getattr(err, "__traceback__", "") if trace: tb = Traceback.from_exception(err.__class__, err, trace, theme="ansi_dark") - console.print(tb) + console.print(Padding(tb, pad=(1, 0, 0, 0))) else: print(str(err)) @@ -519,7 +521,7 @@ def output_test_result_summary( else: result_style = "fail.textonly" - result_summary_panel = Panel(result_table, title="[b white]Results[/b white]", style="none", expand=False, + result_summary_panel = Panel(result_table, title="[b default]Results[/b default]", style="none", expand=False, border_style=result_style) console.print(result_summary_panel) @@ -527,50 +529,34 @@ def output_test_result_summary( Rule(f"[b]{exit_code.clean_name}[/b] in [b]{time_taken:.2f}[/b] seconds", style=result_style) ) - def _output_slowest_tests(self, test_results: List[TestResult], num_tests: int): - test_results = sorted( - test_results, key=lambda r: r.test.timer.duration, reverse=True - ) - heading = f"{colored('Longest Running Tests:', color='cyan', attrs=['bold'])}\n" - print(indent(heading, INDENT)) - - for result in test_results[:num_tests]: - test_id = format_test_id(result) - message = f"{result.test.timer.duration:.2f} sec {test_id} {result.test.description} " - print(indent(message, DOUBLE_INDENT)) - print() - def output_captured_stderr(self, test_result: TestResult): if test_result.captured_stderr: captured_stderr_lines = test_result.captured_stderr.split("\n") - print( - indent( - colored(f"Captured stderr:\n", color="cyan", attrs=["bold"]), INDENT + console.print( + Padding( + Text(f"Captured stderr"), + pad=(0, 0, 1, 2) ) ) for line in captured_stderr_lines: - print(indent(line, DOUBLE_INDENT)) - print() + console.print(Padding(line, pad=(0, 0, 0, 4))) def output_captured_stdout(self, test_result: TestResult): if test_result.captured_stdout: captured_stdout_lines = test_result.captured_stdout.split("\n") - print( - indent( - colored(f"Captured stdout:\n", color="cyan", attrs=["bold"]), INDENT + console.print( + Padding( + Text(f"Captured stdout"), + pad=(0, 0, 1, 2) ) ) for line in captured_stdout_lines: - print(indent(line, DOUBLE_INDENT)) + console.print(Padding(line, pad=(0, 0, 0, 4))) def output_test_failed_location(self, test_result: TestResult): if isinstance(test_result.error, TestFailure) or isinstance( test_result.error, AssertionError ): - # print( - # indent(colored("Location:", color="cyan", attrs=["bold"]), INDENT), - # f"{test_result.test.path.relative_to(Path.cwd())}:{test_result.error.error_line}", - # ) console.print( Padding( Text(f"Failed at {test_result.test.path.relative_to(Path.cwd())}:{test_result.error.error_line}"), diff --git a/ward/tests/test_util.py b/ward/tests/test_util.py index f7f935cf..8174ebe8 100644 --- a/ward/tests/test_util.py +++ b/ward/tests/test_util.py @@ -1,9 +1,9 @@ import os from pathlib import Path -from ward.tests.utilities import make_project from ward import test, using, fixture -from ward.testing import each +from ward.testing import each, xfail, skip +from ward.tests.utilities import make_project from ward.util import ( truncate, find_project_root, @@ -18,7 +18,7 @@ def s(): @test("truncate('{input}', num_chars={num_chars}) returns '{expected}'") def _( - input=s, num_chars=each(20, 11, 10, 5), expected=each(s, s, "hello w...", "he...") + input=s, num_chars=each(20, 11, 10, 5), expected=each(s, s, "hello w...", "he...") ): result = truncate(input, num_chars) assert result == expected @@ -66,12 +66,12 @@ def square(x): @test("group {items!r} by {key} returns {result}") def _( - items=each(range(5), "echolocation", [-2, 3, 4, -3, 2, 3]), - key=each(is_even, is_vowel, square), - result=each( - {True: [0, 2, 4], False: [1, 3]}, - {True: ["e", "o", "o", "a", "i", "o"], False: ["c", "h", "l", "c", "t", "n"]}, - {4: [-2, 2], 9: [3, -3, 3], 16: [4]}, - ), + items=each(range(5), "echolocation", [-2, 3, 4, -3, 2, 3]), + key=each(is_even, is_vowel, square), + result=each( + {True: [0, 2, 4], False: [1, 3]}, + {True: ["e", "o", "o", "a", "i", "o"], False: ["c", "h", "l", "c", "t", "n"]}, + {4: [-2, 2], 9: [3, -3, 3], 16: [4]}, + ), ): assert group_by(items, key) == result From f05c953caf494d1fde657f10de5d86ccdf11e8b0 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Fri, 19 Feb 2021 12:56:09 +0000 Subject: [PATCH 09/14] Move to snok/install-poetry action --- .github/workflows/build.yml | 5 +-- .github/workflows/pullrequest.yml | 5 +-- .github/workflows/release.yml | 2 +- ward/terminal.py | 13 ++++-- ward/tests/test_util.py | 66 +++++++++++++++++++++++++++++++ 5 files changed, 78 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ee0bd49d..ed302d52 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,10 +23,7 @@ jobs: uses: actions/setup-python@v1 with: python-version: ${{ matrix.python-version }} - - uses: dschep/install-poetry-action@v1.3 - with: - version: 1.0.3 - create_virtualenvs: true + - uses: snok/install-poetry@v1.1.1 - name: Run tests with Ward run: | poetry install diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 5b80b2c1..0c4e3b45 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -19,10 +19,7 @@ jobs: uses: actions/setup-python@v1 with: python-version: ${{ matrix.python-version }} - - uses: dschep/install-poetry-action@v1.3 - with: - version: 1.0.3 - create_virtualenvs: true + - uses: snok/install-poetry@v1.1.1 - name: Run tests with Ward run: | poetry install diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 01926efe..20ae5479 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ jobs: steps: - uses: actions/checkout@v1 - uses: actions/setup-python@v1 - - uses: dschep/install-poetry-action@v1.3 + - uses: snok/install-poetry@v1.1.1 with: version: 1.0.3 create_virtualenvs: true diff --git a/ward/terminal.py b/ward/terminal.py index 914949b0..26dd3739 100644 --- a/ward/terminal.py +++ b/ward/terminal.py @@ -483,10 +483,13 @@ def print_failure_equals(self, err: TestFailure): def print_traceback(self, err): trace = getattr(err, "__traceback__", "") if trace: - tb = Traceback.from_exception(err.__class__, err, trace, theme="ansi_dark") - console.print(Padding(tb, pad=(1, 0, 0, 0))) + # The first frame contains library internal code which is not + # relevant to end users, so skip over it. + trace = trace.tb_next + tb = Traceback.from_exception(err.__class__, err, trace, show_locals=True) + console.print(Padding(tb, pad=(0, 4, 1, 4))) else: - print(str(err)) + console.print(str(err)) def output_test_result_summary( self, test_results: List[TestResult], time_taken: float, show_slowest: int @@ -540,6 +543,7 @@ def output_captured_stderr(self, test_result: TestResult): ) for line in captured_stderr_lines: console.print(Padding(line, pad=(0, 0, 0, 4))) + console.print() def output_captured_stdout(self, test_result: TestResult): if test_result.captured_stdout: @@ -552,6 +556,7 @@ def output_captured_stdout(self, test_result: TestResult): ) for line in captured_stdout_lines: console.print(Padding(line, pad=(0, 0, 0, 4))) + console.print() def output_test_failed_location(self, test_result: TestResult): if isinstance(test_result.error, TestFailure) or isinstance( @@ -560,7 +565,7 @@ def output_test_failed_location(self, test_result: TestResult): console.print( Padding( Text(f"Failed at {test_result.test.path.relative_to(Path.cwd())}:{test_result.error.error_line}"), - pad=(1, 0, 0, 2) + pad=(1, 0, 1, 2) ) ) diff --git a/ward/tests/test_util.py b/ward/tests/test_util.py index 8174ebe8..22660cad 100644 --- a/ward/tests/test_util.py +++ b/ward/tests/test_util.py @@ -1,4 +1,5 @@ import os +import sys from pathlib import Path from ward import test, using, fixture @@ -75,3 +76,68 @@ def _( ), ): assert group_by(items, key) == result + + +def is_even(n): + return n % 2 == 0 + + +def is_vowel(char): + return char in "aeiou" + + +def square(x): + return x ** 2 + + +def throws_ex(): + raise ZeroDivisionError("oh no") + + +def calls_throws_ex(): + throws_ex() + + +@test("`group` returns expected result for regular function") +def _(items=range(5), key=is_even): + expected = {True: [0, 2, 4], False: [1, 3]} + assert group_by(items, key) == expected + + +@skip +@test("`group` returns empty dict on `None` items") +def _(items=range(5), key=is_even): + expected = {True: [0, 2, 4], False: [1, 3]} + assert group_by(items, key) == expected + + +@xfail("Known issue, see Jira XY-1234") +@test("`group` returns empty dict on `None` key") +def _(items=range(5), key=is_even): + expected = {True: [0, 2, 4], False: [1, 2]} + assert group_by(items, key) == expected + + +@xfail +@test("descriptions **support** `Markdown` *syntax*") +def _(items=range(5), key=is_even): + expected = {True: [0, 2, 4], False: [1, 3]} + assert group_by(items, key) == expected + + +@test("this test throws an exception") +def _(): + calls_throws_ex() + + +@test("this test will fail due to non-equal strings") +def _(): + print("hello world") + assert "abcdef" == "abdefg" + + +@test("this test prints to std_out") +def _(): + print("hello i am on stdout") + sys.stderr.write("abcdef") + assert False From 4c69d3234e4fdb58f41a21f64c013154b0b7d176 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Fri, 19 Feb 2021 12:58:55 +0000 Subject: [PATCH 10/14] Remove some meta test cases --- ward/tests/test_util.py | 65 ----------------------------------------- 1 file changed, 65 deletions(-) diff --git a/ward/tests/test_util.py b/ward/tests/test_util.py index 22660cad..a9765feb 100644 --- a/ward/tests/test_util.py +++ b/ward/tests/test_util.py @@ -76,68 +76,3 @@ def _( ), ): assert group_by(items, key) == result - - -def is_even(n): - return n % 2 == 0 - - -def is_vowel(char): - return char in "aeiou" - - -def square(x): - return x ** 2 - - -def throws_ex(): - raise ZeroDivisionError("oh no") - - -def calls_throws_ex(): - throws_ex() - - -@test("`group` returns expected result for regular function") -def _(items=range(5), key=is_even): - expected = {True: [0, 2, 4], False: [1, 3]} - assert group_by(items, key) == expected - - -@skip -@test("`group` returns empty dict on `None` items") -def _(items=range(5), key=is_even): - expected = {True: [0, 2, 4], False: [1, 3]} - assert group_by(items, key) == expected - - -@xfail("Known issue, see Jira XY-1234") -@test("`group` returns empty dict on `None` key") -def _(items=range(5), key=is_even): - expected = {True: [0, 2, 4], False: [1, 2]} - assert group_by(items, key) == expected - - -@xfail -@test("descriptions **support** `Markdown` *syntax*") -def _(items=range(5), key=is_even): - expected = {True: [0, 2, 4], False: [1, 3]} - assert group_by(items, key) == expected - - -@test("this test throws an exception") -def _(): - calls_throws_ex() - - -@test("this test will fail due to non-equal strings") -def _(): - print("hello world") - assert "abcdef" == "abdefg" - - -@test("this test prints to std_out") -def _(): - print("hello i am on stdout") - sys.stderr.write("abcdef") - assert False From e559e13abc6abdd84bd1e64a1781660705560fce Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Fri, 19 Feb 2021 13:06:27 +0000 Subject: [PATCH 11/14] Activate venv in GitHub action --- .github/workflows/build.yml | 8 ++++++++ .github/workflows/pullrequest.yml | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ed302d52..8a854db7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,6 +24,14 @@ jobs: with: python-version: ${{ matrix.python-version }} - uses: snok/install-poetry@v1.1.1 + - run: | + source .venv/scripts/activate + pytest --version + if: runner.os == 'Windows' + - run: | + source .venv/bin/activate + pytest --version + if: runner.os != 'Windows' - name: Run tests with Ward run: | poetry install diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 0c4e3b45..9b1c46f5 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -12,6 +12,9 @@ jobs: matrix: os: [ubuntu-latest, macOS-latest, windows-latest] python-version: [3.6, 3.7, 3.8] + defaults: + run: + shell: bash steps: - uses: actions/checkout@v1 @@ -20,6 +23,14 @@ jobs: with: python-version: ${{ matrix.python-version }} - uses: snok/install-poetry@v1.1.1 + - run: | + source .venv/scripts/activate + pytest --version + if: runner.os == 'Windows' + - run: | + source .venv/bin/activate + pytest --version + if: runner.os != 'Windows' - name: Run tests with Ward run: | poetry install From 7f28fc7f75a4254662fa142d4321b652b4205e82 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Fri, 19 Feb 2021 13:19:43 +0000 Subject: [PATCH 12/14] Further GitHub actions changes --- .github/workflows/build.yml | 73 +++++++++++++++++++------------ .github/workflows/pullrequest.yml | 68 +++++++++++++++++----------- 2 files changed, 88 insertions(+), 53 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8a854db7..263ea065 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,8 +3,8 @@ name: Build on: push: branches: - - master - - release/* + - master + - release/* jobs: test: @@ -14,33 +14,52 @@ jobs: max-parallel: 9 fail-fast: false matrix: - os: [ubuntu-latest, macOS-latest, windows-latest] - python-version: [3.6, 3.7, 3.8] + os: [ ubuntu-latest, macOS-latest, windows-latest ] + python-version: [ 3.6, 3.7, 3.8, 3.9 ] + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v1 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 - with: - python-version: ${{ matrix.python-version }} - - uses: snok/install-poetry@v1.1.1 - - run: | - source .venv/scripts/activate - pytest --version - if: runner.os == 'Windows' - - run: | - source .venv/bin/activate - pytest --version - if: runner.os != 'Windows' - - name: Run tests with Ward - run: | - poetry install - poetry run coverage run -m ward - poetry run coverage xml -i - - name: Upload coverage report to codecov - run: | - bash <(curl -s https://codecov.io/bash) -f coverage.xml - shell: bash + + - uses: actions/checkout@v2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - uses: snok/install-poetry@v1.1.1 + with: + virtualenvs-create: true + vitualenvs-in-project: true + + - name: Load cached venv + id: cached-pip-wheels + uses: actions/cache@v2 + with: + path: ~/.cache + key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }} + + - name: Install dependencies + run: poetry install --no-interaction + + - run: | + source .venv/scripts/activate + if: runner.os == 'Windows' + - run: | + source .venv/bin/activate + if: runner.os != 'Windows' + + - name: Run tests with Ward + run: | + coverage run -m ward + coverage xml -i + + - name: Upload coverage report to codecov + run: | + bash <(curl -s https://codecov.io/bash) -f coverage.xml + shell: bash # TODO: Update to use the Makefile and actually enforce this. # - name: Lint with flake8 (CONFIG OUTDATED) diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 9b1c46f5..ae5d5374 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -1,6 +1,6 @@ name: Ward Pull Requests -on: [pull_request] +on: [ pull_request ] jobs: test: @@ -10,33 +10,49 @@ jobs: max-parallel: 9 fail-fast: false matrix: - os: [ubuntu-latest, macOS-latest, windows-latest] - python-version: [3.6, 3.7, 3.8] + os: [ ubuntu-latest, macOS-latest, windows-latest ] + python-version: [ 3.6, 3.7, 3.8, 3.9 ] defaults: run: shell: bash steps: - - uses: actions/checkout@v1 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 - with: - python-version: ${{ matrix.python-version }} - - uses: snok/install-poetry@v1.1.1 - - run: | - source .venv/scripts/activate - pytest --version - if: runner.os == 'Windows' - - run: | - source .venv/bin/activate - pytest --version - if: runner.os != 'Windows' - - name: Run tests with Ward - run: | - poetry install - poetry run coverage run -m ward - poetry run coverage xml -i - - name: Upload coverage report to codecov - run: | - bash <(curl -s https://codecov.io/bash) -f coverage.xml - shell: bash + + - uses: actions/checkout@v2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - uses: snok/install-poetry@v1.1.1 + with: + virtualenvs-create: true + vitualenvs-in-project: true + + - name: Load cached venv + id: cached-pip-wheels + uses: actions/cache@v2 + with: + path: ~/.cache + key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }} + + - name: Install dependencies + run: poetry install --no-interaction + + - run: | + source .venv/scripts/activate + if: runner.os == 'Windows' + - run: | + source .venv/bin/activate + if: runner.os != 'Windows' + + - name: Run tests with Ward + run: | + coverage run -m ward + coverage xml -i + + - name: Upload coverage report to codecov + run: | + bash <(curl -s https://codecov.io/bash) -f coverage.xml + shell: bash \ No newline at end of file From 04f288071d5aa4b0dca4de866f7f879654db4bbb Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Fri, 19 Feb 2021 13:25:02 +0000 Subject: [PATCH 13/14] Further GitHub actions changes --- .github/workflows/build.yml | 19 ++----------------- .github/workflows/pullrequest.yml | 19 ++----------------- 2 files changed, 4 insertions(+), 34 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 263ea065..de0c9036 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,29 +32,14 @@ jobs: - uses: snok/install-poetry@v1.1.1 with: virtualenvs-create: true - vitualenvs-in-project: true - - - name: Load cached venv - id: cached-pip-wheels - uses: actions/cache@v2 - with: - path: ~/.cache - key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }} - name: Install dependencies run: poetry install --no-interaction - - run: | - source .venv/scripts/activate - if: runner.os == 'Windows' - - run: | - source .venv/bin/activate - if: runner.os != 'Windows' - - name: Run tests with Ward run: | - coverage run -m ward - coverage xml -i + poetry run coverage run -m ward + poetry run coverage xml -i - name: Upload coverage report to codecov run: | diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index ae5d5374..dbf5c0f3 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -28,29 +28,14 @@ jobs: - uses: snok/install-poetry@v1.1.1 with: virtualenvs-create: true - vitualenvs-in-project: true - - - name: Load cached venv - id: cached-pip-wheels - uses: actions/cache@v2 - with: - path: ~/.cache - key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }} - name: Install dependencies run: poetry install --no-interaction - - run: | - source .venv/scripts/activate - if: runner.os == 'Windows' - - run: | - source .venv/bin/activate - if: runner.os != 'Windows' - - name: Run tests with Ward run: | - coverage run -m ward - coverage xml -i + poetry run coverage run -m ward + poetry run coverage xml -i - name: Upload coverage report to codecov run: | From 1a2f7d61c4fa50c7e0a47f7933417eb8dd794f3e Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Fri, 19 Feb 2021 13:33:43 +0000 Subject: [PATCH 14/14] Prepare as 0.49.0b0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 86746e30..245c95ac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ path = ["ward/tests"] [tool.poetry] name = "ward" -version = "0.50.0b0" +version = "0.49.0b0" description = "A modern Python testing framework" exclude = ["ward/tests"] authors = ["Darren Burns "]