diff --git a/poetry.lock b/poetry.lock index 09294f34..5eecad8a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -94,7 +94,7 @@ test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"] [[package]] name = "coverage" -version = "5.4" +version = "5.5" description = "Code coverage measurement for Python" category = "dev" optional = false @@ -124,21 +124,21 @@ python-versions = ">=3.6, <3.7" [[package]] name = "flake8" -version = "3.8.4" +version = "3.9.0" 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" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [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" +pycodestyle = ">=2.7.0,<2.8.0" +pyflakes = ">=2.3.0,<2.4.0" [[package]] name = "importlib-metadata" -version = "3.4.0" +version = "3.7.3" description = "Read metadata from Python packages" category = "dev" optional = false @@ -200,7 +200,7 @@ python-versions = "*" [[package]] name = "pycodestyle" -version = "2.6.0" +version = "2.7.0" description = "Python style guide checker" category = "dev" optional = false @@ -208,7 +208,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pyflakes" -version = "2.2.0" +version = "2.3.0" description = "passive checker of Python programs" category = "dev" optional = false @@ -216,7 +216,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pygments" -version = "2.8.0" +version = "2.8.1" description = "Pygments is a syntax highlighting package written in Python." category = "main" optional = false @@ -224,7 +224,7 @@ python-versions = ">=3.5" [[package]] name = "regex" -version = "2020.11.13" +version = "2021.3.17" description = "Alternative regular expression module, to replace re." category = "dev" optional = false @@ -232,7 +232,7 @@ python-versions = "*" [[package]] name = "rich" -version = "9.11.0" +version = "9.13.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" category = "main" optional = false @@ -298,15 +298,15 @@ python-versions = "*" [[package]] name = "zipp" -version = "3.4.0" +version = "3.4.1" description = "Backport of pathlib-compatible object wrapper for zip files" category = "dev" optional = false python-versions = ">=3.6" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -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"] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [metadata] lock-version = "1.1" @@ -345,55 +345,58 @@ commonmark = [ {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, ] coverage = [ - {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"}, + {file = "coverage-5.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf"}, + {file = "coverage-5.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b"}, + {file = "coverage-5.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:c2723d347ab06e7ddad1a58b2a821218239249a9e4365eaff6649d31180c1669"}, + {file = "coverage-5.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:900fbf7759501bc7807fd6638c947d7a831fc9fdf742dc10f02956ff7220fa90"}, + {file = "coverage-5.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:004d1880bed2d97151facef49f08e255a20ceb6f9432df75f4eef018fdd5a78c"}, + {file = "coverage-5.5-cp27-cp27m-win32.whl", hash = "sha256:06191eb60f8d8a5bc046f3799f8a07a2d7aefb9504b0209aff0b47298333302a"}, + {file = "coverage-5.5-cp27-cp27m-win_amd64.whl", hash = "sha256:7501140f755b725495941b43347ba8a2777407fc7f250d4f5a7d2a1050ba8e82"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:372da284cfd642d8e08ef606917846fa2ee350f64994bebfbd3afb0040436905"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:8963a499849a1fc54b35b1c9f162f4108017b2e6db2c46c1bed93a72262ed083"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:869a64f53488f40fa5b5b9dcb9e9b2962a66a87dab37790f3fcfb5144b996ef5"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4a7697d8cb0f27399b0e393c0b90f0f1e40c82023ea4d45d22bce7032a5d7b81"}, + {file = "coverage-5.5-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:8d0a0725ad7c1a0bcd8d1b437e191107d457e2ec1084b9f190630a4fb1af78e6"}, + {file = "coverage-5.5-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:51cb9476a3987c8967ebab3f0fe144819781fca264f57f89760037a2ea191cb0"}, + {file = "coverage-5.5-cp310-cp310-win_amd64.whl", hash = "sha256:c0891a6a97b09c1f3e073a890514d5012eb256845c451bd48f7968ef939bf4ae"}, + {file = "coverage-5.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:3487286bc29a5aa4b93a072e9592f22254291ce96a9fbc5251f566b6b7343cdb"}, + {file = "coverage-5.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:deee1077aae10d8fa88cb02c845cfba9b62c55e1183f52f6ae6a2df6a2187160"}, + {file = "coverage-5.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f11642dddbb0253cc8853254301b51390ba0081750a8ac03f20ea8103f0c56b6"}, + {file = "coverage-5.5-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:6c90e11318f0d3c436a42409f2749ee1a115cd8b067d7f14c148f1ce5574d701"}, + {file = "coverage-5.5-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:30c77c1dc9f253283e34c27935fded5015f7d1abe83bc7821680ac444eaf7793"}, + {file = "coverage-5.5-cp35-cp35m-win32.whl", hash = "sha256:9a1ef3b66e38ef8618ce5fdc7bea3d9f45f3624e2a66295eea5e57966c85909e"}, + {file = "coverage-5.5-cp35-cp35m-win_amd64.whl", hash = "sha256:972c85d205b51e30e59525694670de6a8a89691186012535f9d7dbaa230e42c3"}, + {file = "coverage-5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:af0e781009aaf59e25c5a678122391cb0f345ac0ec272c7961dc5455e1c40066"}, + {file = "coverage-5.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:74d881fc777ebb11c63736622b60cb9e4aee5cace591ce274fb69e582a12a61a"}, + {file = "coverage-5.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:92b017ce34b68a7d67bd6d117e6d443a9bf63a2ecf8567bb3d8c6c7bc5014465"}, + {file = "coverage-5.5-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d636598c8305e1f90b439dbf4f66437de4a5e3c31fdf47ad29542478c8508bbb"}, + {file = "coverage-5.5-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:41179b8a845742d1eb60449bdb2992196e211341818565abded11cfa90efb821"}, + {file = "coverage-5.5-cp36-cp36m-win32.whl", hash = "sha256:040af6c32813fa3eae5305d53f18875bedd079960822ef8ec067a66dd8afcd45"}, + {file = "coverage-5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:5fec2d43a2cc6965edc0bb9e83e1e4b557f76f843a77a2496cbe719583ce8184"}, + {file = "coverage-5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:18ba8bbede96a2c3dde7b868de9dcbd55670690af0988713f0603f037848418a"}, + {file = "coverage-5.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2910f4d36a6a9b4214bb7038d537f015346f413a975d57ca6b43bf23d6563b53"}, + {file = "coverage-5.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:f0b278ce10936db1a37e6954e15a3730bea96a0997c26d7fee88e6c396c2086d"}, + {file = "coverage-5.5-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:796c9c3c79747146ebd278dbe1e5c5c05dd6b10cc3bcb8389dfdf844f3ead638"}, + {file = "coverage-5.5-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:53194af30d5bad77fcba80e23a1441c71abfb3e01192034f8246e0d8f99528f3"}, + {file = "coverage-5.5-cp37-cp37m-win32.whl", hash = "sha256:184a47bbe0aa6400ed2d41d8e9ed868b8205046518c52464fde713ea06e3a74a"}, + {file = "coverage-5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:2949cad1c5208b8298d5686d5a85b66aae46d73eec2c3e08c817dd3513e5848a"}, + {file = "coverage-5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:217658ec7187497e3f3ebd901afdca1af062b42cfe3e0dafea4cced3983739f6"}, + {file = "coverage-5.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1aa846f56c3d49205c952d8318e76ccc2ae23303351d9270ab220004c580cfe2"}, + {file = "coverage-5.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:24d4a7de75446be83244eabbff746d66b9240ae020ced65d060815fac3423759"}, + {file = "coverage-5.5-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1f8bf7b90ba55699b3a5e44930e93ff0189aa27186e96071fac7dd0d06a1873"}, + {file = "coverage-5.5-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:970284a88b99673ccb2e4e334cfb38a10aab7cd44f7457564d11898a74b62d0a"}, + {file = "coverage-5.5-cp38-cp38-win32.whl", hash = "sha256:01d84219b5cdbfc8122223b39a954820929497a1cb1422824bb86b07b74594b6"}, + {file = "coverage-5.5-cp38-cp38-win_amd64.whl", hash = "sha256:2e0d881ad471768bf6e6c2bf905d183543f10098e3b3640fc029509530091502"}, + {file = "coverage-5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d1f9ce122f83b2305592c11d64f181b87153fc2c2bbd3bb4a3dde8303cfb1a6b"}, + {file = "coverage-5.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:13c4ee887eca0f4c5a247b75398d4114c37882658300e153113dafb1d76de529"}, + {file = "coverage-5.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:52596d3d0e8bdf3af43db3e9ba8dcdaac724ba7b5ca3f6358529d56f7a166f8b"}, + {file = "coverage-5.5-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2cafbbb3af0733db200c9b5f798d18953b1a304d3f86a938367de1567f4b5bff"}, + {file = "coverage-5.5-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:44d654437b8ddd9eee7d1eaee28b7219bec228520ff809af170488fd2fed3e2b"}, + {file = "coverage-5.5-cp39-cp39-win32.whl", hash = "sha256:d314ed732c25d29775e84a960c3c60808b682c08d86602ec2c3008e1202e3bb6"}, + {file = "coverage-5.5-cp39-cp39-win_amd64.whl", hash = "sha256:13034c4409db851670bc9acd836243aeee299949bd5673e11844befcb0149f03"}, + {file = "coverage-5.5-pp36-none-any.whl", hash = "sha256:f030f8873312a16414c0d8e1a1ddff2d3235655a2174e3648b4fa66b3f2f1079"}, + {file = "coverage-5.5-pp37-none-any.whl", hash = "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4"}, + {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"}, ] cucumber-tag-expressions = [ {file = "cucumber-tag-expressions-2.0.4.tar.gz", hash = "sha256:72197b9330c023ce2643847fd6659c5c000f7f286f5b42cbcfd19adb3be92d30"}, @@ -403,12 +406,12 @@ dataclasses = [ {file = "dataclasses-0.7.tar.gz", hash = "sha256:494a6dcae3b8bcf80848eea2ef64c0cc5cd307ffc263e17cdf42f3e5420808e6"}, ] flake8 = [ - {file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"}, - {file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"}, + {file = "flake8-3.9.0-py2.py3-none-any.whl", hash = "sha256:12d05ab02614b6aee8df7c36b97d1a3b2372761222b19b58621355e82acddcff"}, + {file = "flake8-3.9.0.tar.gz", hash = "sha256:78873e372b12b093da7b5e5ed302e8ad9e988b38b063b61ad937f26ca58fc5f0"}, ] importlib-metadata = [ - {file = "importlib_metadata-3.4.0-py3-none-any.whl", hash = "sha256:ace61d5fc652dc280e7b6b4ff732a9c2d40db2c0f92bc6cb74e07b73d53a1771"}, - {file = "importlib_metadata-3.4.0.tar.gz", hash = "sha256:fa5daa4477a7414ae34e95942e4dd07f62adf589143c875c133c1e53c4eff38d"}, + {file = "importlib_metadata-3.7.3-py3-none-any.whl", hash = "sha256:b74159469b464a99cb8cc3e21973e4d96e05d3024d337313fedb618a6e86e6f4"}, + {file = "importlib_metadata-3.7.3.tar.gz", hash = "sha256:742add720a20d0467df2f444ae41704000f50e1234f46174b51f9c6031a1bd71"}, ] jinja2 = [ {file = "Jinja2-2.11.3-py2.py3-none-any.whl", hash = "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419"}, @@ -481,63 +484,63 @@ pprintpp = [ {file = "pprintpp-0.4.0.tar.gz", hash = "sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403"}, ] pycodestyle = [ - {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, - {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, + {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, + {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, ] pyflakes = [ - {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, - {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, + {file = "pyflakes-2.3.0-py2.py3-none-any.whl", hash = "sha256:910208209dcea632721cb58363d0f72913d9e8cf64dc6f8ae2e02a3609aba40d"}, + {file = "pyflakes-2.3.0.tar.gz", hash = "sha256:e59fd8e750e588358f1b8885e5a4751203a0516e0ee6d34811089ac294c8806f"}, ] pygments = [ - {file = "Pygments-2.8.0-py3-none-any.whl", hash = "sha256:b21b072d0ccdf29297a82a2363359d99623597b8a265b8081760e4d0f7153c88"}, - {file = "Pygments-2.8.0.tar.gz", hash = "sha256:37a13ba168a02ac54cc5891a42b1caec333e59b66addb7fa633ea8a6d73445c0"}, + {file = "Pygments-2.8.1-py3-none-any.whl", hash = "sha256:534ef71d539ae97d4c3a4cf7d6f110f214b0e687e92f9cb9d2a3b0d3101289c8"}, + {file = "Pygments-2.8.1.tar.gz", hash = "sha256:2656e1a6edcdabf4275f9a3640db59fd5de107d88e8663c5d4e9a0fa62f77f94"}, ] regex = [ - {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"}, + {file = "regex-2021.3.17-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b97ec5d299c10d96617cc851b2e0f81ba5d9d6248413cd374ef7f3a8871ee4a6"}, + {file = "regex-2021.3.17-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:cb4ee827857a5ad9b8ae34d3c8cc51151cb4a3fe082c12ec20ec73e63cc7c6f0"}, + {file = "regex-2021.3.17-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:633497504e2a485a70a3268d4fc403fe3063a50a50eed1039083e9471ad0101c"}, + {file = "regex-2021.3.17-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:a59a2ee329b3de764b21495d78c92ab00b4ea79acef0f7ae8c1067f773570afa"}, + {file = "regex-2021.3.17-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:f85d6f41e34f6a2d1607e312820971872944f1661a73d33e1e82d35ea3305e14"}, + {file = "regex-2021.3.17-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:4651f839dbde0816798e698626af6a2469eee6d9964824bb5386091255a1694f"}, + {file = "regex-2021.3.17-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:39c44532d0e4f1639a89e52355b949573e1e2c5116106a395642cbbae0ff9bcd"}, + {file = "regex-2021.3.17-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:3d9a7e215e02bd7646a91fb8bcba30bc55fd42a719d6b35cf80e5bae31d9134e"}, + {file = "regex-2021.3.17-cp36-cp36m-win32.whl", hash = "sha256:159fac1a4731409c830d32913f13f68346d6b8e39650ed5d704a9ce2f9ef9cb3"}, + {file = "regex-2021.3.17-cp36-cp36m-win_amd64.whl", hash = "sha256:13f50969028e81765ed2a1c5fcfdc246c245cf8d47986d5172e82ab1a0c42ee5"}, + {file = "regex-2021.3.17-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b9d8d286c53fe0cbc6d20bf3d583cabcd1499d89034524e3b94c93a5ab85ca90"}, + {file = "regex-2021.3.17-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:201e2619a77b21a7780580ab7b5ce43835e242d3e20fef50f66a8df0542e437f"}, + {file = "regex-2021.3.17-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d47d359545b0ccad29d572ecd52c9da945de7cd6cf9c0cfcb0269f76d3555689"}, + {file = "regex-2021.3.17-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:ea2f41445852c660ba7c3ebf7d70b3779b20d9ca8ba54485a17740db49f46932"}, + {file = "regex-2021.3.17-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:486a5f8e11e1f5bbfcad87f7c7745eb14796642323e7e1829a331f87a713daaa"}, + {file = "regex-2021.3.17-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:18e25e0afe1cf0f62781a150c1454b2113785401ba285c745acf10c8ca8917df"}, + {file = "regex-2021.3.17-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:a2ee026f4156789df8644d23ef423e6194fad0bc53575534101bb1de5d67e8ce"}, + {file = "regex-2021.3.17-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:4c0788010a93ace8a174d73e7c6c9d3e6e3b7ad99a453c8ee8c975ddd9965643"}, + {file = "regex-2021.3.17-cp37-cp37m-win32.whl", hash = "sha256:575a832e09d237ae5fedb825a7a5bc6a116090dd57d6417d4f3b75121c73e3be"}, + {file = "regex-2021.3.17-cp37-cp37m-win_amd64.whl", hash = "sha256:8e65e3e4c6feadf6770e2ad89ad3deb524bcb03d8dc679f381d0568c024e0deb"}, + {file = "regex-2021.3.17-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a0df9a0ad2aad49ea3c7f65edd2ffb3d5c59589b85992a6006354f6fb109bb18"}, + {file = "regex-2021.3.17-cp38-cp38-manylinux1_i686.whl", hash = "sha256:b98bc9db003f1079caf07b610377ed1ac2e2c11acc2bea4892e28cc5b509d8d5"}, + {file = "regex-2021.3.17-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:808404898e9a765e4058bf3d7607d0629000e0a14a6782ccbb089296b76fa8fe"}, + {file = "regex-2021.3.17-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:5770a51180d85ea468234bc7987f5597803a4c3d7463e7323322fe4a1b181578"}, + {file = "regex-2021.3.17-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:976a54d44fd043d958a69b18705a910a8376196c6b6ee5f2596ffc11bff4420d"}, + {file = "regex-2021.3.17-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:63f3ca8451e5ff7133ffbec9eda641aeab2001be1a01878990f6c87e3c44b9d5"}, + {file = "regex-2021.3.17-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:bcd945175c29a672f13fce13a11893556cd440e37c1b643d6eeab1988c8b209c"}, + {file = "regex-2021.3.17-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:3d9356add82cff75413bec360c1eca3e58db4a9f5dafa1f19650958a81e3249d"}, + {file = "regex-2021.3.17-cp38-cp38-win32.whl", hash = "sha256:f5d0c921c99297354cecc5a416ee4280bd3f20fd81b9fb671ca6be71499c3fdf"}, + {file = "regex-2021.3.17-cp38-cp38-win_amd64.whl", hash = "sha256:14de88eda0976020528efc92d0a1f8830e2fb0de2ae6005a6fc4e062553031fa"}, + {file = "regex-2021.3.17-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4c2e364491406b7888c2ad4428245fc56c327e34a5dfe58fd40df272b3c3dab3"}, + {file = "regex-2021.3.17-cp39-cp39-manylinux1_i686.whl", hash = "sha256:8bd4f91f3fb1c9b1380d6894bd5b4a519409135bec14c0c80151e58394a4e88a"}, + {file = "regex-2021.3.17-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:882f53afe31ef0425b405a3f601c0009b44206ea7f55ee1c606aad3cc213a52c"}, + {file = "regex-2021.3.17-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:07ef35301b4484bce843831e7039a84e19d8d33b3f8b2f9aab86c376813d0139"}, + {file = "regex-2021.3.17-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:360a01b5fa2ad35b3113ae0c07fb544ad180603fa3b1f074f52d98c1096fa15e"}, + {file = "regex-2021.3.17-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:709f65bb2fa9825f09892617d01246002097f8f9b6dde8d1bb4083cf554701ba"}, + {file = "regex-2021.3.17-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:c66221e947d7207457f8b6f42b12f613b09efa9669f65a587a2a71f6a0e4d106"}, + {file = "regex-2021.3.17-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:c782da0e45aff131f0bed6e66fbcfa589ff2862fc719b83a88640daa01a5aff7"}, + {file = "regex-2021.3.17-cp39-cp39-win32.whl", hash = "sha256:dc9963aacb7da5177e40874585d7407c0f93fb9d7518ec58b86e562f633f36cd"}, + {file = "regex-2021.3.17-cp39-cp39-win_amd64.whl", hash = "sha256:a0d04128e005142260de3733591ddf476e4902c0c23c1af237d9acf3c96e1b38"}, + {file = "regex-2021.3.17.tar.gz", hash = "sha256:4b8a1fb724904139149a43e172850f35aa6ea97fb0545244dc0b805e0154ed68"}, ] rich = [ - {file = "rich-9.11.0-py3-none-any.whl", hash = "sha256:a8ee22199562278d2f78148cacb2f9460ccac362cd4a40f705505b41daae60e0"}, - {file = "rich-9.11.0.tar.gz", hash = "sha256:f8f08fdac6bd67dc2dd7fe976da702d748487aa9eb5d050c48b2321bc67ed659"}, + {file = "rich-9.13.0-py3-none-any.whl", hash = "sha256:9004f6449c89abadf689dad6f92393e760b8c3a8a8c4ea6d8d474066307c0e66"}, + {file = "rich-9.13.0.tar.gz", hash = "sha256:d59e94a0e3e686f0d268fe5c7060baa1bd6744abca71b45351f5850a3aaa6764"}, ] shellingham = [ {file = "shellingham-1.4.0-py2.py3-none-any.whl", hash = "sha256:536b67a0697f2e4af32ab176c00a50ac2899c5a05e0d8e2dadac8e58888283f9"}, @@ -592,6 +595,6 @@ typing-extensions = [ {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, ] zipp = [ - {file = "zipp-3.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"}, - {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"}, + {file = "zipp-3.4.1-py3-none-any.whl", hash = "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"}, + {file = "zipp-3.4.1.tar.gz", hash = "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76"}, ] diff --git a/ward/diff.py b/ward/diff.py index d805923e..03b24ec1 100644 --- a/ward/diff.py +++ b/ward/diff.py @@ -105,17 +105,16 @@ 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 + current_span += line_to_rewrite[index - 2] 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 - ) # subtract 2 for code at start, and 1 to remove the newline char + + # subtract 2 for code at start, and 1 to remove the newline char + remaining_index = index - 3 if prev_marker == "+": output_lines[last_output_idx] += colored( line_to_rewrite[remaining_index:], color="red" diff --git a/ward/run.py b/ward/run.py index 68ea3865..6fd05675 100644 --- a/ward/run.py +++ b/ward/run.py @@ -244,6 +244,7 @@ def fixtures( show_dependency_trees=show_dependency_trees or full, ) + @run.command() @click.pass_context def completions(ctx: click.Context): diff --git a/ward/terminal.py b/ward/terminal.py index 26dd3739..fdad2f8c 100644 --- a/ward/terminal.py +++ b/ward/terminal.py @@ -5,7 +5,7 @@ from dataclasses import dataclass from enum import Enum from pathlib import Path -from textwrap import indent, dedent, wrap +from textwrap import dedent, wrap from typing import ( Any, Dict, @@ -13,7 +13,6 @@ Iterable, List, Optional, - Iterator, Collection, ) @@ -31,7 +30,7 @@ from rich.text import Text from rich.theme import Theme from rich.traceback import Traceback -from termcolor import colored +from rich.tree import Tree from ward._ward_version import __version__ from ward.diff import make_diff @@ -59,25 +58,32 @@ def make_indent(depth=1): DOUBLE_INDENT = make_indent(depth=2) -theme = Theme({ - "title": "bold", - "heading": "bold", - "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", - "dryrun": "#ffffff on #162740", - "rule.line": "#189F4A", -}) +theme = Theme( + { + "title": "bold", + "heading": "bold", + "pass": "#ffffff on #137C39", + "pass.textonly": "#189F4A", + "fail": "#ffffff on #BF2D2D", + "fail.textonly": "#BF2D2D", + "fail.header": "bold #BF2D2D", + "skip": "#ffffff on #0E67B3", + "skip.textonly": "#1381E0", + "xpass": "#162740 on #F4C041", + "xpass.textonly": "#F4C041", + "xfail": "#ffffff on #695CC8", + "xfail.textonly": "#695CC8", + "muted": "dim", + "info": "yellow italic", + "dryrun": "#ffffff on #162740", + "rule.line": "#189F4A", + "fixture.name": "bold #1381E0", + "fixture.scope.test": "bold #189F4A", + "fixture.scope.module": "bold #F4C041", + "fixture.scope.global": "bold #EA913C", + "usedby": "#9285F6", + } +) console = Console(theme=theme, highlighter=NullHighlighter()) @@ -154,14 +160,15 @@ def output_test_result_line(test_result: TestResult): common_columns = ( 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)), - Padding(Markdown(test.description, inline_code_theme="ansi_dark"), pad=(0, 1, 0, 0)), + Padding( + Markdown(test.description, inline_code_theme="ansi_dark"), pad=(0, 1, 0, 0) + ), ) if reason: grid.add_column(justify="center", style=test_style) grid.add_row( - *common_columns, - Padding(reason, pad=(0, 1, 0, 1)), + *common_columns, Padding(reason, pad=(0, 1, 0, 1)), ) else: grid.add_row(*common_columns) @@ -190,7 +197,7 @@ 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 @@ -222,7 +229,7 @@ def print_dot(result): 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 = "" @@ -239,12 +246,14 @@ def output_dots_module( 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: - console.print(rel_path[: final_slash_idx + 1], style="muted", end="") - console.print(rel_path[final_slash_idx + 1:] + ": ", end="") + console.print( + rel_path[: final_slash_idx + 1], style="muted", end="" + ) + console.print(rel_path[final_slash_idx + 1 :] + ": ", end="") else: console.print(f"\n{rel_path}: ", end="") print_dot(result) @@ -265,8 +274,7 @@ def output_dots_module( def output_run_cancelled(): console.print( - "Run cancelled - results for tests that ran shown below.", - style="info", + "Run cancelled - results for tests that ran shown below.", style="info", ) @@ -299,21 +307,27 @@ def __rich_console__(self, c: Console, co: ConsoleOptions) -> RenderResult: grid.add_column() # Test ID grid.add_column() # Test description - for result in test_results[:self.num_tests_to_show]: + for result in test_results[: self.num_tests_to_show]: 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"[b]{time_taken_millis:.0f}[/b]ms", Text(test_id, style="muted"), 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) + num_slowest_displayed = min( + len(self.all_tests_in_session), self.num_tests_to_show + ) panel = Panel( 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) + pad=(0, 0, 1, 0), ), grid, ), @@ -333,11 +347,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 @@ -348,9 +362,7 @@ def __init__( def output_header(self, time_to_collect): python_impl = platform.python_implementation() python_version = platform.python_version() - console.print( - Rule(Text(f"Ward {__version__}", style="title")), - ) + console.print(Rule(Text(f"Ward {__version__}", style="title")),) if self.config_path: try: path = self.config_path.relative_to(Path.cwd()) @@ -364,9 +376,9 @@ def output_header(self, time_to_collect): ) 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 [] @@ -387,7 +399,7 @@ def output_all_test_results( console.print() return all_results - def print_divider(self): + def print_divider(self) -> None: console.print(Rule(style="muted")) def output_single_test_result(self, test_result: TestResult): @@ -401,7 +413,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() @@ -422,10 +434,6 @@ def output_test_failed_location(self, test_result: TestResult): raise NotImplementedError() -def lightblack(s: str) -> str: - return s - - @dataclass class TerminalSize: height: int @@ -446,7 +454,13 @@ class SimpleTestResultWrite(TestResultWriterBase): def output_why_test_failed_header(self, test_result: TestResult): test = test_result.test console.print( - Padding(Rule(title=Text(test.description, style="fail.header"), style="fail.textonly"), pad=(1, 0, 0, 0)), + 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): @@ -456,8 +470,15 @@ def output_why_test_failed(self, test_result: TestResult): if err.operator in Comparison: src = "".join(src_lines) - src = Syntax(src, "python", start_line=line_num, line_numbers=True, highlight_lines={err.error_line}, - background_color="default", theme="ansi_dark") + 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) @@ -492,7 +513,7 @@ def print_traceback(self, err): console.print(str(err)) 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: console.print(TestTimingStats(test_results, show_slowest)) @@ -507,7 +528,7 @@ def output_test_result_summary( result_table.add_row( Padding(str(test_count), pad=HORIZONTAL_PAD, style="bold"), Padding("Tests Encountered", pad=HORIZONTAL_PAD), - style="default" + style="default", ) for outcome, count in outcome_counts.items(): if count > 0: @@ -515,7 +536,7 @@ def output_test_result_summary( 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) + style=outcome_to_style(outcome), ) exit_code = get_exit_code(test_results) @@ -524,23 +545,26 @@ def output_test_result_summary( else: result_style = "fail.textonly" - result_summary_panel = Panel(result_table, title="[b default]Results[/b default]", style="none", expand=False, - border_style=result_style) + 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) console.print( - Rule(f"[b]{exit_code.clean_name}[/b] in [b]{time_taken:.2f}[/b] seconds", style=result_style) + Rule( + f"[b]{exit_code.clean_name}[/b] in [b]{time_taken:.2f}[/b] seconds", + style=result_style, + ) ) def output_captured_stderr(self, test_result: TestResult): if test_result.captured_stderr: captured_stderr_lines = test_result.captured_stderr.split("\n") - console.print( - Padding( - Text(f"Captured stderr"), - pad=(0, 0, 1, 2) - ) - ) + console.print(Padding(Text(f"Captured stderr"), pad=(0, 0, 1, 2))) for line in captured_stderr_lines: console.print(Padding(line, pad=(0, 0, 0, 4))) console.print() @@ -548,29 +572,26 @@ def output_captured_stderr(self, test_result: TestResult): def output_captured_stdout(self, test_result: TestResult): if test_result.captured_stdout: captured_stdout_lines = test_result.captured_stdout.split("\n") - console.print( - Padding( - Text(f"Captured stdout"), - pad=(0, 0, 1, 2) - ) - ) + console.print(Padding(Text(f"Captured stdout"), pad=(0, 0, 1, 2))) 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( - test_result.error, AssertionError + test_result.error, AssertionError ): console.print( Padding( - Text(f"Failed at {test_result.test.path.relative_to(Path.cwd())}:{test_result.error.error_line}"), - pad=(1, 0, 1, 2) + Text( + f"Failed at {test_result.test.path.relative_to(Path.cwd())}:{test_result.error.error_line}" + ), + pad=(1, 0, 1, 2), ) ) def _get_outcome_counts( - self, test_results: List[TestResult] + self, test_results: List[TestResult] ) -> Dict[TestOutcome, int]: return { TestOutcome.PASS: len( @@ -616,17 +637,21 @@ def outcome_to_style(outcome: TestOutcome) -> str: }[outcome] -def scope_to_colour(scope: Scope) -> str: - return {Scope.Test: "green", Scope.Module: "blue", Scope.Global: "magenta"}[scope] +def scope_to_style(scope: Scope) -> str: + return { + Scope.Test: "fixture.scope.test", + Scope.Module: "fixture.scope.module", + Scope.Global: "fixture.scope.global", + }[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 @@ -636,30 +661,34 @@ def output_fixtures( fixtures_to_parents, fixtures_to_children = fixture_parents_and_children(fixtures) - for fixture in fixtures: - output_fixture_information( - fixture, - used_by_tests=fixture_to_tests[fixture], - fixtures_to_children=fixtures_to_children, - fixtures_to_parents=fixtures_to_parents, - show_scopes=show_scopes, - show_docstrings=show_docstrings, - show_dependencies=show_dependencies, - show_dependency_trees=show_dependency_trees, - ) + for module, fixtures in group_by(fixtures, key=lambda f: f.module_name).items(): + console.print(Rule(Text(module, style="title"))) + + for fixture in fixtures: + fixture_tree = make_fixture_information_tree( + fixture, + used_by_tests=fixture_to_tests[fixture], + fixtures_to_children=fixtures_to_children, + fixtures_to_parents=fixtures_to_parents, + show_scopes=show_scopes, + show_docstrings=show_docstrings, + show_dependencies=show_dependencies, + show_dependency_trees=show_dependency_trees, + ) + console.print(fixture_tree) -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, -): - lines = [format_fixture(fixture, show_scope=show_scopes)] +def make_fixture_information_tree( + 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, +) -> Tree: + root = Tree(label=make_text_for_fixture(fixture, show_scope=show_scopes)) if show_dependency_trees: max_depth = None @@ -668,73 +697,48 @@ def output_fixture_information( else: max_depth = 0 + if show_docstrings and fixture.fn.__doc__ is not None: + root.add(dedent(fixture.fn.__doc__).strip("\n")) + if show_dependencies or show_dependency_trees: if fixtures_to_parents[fixture]: - lines.append(indent("depends on fixtures", INDENT)) - lines.extend( - yield_fixture_dependency_tree( - fixture, - fixtures_to_parents, - show_scopes=show_scopes, - max_depth=max_depth, - ) + depends_on_node = root.add(label="[usedby]depends on fixtures") + add_fixture_dependencies_to_tree( + depends_on_node, + fixture, + fixtures_to_parents, + show_scopes=show_scopes, + max_depth=max_depth, ) - lines.append("") if fixtures_to_children[fixture]: - lines.append(indent("used by fixtures", INDENT)) - lines.extend( - yield_fixture_dependency_tree( - fixture, - fixtures_to_children, - show_scopes=show_scopes, - max_depth=max_depth, - ) + used_by_node = root.add(label="[usedby]used by fixtures") + add_fixture_dependencies_to_tree( + used_by_node, + fixture, + fixtures_to_children, + show_scopes=show_scopes, + max_depth=max_depth, ) - lines.append("") if used_by_tests: - lines.append(indent("used directly by tests", INDENT)) - lines.extend(yield_fixture_usages_by_tests(used_by_tests)) - lines.append("") + used_by_tests_node = root.add("[usedby]used directly by tests") + add_fixture_usages_by_tests_to_tree(used_by_tests_node, used_by_tests) if not (used_by_tests or fixtures_to_children[fixture]): - lines.append( - indent( - f"used by {colored('no tests or fixtures', color='red', attrs=['bold'])}", - INDENT, - ) - ) - lines.append("") - - if show_docstrings and fixture.fn.__doc__ is not None: - doc = dedent(fixture.fn.__doc__.strip("\n")) - lines.extend(indent(doc, INDENT).splitlines()) - lines.append("") + root.add(f"[usedby]used by [fail]no tests or fixtures") - print("\n".join(lines)) + return root -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] - prefix = "├─" if idx != len(grouped_used_by) - 1 else "└─" - loc = lightblack(format_test_location(test)) - sep = lightblack(f" [{len(tests)}]:" if len(tests) > 1 else ":") - yield indent( - f"{prefix} {loc}{sep} {test.description}", INDENT, - ) - - -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, -) -> Iterator[str]: +def add_fixture_dependencies_to_tree( + parent: Tree, + fixture: Fixture, + fixtures_to_parents_or_children: _TYPE_FIXTURE_TO_FIXTURES, + show_scopes: bool, + max_depth: Optional[int], + depth: int = 0, +) -> None: if max_depth is not None and depth >= max_depth: return @@ -743,38 +747,38 @@ def yield_fixture_dependency_tree( if not this_layer: return - for idx, dep in enumerate(this_layer): - fix = format_fixture(dep, show_scopes) - if idx < len(this_layer) - 1: - tree = "├─" - next_prefix = prefix + "│ " - else: - tree = "└─" - next_prefix = prefix + " " - - yield f"{prefix}{tree} {fix}" - yield from yield_fixture_dependency_tree( - dep, - fixtures_to_parents_or_children, - show_scopes, - max_depth, + for dep in this_layer: + node = parent.add(make_text_for_fixture(fixture=dep, show_scope=show_scopes)) + add_fixture_dependencies_to_tree( + parent=node, + fixture=dep, + fixtures_to_parents_or_children=fixtures_to_parents_or_children, + show_scopes=show_scopes, + max_depth=max_depth, depth=depth + 1, - prefix=next_prefix, ) -def format_fixture(fixture: Fixture, show_scope: bool): - path = lightblack(f"{fixture.path.name}:{fixture.line_number}") - name = colored(fixture.name, color="cyan", attrs=["bold"]) - scope = colored( - fixture.scope.value, color=scope_to_colour(fixture.scope), attrs=["bold"] - ) - header = f"{path} {name}" +def add_fixture_usages_by_tests_to_tree(node: Tree, used_by: Iterable[Test]) -> None: + 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] + loc = format_test_location(test) + sep = f" [{len(tests)}]" if len(tests) > 1 else "" + node.add(f"[muted]{loc}{sep}[/muted] {test.description}") + + +def make_text_for_fixture(fixture: Fixture, show_scope: bool) -> Text: + text = Text() + text.append(f"{fixture.path.name}:{fixture.line_number} ", style="dim") + text.append(fixture.name, style="fixture.name") if show_scope: - header = f"{header} (scope: {scope})" + text.append( + f" (scope: {fixture.scope.value})", style=scope_to_style(fixture.scope) + ) - return header + return text class ExitCode(Enum): @@ -793,7 +797,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 24a189ef..dd7ee94a 100644 --- a/ward/testing.py +++ b/ward/testing.py @@ -366,7 +366,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. @@ -392,7 +392,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 @@ -406,7 +406,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) @@ -476,7 +476,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} diff --git a/ward/tests/test_suite.py b/ward/tests/test_suite.py index a8497ced..961c97f6 100644 --- a/ward/tests/test_suite.py +++ b/ward/tests/test_suite.py @@ -30,7 +30,7 @@ def _(suite=suite): @test( - f"Suite.generate_test_runs generates {NUMBER_OF_TESTS} when suite has {NUMBER_OF_TESTS} tests" + f"Suite.generate_test_runs generates {NUMBER_OF_TESTS} tests when suite has {NUMBER_OF_TESTS} tests" ) def _(suite=suite): runs = suite.generate_test_runs() @@ -38,7 +38,7 @@ def _(suite=suite): assert len(list(runs)) == NUMBER_OF_TESTS -@test("Suite.generate_test_runs generates yields the expected test results") +@test("Suite.generate_test_runs yields the expected test results") def _(suite=suite): results = list(suite.generate_test_runs()) expected = [ diff --git a/ward/tests/test_util.py b/ward/tests/test_util.py index a9765feb..44049e9c 100644 --- a/ward/tests/test_util.py +++ b/ward/tests/test_util.py @@ -19,7 +19,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 @@ -67,12 +67,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 diff --git a/ward/util.py b/ward/util.py index 1ed9659c..8447cba8 100644 --- a/ward/util.py +++ b/ward/util.py @@ -1,7 +1,7 @@ import collections import inspect from pathlib import Path -from typing import Iterable, Any, Callable, Hashable, TypeVar, Dict +from typing import Iterable, Any, Callable, Hashable, TypeVar, Dict, List def truncate(s: str, num_chars: int) -> str: @@ -38,7 +38,7 @@ def get_absolute_path(object: Any) -> Path: H = TypeVar("H", bound=Hashable) -def group_by(items: Iterable[T], key: Callable[[T], H]) -> Dict[H, T]: +def group_by(items: Iterable[T], key: Callable[[T], H]) -> Dict[H, List[T]]: groups = collections.defaultdict(list) for item in items: groups[key(item)].append(item)