From 71117e730c4f62458b30af820f51890487b458e4 Mon Sep 17 00:00:00 2001 From: Oliver Newman <15459200+orn688@users.noreply.github.com> Date: Wed, 27 Jan 2021 12:36:21 -0500 Subject: [PATCH 01/54] Update example exclude to match only files in root (#1861) * Update example exclude to match only files in root The `exclude` section of the example `pyproject.toml` file didn't work as expected. It claimed to exclude matched files only in the project root, but it actually excluded matched files at any directory level within the project. We can address this by prepending `^/` to the regex to ensure that it only matches files in the project root. See https://github.com/psf/black/issues/1473#issuecomment-740008873 for explanation. * Mention excluding directories as well --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f1ec76938f0..83ecb89d6c9 100644 --- a/README.md +++ b/README.md @@ -313,9 +313,10 @@ line-length = 88 target-version = ['py37'] include = '\.pyi?$' exclude = ''' - -( - /( +# A regex preceded with ^/ will apply only to files and directories +# in the root of the project. +^/( + ( \.eggs # exclude a few common directories in the | \.git # root of the project | \.hg From 988c686d312986760a42cc7edd9a79a8f31c4769 Mon Sep 17 00:00:00 2001 From: James Addison Date: Mon, 1 Feb 2021 17:54:19 +0000 Subject: [PATCH 02/54] Remove placeholder exit code in unreachable 'black-primer' subprocess handler (#1952) --- src/black_primer/lib.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/black_primer/lib.py b/src/black_primer/lib.py index c3069812b22..39ae93ba516 100644 --- a/src/black_primer/lib.py +++ b/src/black_primer/lib.py @@ -58,13 +58,16 @@ async def _gen_check_output( await process.wait() raise - if process.returncode != 0: - returncode = process.returncode - if returncode is None: - returncode = 69 + # A non-optional timeout was supplied to asyncio.wait_for, guaranteeing + # a timeout or completed process. A terminated Python process will have a + # non-empty returncode value. + assert process.returncode is not None + if process.returncode != 0: cmd_str = " ".join(cmd) - raise CalledProcessError(returncode, cmd_str, output=stdout, stderr=stderr) + raise CalledProcessError( + process.returncode, cmd_str, output=stdout, stderr=stderr + ) return (stdout, stderr) From df4dd38a9a2b44c14485948fe8209fa19db2383a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Feb 2021 15:54:14 -0800 Subject: [PATCH 03/54] Bump bleach from 3.2.1 to 3.3.0 (#1957) Bumps [bleach](https://github.com/mozilla/bleach) from 3.2.1 to 3.3.0. - [Release notes](https://github.com/mozilla/bleach/releases) - [Changelog](https://github.com/mozilla/bleach/blob/master/CHANGES) - [Commits](https://github.com/mozilla/bleach/compare/v3.2.1...v3.3.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Pipfile.lock | 219 ++++++++++++++++++++++----------------------------- 1 file changed, 92 insertions(+), 127 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 91fd3a49556..44e987de0e4 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -78,7 +78,6 @@ "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f", "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3" ], - "markers": "python_full_version >= '3.5.3'", "version": "==3.0.1" }, "attrs": { @@ -86,7 +85,6 @@ "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6", "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==20.3.0" }, "black": { @@ -117,17 +115,14 @@ "sha256:6988bd2b895eef432d562370bb707d540f32f7360ab13da45340101bc2307d84" ], "index": "pypi", - "python_version <": "3.7", - "version": "==0.6", - "version >": "0.6" + "version": "==0.6" }, "idna": { "hashes": [ - "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", - "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" + "sha256:5205d03e7bcbb919cc9c19885f9920d622ca52448306f2377daede5cf3faac16", + "sha256:c5b02147e01ea9920e6b0a3f1f7bb833612d507592c837a6c49552768f4054e1" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.10" + "version": "==3.1" }, "multidict": { "hashes": [ @@ -169,7 +164,6 @@ "sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281", "sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80" ], - "markers": "python_version >= '3.6'", "version": "==5.1.0" }, "mypy-extensions": { @@ -235,20 +229,6 @@ "index": "pypi", "version": "==2020.11.13" }, - "setuptools-scm": { - "hashes": [ - "sha256:1fc4e25df445351d172bb4788f4d07f9e9ce0e8b7dee6b19584e46110172ca13", - "sha256:48b31488d089270500f120efea723968c01abd85fd4876043a3b7c7ef7d0b761", - "sha256:62fa535edb31ece9fa65dc9dcb3056145b8020c8c26c0ef1018aef33db95c40d", - "sha256:b928021c4381f96d577847d540d6e03065f8f8851c768a0c9bc552d463bae0d4", - "sha256:c85b6b46d0edd40d2301038cdea96bb6adc14d62ef943e75afb08b3e7bcf142a", - "sha256:db4ab2e0c2644ba71b1e5212b14ff65dbf0af465796d314a75e0cf6128f605f7", - "sha256:e878036c2527dfd05818727846338be86b2be6955741b85fab2625f63d001021", - "sha256:eb19b46816fc106a4c2d4180022687eab40f9773cf61390b845afb093d1f4ecd" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==5.0.1" - }, "toml": { "hashes": [ "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", @@ -300,9 +280,7 @@ "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f" ], "index": "pypi", - "python_version <": "3.8", - "version": "==3.7.4.3", - "version >=": "3.7.4" + "version": "==3.7.4.3" }, "yarl": { "hashes": [ @@ -344,7 +322,6 @@ "sha256:f0b059678fd549c66b89bed03efcabb009075bd131c248ecdf087bdb6faba24a", "sha256:fcbb48a93e8699eae920f8d92f7160c03567b421bc17362a9ffbbd706a816f71" ], - "markers": "python_version >= '3.6'", "version": "==1.6.3" } }, @@ -420,7 +397,6 @@ "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f", "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3" ], - "markers": "python_full_version >= '3.5.3'", "version": "==3.0.1" }, "attrs": { @@ -428,7 +404,6 @@ "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6", "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==20.3.0" }, "babel": { @@ -436,7 +411,6 @@ "sha256:9d35c22fcc79893c3ecc85ac4a56cde1ecf3f19c540bba0922308a6c06ca6fa5", "sha256:da031ab54472314f210b0adcff1588ee5d1d1d0ba4dbd07b94dba82bde791e05" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.9.0" }, "black": { @@ -448,11 +422,11 @@ }, "bleach": { "hashes": [ - "sha256:52b5919b81842b1854196eaae5ca29679a2f2e378905c346d3ca8227c2c66080", - "sha256:9f8ccbeb6183c6e6cddea37592dfb0167485c1e3b13b3363bc325aa8bda3adbd" + "sha256:6123ddc1052673e52bab52cdc955bcb57a015264a1c57d37bea2f6b817af0125", + "sha256:98b3170739e5e83dd9dc19633f074727ad848cbedb6026708c8ac2d3b697a433" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==3.2.1" + "index": "pypi", + "version": "==3.3.0" }, "certifi": { "hashes": [ @@ -479,6 +453,7 @@ "sha256:6bc25fc545a6b3d57b5f8618e59fc13d3a3a68431e8ca5fd4c13241cd70d0009", "sha256:798caa2a2384b1cbe8a2a139d80734c9db54f9cc155c99d7cc92441a23871c03", "sha256:7c6b1dece89874d9541fc974917b631406233ea0440d0bdfbb8e03bf39a49b3b", + "sha256:7ef7d4ced6b325e92eb4d3502946c78c5367bc416398d387b39591532536734e", "sha256:840793c68105fe031f34d6a086eaea153a0cd5c491cde82a74b420edd0a2b909", "sha256:8d6603078baf4e11edc4168a514c5ce5b3ba6e3e9c374298cb88437957960a53", "sha256:9cc46bc107224ff5b6d04369e7c595acb700c3613ad7bcf2e2012f62ece80c35", @@ -507,7 +482,6 @@ "sha256:32e43d604bbe7896fe7c248a9c2276447dbef840feb28fe20494f62af110211d", "sha256:cf22deb93d4bcf92f345a5c3cd39d3d41d6340adc60c78bbbd6588c384fda6a1" ], - "markers": "python_full_version >= '3.6.1'", "version": "==3.2.0" }, "chardet": { @@ -530,7 +504,6 @@ "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b", "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==0.4.4" }, "commonmark": { @@ -612,7 +585,6 @@ "sha256:c366df0401d1ec4e548bebe8f91d55ebcc0ec3137900d214dd7aac8427ef3030", "sha256:dc42f645f8f3a489c3dd416730a514e7a91a59510ddaadc09d04224c098d3302" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", "version": "==3.3.1" }, "distlib": { @@ -625,7 +597,6 @@ "docutils": { "hashes": [ "sha256:54a349c622ff31c91cbec43b0b512f113b5b24daf00e2ea530bb1bd9aac14849", - "sha256:ba4584f9107571ced0d2c7f56a5499c696215ba90797849c92d395979da68521", "sha256:d2ddba74835cb090a1b627d3de4e7835c628d07ee461f7b4480f51af2fe4d448" ], "index": "pypi", @@ -656,26 +627,23 @@ }, "identify": { "hashes": [ - "sha256:943cd299ac7f5715fcb3f684e2fc1594c1e0f22a90d15398e5888143bd4144b5", - "sha256:cc86e6a9a390879dcc2976cef169dd9cc48843ed70b7380f321d1b118163c60e" + "sha256:70b638cf4743f33042bebb3b51e25261a0a10e80f978739f17e7fd4837664a66", + "sha256:9dfb63a2e871b807e3ba62f029813552a24b5289504f5b071dea9b041aee9fe4" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.5.10" + "version": "==1.5.13" }, "idna": { "hashes": [ - "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", - "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" + "sha256:5205d03e7bcbb919cc9c19885f9920d622ca52448306f2377daede5cf3faac16", + "sha256:c5b02147e01ea9920e6b0a3f1f7bb833612d507592c837a6c49552768f4054e1" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.10" + "version": "==3.1" }, "imagesize": { "hashes": [ "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1", "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.2.0" }, "jeepney": { @@ -688,19 +656,17 @@ }, "jinja2": { "hashes": [ - "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0", - "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035" + "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419", + "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==2.11.2" + "version": "==2.11.3" }, "keyring": { "hashes": [ - "sha256:1746d3ac913d449a090caf11e9e4af00e26c3f7f7e81027872192b2398b98675", - "sha256:4be9cbaaaf83e61d6399f733d113ede7d1c73bc75cb6aeb64eee0f6ac39b30ea" + "sha256:9acb3e1452edbb7544822b12fd25459078769e560fa51f418b6d00afaa6178df", + "sha256:9f44660a5d4931bdc14c08a1d01ef30b18a7a8147380710d8c9f9531e1f6c3c0" ], - "markers": "python_version >= '3.6'", - "version": "==21.8.0" + "version": "==22.0.1" }, "markupsafe": { "hashes": [ @@ -709,8 +675,12 @@ "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42", + "sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f", + "sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39", "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", + "sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014", + "sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f", "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", @@ -719,26 +689,40 @@ "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15", "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", + "sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85", + "sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1", "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", + "sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850", + "sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0", "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", + "sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb", "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", + "sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1", + "sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2", "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", + "sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7", "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", + "sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8", "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", + "sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193", "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", + "sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b", "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2", + "sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5", + "sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c", + "sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032", "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7", - "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be" + "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be", + "sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.1.1" }, "mccabe": { @@ -788,7 +772,6 @@ "sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281", "sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80" ], - "markers": "python_version >= '3.6'", "version": "==5.1.0" }, "mypy": { @@ -828,11 +811,10 @@ }, "packaging": { "hashes": [ - "sha256:24e0da08660a87484d1602c30bb4902d74816b6985b93de36926f5bc95741858", - "sha256:78598185a7008a470d64526a8059de9aaa449238f280fc9eb6b13ba6c4109093" + "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5", + "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==20.8" + "version": "==20.9" }, "pathspec": { "hashes": [ @@ -844,10 +826,10 @@ }, "pkginfo": { "hashes": [ - "sha256:a6a4ac943b496745cec21f14f021bbd869d5e9b4f6ec06918cffea5a2f4b9193", - "sha256:ce14d7296c673dc4c61c759a0b6c14bae34e34eb819c0017bb6ca5b7292c56e9" + "sha256:029a70cb45c6171c329dfc890cde0879f8c52d6f3922794796e06f577bb03db4", + "sha256:9fdbea6495622e022cc72c2e5e1b735218e4ffb2a2a69cde2694a6c1f16afb75" ], - "version": "==1.6.1" + "version": "==1.7.0" }, "pre-commit": { "hashes": [ @@ -862,7 +844,6 @@ "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367", "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.6.0" }, "pycparser": { @@ -870,7 +851,6 @@ "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0", "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.20" }, "pyflakes": { @@ -878,49 +858,54 @@ "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92", "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.2.0" }, "pygments": { "hashes": [ - "sha256:ccf3acacf3782cbed4a989426012f1c535c9a90d3a7fc3f16d231b9372d2b716", - "sha256:f275b6c0909e5dafd2d6269a656aa90fa58ebf4a74f8fcf9053195d226b24a08" + "sha256:bc9591213a8f0e0ca1a5e68a479b4887fdc3e75d0774e5c71c31920c427de435", + "sha256:df49d09b498e83c1a73128295860250b0b7edd4c723a32e9bc0d295c7c2ec337" ], - "markers": "python_version >= '3.5'", - "version": "==2.7.3" + "version": "==2.7.4" }, "pyparsing": { "hashes": [ "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.4.7" }, "pytz": { "hashes": [ - "sha256:16962c5fb8db4a8f63a26646d8886e9d769b6c511543557bc84e9569fb9a9cb4", - "sha256:180befebb1927b16f6b57101720075a984c019ac16b1b7575673bea42c6c3da5" + "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da", + "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798" ], - "version": "==2020.5" + "version": "==2021.1" }, "pyyaml": { "hashes": [ - "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97", - "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76", - "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2", - "sha256:6034f55dab5fea9e53f436aa68fa3ace2634918e8b5994d82f3621c04ff5ed2e", - "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648", - "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf", - "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f", - "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2", - "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee", - "sha256:ad9c67312c84def58f3c04504727ca879cb0013b2517c85a9a253f0cb6380c0a", - "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d", - "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c", - "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a" - ], - "version": "==5.3.1" + "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf", + "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696", + "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393", + "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77", + "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922", + "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5", + "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8", + "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10", + "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc", + "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018", + "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e", + "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253", + "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183", + "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb", + "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185", + "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db", + "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46", + "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b", + "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63", + "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df", + "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc" + ], + "version": "==5.4.1" }, "readme-renderer": { "hashes": [ @@ -990,7 +975,6 @@ "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==2.25.1" }, "requests-toolbelt": { @@ -1017,16 +1001,10 @@ }, "setuptools-scm": { "hashes": [ - "sha256:1fc4e25df445351d172bb4788f4d07f9e9ce0e8b7dee6b19584e46110172ca13", - "sha256:48b31488d089270500f120efea723968c01abd85fd4876043a3b7c7ef7d0b761", "sha256:62fa535edb31ece9fa65dc9dcb3056145b8020c8c26c0ef1018aef33db95c40d", - "sha256:b928021c4381f96d577847d540d6e03065f8f8851c768a0c9bc552d463bae0d4", - "sha256:c85b6b46d0edd40d2301038cdea96bb6adc14d62ef943e75afb08b3e7bcf142a", - "sha256:db4ab2e0c2644ba71b1e5212b14ff65dbf0af465796d314a75e0cf6128f605f7", - "sha256:e878036c2527dfd05818727846338be86b2be6955741b85fab2625f63d001021", - "sha256:eb19b46816fc106a4c2d4180022687eab40f9773cf61390b845afb093d1f4ecd" + "sha256:c85b6b46d0edd40d2301038cdea96bb6adc14d62ef943e75afb08b3e7bcf142a" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "index": "pypi", "version": "==5.0.1" }, "six": { @@ -1034,15 +1012,14 @@ "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.15.0" }, "snowballstemmer": { "hashes": [ - "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0", - "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52" + "sha256:b51b447bea85f9968c13b650126a888aabd4cb4463fca868ec596826325dedc2", + "sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914" ], - "version": "==2.0.0" + "version": "==2.1.0" }, "sphinx": { "hashes": [ @@ -1057,7 +1034,6 @@ "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a", "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58" ], - "markers": "python_version >= '3.5'", "version": "==1.0.2" }, "sphinxcontrib-devhelp": { @@ -1065,7 +1041,6 @@ "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e", "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4" ], - "markers": "python_version >= '3.5'", "version": "==1.0.2" }, "sphinxcontrib-htmlhelp": { @@ -1073,7 +1048,6 @@ "sha256:3c0bc24a2c41e340ac37c85ced6dafc879ab485c095b1d65d2461ac2f7cca86f", "sha256:e8f5bb7e31b2dbb25b9cc435c8ab7a79787ebf7f906155729338f3156d93659b" ], - "markers": "python_version >= '3.5'", "version": "==1.0.3" }, "sphinxcontrib-jsmath": { @@ -1081,7 +1055,6 @@ "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8" ], - "markers": "python_version >= '3.5'", "version": "==1.0.1" }, "sphinxcontrib-qthelp": { @@ -1089,7 +1062,6 @@ "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72", "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6" ], - "markers": "python_version >= '3.5'", "version": "==1.0.3" }, "sphinxcontrib-serializinghtml": { @@ -1097,7 +1069,6 @@ "sha256:eaa0eccc86e982a9b939b2b82d12cc5d013385ba5eadcc7e4fed23f4405f77bc", "sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a" ], - "markers": "python_version >= '3.5'", "version": "==1.1.4" }, "toml": { @@ -1110,11 +1081,10 @@ }, "tqdm": { "hashes": [ - "sha256:0cd81710de29754bf17b6fee07bdb86f956b4fa20d3078f02040f83e64309416", - "sha256:f4f80b96e2ceafea69add7bf971b8403b9cba8fb4451c1220f91c79be4ebd208" + "sha256:4621f6823bab46a9cc33d48105753ccbea671b68bab2c50a9f0be23d4065cb5a", + "sha256:fe3d08dd00a526850568d542ff9de9bbc2a09a791da3c334f3213d8d0bbbca65" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==4.55.0" + "version": "==4.56.0" }, "twine": { "hashes": [ @@ -1167,25 +1137,21 @@ "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f" ], "index": "pypi", - "python_version <": "3.8", - "version": "==3.7.4.3", - "version >=": "3.7.4" + "version": "==3.7.4.3" }, "urllib3": { "hashes": [ - "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08", - "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473" + "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80", + "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.26.2" + "version": "==1.26.3" }, "virtualenv": { "hashes": [ - "sha256:54b05fc737ea9c9ee9f8340f579e5da5b09fb64fd010ab5757eb90268616907c", - "sha256:b7a8ec323ee02fb2312f098b6b4c9de99559b462775bc8fe3627a73706603c1b" + "sha256:147b43894e51dd6bba882cf9c282447f780e2251cd35172403745fc381a0a80d", + "sha256:2be72df684b74df0ea47679a7df93fd0e04e72520022c57b479d8f881485dbe3" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==20.2.2" + "version": "==20.4.2" }, "webencodings": { "hashes": [ @@ -1242,7 +1208,6 @@ "sha256:f0b059678fd549c66b89bed03efcabb009075bd131c248ecdf087bdb6faba24a", "sha256:fcbb48a93e8699eae920f8d92f7160c03567b421bc17362a9ffbbd706a816f71" ], - "markers": "python_version >= '3.6'", "version": "==1.6.3" } } From 3fca540d05a0f0b4480cfcce84d7e0392270b841 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 4 Feb 2021 13:03:42 -0800 Subject: [PATCH 04/54] speed up cache by approximately 42x by avoiding pathlib (#1953) --- CHANGES.md | 2 ++ src/black/__init__.py | 14 +++++++++----- tests/test_black.py | 39 +++++++++++++++++++++------------------ 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index ca8a0472a3b..5f7ca4f4da7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -26,6 +26,8 @@ - use lowercase hex strings (#1692) +- speed up caching by avoiding pathlib (#1950) + #### _Packaging_ - Self-contained native _Black_ binaries are now provided for releases via GitHub diff --git a/src/black/__init__.py b/src/black/__init__.py index 9034bf6cf77..7c1a013aae3 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -93,7 +93,7 @@ Timestamp = float FileSize = int CacheInfo = Tuple[Timestamp, FileSize] -Cache = Dict[Path, CacheInfo] +Cache = Dict[str, CacheInfo] out = partial(click.secho, bold=True, err=True) err = partial(click.secho, fg="red", err=True) @@ -724,7 +724,8 @@ def reformat_one( if write_back not in (WriteBack.DIFF, WriteBack.COLOR_DIFF): cache = read_cache(mode) res_src = src.resolve() - if res_src in cache and cache[res_src] == get_cache_info(res_src): + res_src_s = str(res_src) + if res_src_s in cache and cache[res_src_s] == get_cache_info(res_src): changed = Changed.CACHED if changed is not Changed.CACHED and format_file_in_place( src, fast=fast, write_back=write_back, mode=mode @@ -6781,8 +6782,8 @@ def filter_cached(cache: Cache, sources: Iterable[Path]) -> Tuple[Set[Path], Set """ todo, done = set(), set() for src in sources: - src = src.resolve() - if cache.get(src) != get_cache_info(src): + res_src = src.resolve() + if cache.get(str(res_src)) != get_cache_info(res_src): todo.add(src) else: done.add(src) @@ -6794,7 +6795,10 @@ def write_cache(cache: Cache, sources: Iterable[Path], mode: Mode) -> None: cache_file = get_cache_file(mode) try: CACHE_DIR.mkdir(parents=True, exist_ok=True) - new_cache = {**cache, **{src.resolve(): get_cache_info(src) for src in sources}} + new_cache = { + **cache, + **{str(src.resolve()): get_cache_info(src) for src in sources}, + } with tempfile.NamedTemporaryFile(dir=str(cache_file.parent), delete=False) as f: pickle.dump(new_cache, f, protocol=4) os.replace(f.name, cache_file) diff --git a/tests/test_black.py b/tests/test_black.py index 28b75787bd6..cfd3cbd91b3 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -1003,7 +1003,7 @@ def test_cache_broken_file(self) -> None: fobj.write("print('hello')") self.invokeBlack([str(src)]) cache = black.read_cache(mode) - self.assertIn(src, cache) + self.assertIn(str(src), cache) def test_cache_single_file_already_cached(self) -> None: mode = DEFAULT_MODE @@ -1035,8 +1035,8 @@ def test_cache_multiple_files(self) -> None: with two.open("r") as fobj: self.assertEqual(fobj.read(), 'print("hello")\n') cache = black.read_cache(mode) - self.assertIn(one, cache) - self.assertIn(two, cache) + self.assertIn(str(one), cache) + self.assertIn(str(two), cache) def test_no_cache_when_writeback_diff(self) -> None: mode = DEFAULT_MODE @@ -1116,8 +1116,8 @@ def test_write_cache_read_cache(self) -> None: src.touch() black.write_cache({}, [src], mode) cache = black.read_cache(mode) - self.assertIn(src, cache) - self.assertEqual(cache[src], black.get_cache_info(src)) + self.assertIn(str(src), cache) + self.assertEqual(cache[str(src)], black.get_cache_info(src)) def test_filter_cached(self) -> None: with TemporaryDirectory() as workspace: @@ -1128,7 +1128,10 @@ def test_filter_cached(self) -> None: uncached.touch() cached.touch() cached_but_changed.touch() - cache = {cached: black.get_cache_info(cached), cached_but_changed: (0.0, 0)} + cache = { + str(cached): black.get_cache_info(cached), + str(cached_but_changed): (0.0, 0), + } todo, done = black.filter_cached( cache, {uncached, cached, cached_but_changed} ) @@ -1156,8 +1159,8 @@ def test_failed_formatting_does_not_get_cached(self) -> None: fobj.write('print("hello")\n') self.invokeBlack([str(workspace)], exit_code=123) cache = black.read_cache(mode) - self.assertNotIn(failing, cache) - self.assertIn(clean, cache) + self.assertNotIn(str(failing), cache) + self.assertIn(str(clean), cache) def test_write_cache_write_fail(self) -> None: mode = DEFAULT_MODE @@ -1210,9 +1213,9 @@ def test_read_cache_line_lengths(self) -> None: path.touch() black.write_cache({}, [path], mode) one = black.read_cache(mode) - self.assertIn(path, one) + self.assertIn(str(path), one) two = black.read_cache(short_mode) - self.assertNotIn(path, two) + self.assertNotIn(str(path), two) def test_single_file_force_pyi(self) -> None: pyi_mode = replace(DEFAULT_MODE, is_pyi=True) @@ -1226,9 +1229,9 @@ def test_single_file_force_pyi(self) -> None: actual = fh.read() # verify cache with --pyi is separate pyi_cache = black.read_cache(pyi_mode) - self.assertIn(path, pyi_cache) + self.assertIn(str(path), pyi_cache) normal_cache = black.read_cache(DEFAULT_MODE) - self.assertNotIn(path, normal_cache) + self.assertNotIn(str(path), normal_cache) self.assertFormatEqual(expected, actual) black.assert_equivalent(contents, actual) black.assert_stable(contents, actual, pyi_mode) @@ -1255,8 +1258,8 @@ def test_multi_file_force_pyi(self) -> None: pyi_cache = black.read_cache(pyi_mode) normal_cache = black.read_cache(reg_mode) for path in paths: - self.assertIn(path, pyi_cache) - self.assertNotIn(path, normal_cache) + self.assertIn(str(path), pyi_cache) + self.assertNotIn(str(path), normal_cache) def test_pipe_force_pyi(self) -> None: source, expected = read_data("force_pyi") @@ -1280,9 +1283,9 @@ def test_single_file_force_py36(self) -> None: actual = fh.read() # verify cache with --target-version is separate py36_cache = black.read_cache(py36_mode) - self.assertIn(path, py36_cache) + self.assertIn(str(path), py36_cache) normal_cache = black.read_cache(reg_mode) - self.assertNotIn(path, normal_cache) + self.assertNotIn(str(path), normal_cache) self.assertEqual(actual, expected) @event_loop() @@ -1307,8 +1310,8 @@ def test_multi_file_force_py36(self) -> None: pyi_cache = black.read_cache(py36_mode) normal_cache = black.read_cache(reg_mode) for path in paths: - self.assertIn(path, pyi_cache) - self.assertNotIn(path, normal_cache) + self.assertIn(str(path), pyi_cache) + self.assertNotIn(str(path), normal_cache) def test_pipe_force_py36(self) -> None: source, expected = read_data("force_py36") From aebd3c37b28bbc0183a58d13b80e7595db3c09bb Mon Sep 17 00:00:00 2001 From: Richard Si <63936253+ichard26@users.noreply.github.com> Date: Thu, 4 Feb 2021 23:10:45 -0500 Subject: [PATCH 05/54] Update prettier in pre-commit config (#1966) With older versions of prettier, when the hook failed a bunch of "[error] No parser could be inferred for file: {PATH}" error lines showed up because of lack of support of a flag that pre-commit passes for us by default. It made figuring out why the prettier hook failed annoying. --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9955a24baf8..292ed5727d9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,7 +25,7 @@ repos: exclude: ^docs/conf.py - repo: https://github.com/pre-commit/mirrors-prettier - rev: v1.19.1 + rev: v2.2.1 hooks: - id: prettier args: [--prose-wrap=always, --print-width=88] From 1c364f42ee298251d009e39fcab5ecc8cd0384d6 Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 10 Feb 2021 01:10:02 +0000 Subject: [PATCH 06/54] Regenerate documentation (#1980) Resolves #1979 and ensures that the content from #1861 is included in the repository-published documentation. --- docs/installation_and_usage.md | 5 ----- docs/pyproject_toml.md | 7 ++++--- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/docs/installation_and_usage.md b/docs/installation_and_usage.md index e3b53fd076e..ee45c934da8 100644 --- a/docs/installation_and_usage.md +++ b/docs/installation_and_usage.md @@ -100,11 +100,6 @@ Options: respect --force-exclude option on some editors that rely on using stdin. - --stdin-filename TEXT The name of the file when passing it through - stdin. Useful to make sure Black will respect - --force-exclude option on some editors that - rely on using stdin. - -q, --quiet Don't emit non-error messages to stderr. Errors are still emitted; silence those with 2>/dev/null. diff --git a/docs/pyproject_toml.md b/docs/pyproject_toml.md index cd313452b1e..453f533bf96 100644 --- a/docs/pyproject_toml.md +++ b/docs/pyproject_toml.md @@ -55,9 +55,10 @@ line-length = 88 target-version = ['py37'] include = '\.pyi?$' exclude = ''' - -( - /( +# A regex preceded with ^/ will apply only to files and directories +# in the root of the project. +^/( + ( \.eggs # exclude a few common directories in the | \.git # root of the project | \.hg From 2d0c14989dca41676fc83fb36f2d652cf93fad58 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Feb 2021 18:17:23 -0800 Subject: [PATCH 07/54] Bump cryptography from 3.3.1 to 3.3.2 (#1981) Bumps [cryptography](https://github.com/pyca/cryptography) from 3.3.1 to 3.3.2. - [Release notes](https://github.com/pyca/cryptography/releases) - [Changelog](https://github.com/pyca/cryptography/blob/master/CHANGELOG.rst) - [Commits](https://github.com/pyca/cryptography/compare/3.3.1...3.3.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Pipfile.lock | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 44e987de0e4..9aa2d0e7ce8 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -425,7 +425,6 @@ "sha256:6123ddc1052673e52bab52cdc955bcb57a015264a1c57d37bea2f6b817af0125", "sha256:98b3170739e5e83dd9dc19633f074727ad848cbedb6026708c8ac2d3b697a433" ], - "index": "pypi", "version": "==3.3.0" }, "certifi": { @@ -570,22 +569,23 @@ }, "cryptography": { "hashes": [ - "sha256:0003a52a123602e1acee177dc90dd201f9bb1e73f24a070db7d36c588e8f5c7d", - "sha256:0e85aaae861d0485eb5a79d33226dd6248d2a9f133b81532c8f5aae37de10ff7", - "sha256:594a1db4511bc4d960571536abe21b4e5c3003e8750ab8365fafce71c5d86901", - "sha256:69e836c9e5ff4373ce6d3ab311c1a2eed274793083858d3cd4c7d12ce20d5f9c", - "sha256:788a3c9942df5e4371c199d10383f44a105d67d401fb4304178020142f020244", - "sha256:7e177e4bea2de937a584b13645cab32f25e3d96fc0bc4a4cf99c27dc77682be6", - "sha256:83d9d2dfec70364a74f4e7c70ad04d3ca2e6a08b703606993407bf46b97868c5", - "sha256:84ef7a0c10c24a7773163f917f1cb6b4444597efd505a8aed0a22e8c4780f27e", - "sha256:9e21301f7a1e7c03dbea73e8602905a4ebba641547a462b26dd03451e5769e7c", - "sha256:9f6b0492d111b43de5f70052e24c1f0951cb9e6022188ebcb1cc3a3d301469b0", - "sha256:a69bd3c68b98298f490e84519b954335154917eaab52cf582fa2c5c7efc6e812", - "sha256:b4890d5fb9b7a23e3bf8abf5a8a7da8e228f1e97dc96b30b95685df840b6914a", - "sha256:c366df0401d1ec4e548bebe8f91d55ebcc0ec3137900d214dd7aac8427ef3030", - "sha256:dc42f645f8f3a489c3dd416730a514e7a91a59510ddaadc09d04224c098d3302" + "sha256:0d7b69674b738068fa6ffade5c962ecd14969690585aaca0a1b1fc9058938a72", + "sha256:1bd0ccb0a1ed775cd7e2144fe46df9dc03eefd722bbcf587b3e0616ea4a81eff", + "sha256:3c284fc1e504e88e51c428db9c9274f2da9f73fdf5d7e13a36b8ecb039af6e6c", + "sha256:49570438e60f19243e7e0d504527dd5fe9b4b967b5a1ff21cc12b57602dd85d3", + "sha256:541dd758ad49b45920dda3b5b48c968f8b2533d8981bcdb43002798d8f7a89ed", + "sha256:5a60d3780149e13b7a6ff7ad6526b38846354d11a15e21068e57073e29e19bed", + "sha256:7951a966613c4211b6612b0352f5bf29989955ee592c4a885d8c7d0f830d0433", + "sha256:922f9602d67c15ade470c11d616f2b2364950602e370c76f0c94c94ae672742e", + "sha256:a0f0b96c572fc9f25c3f4ddbf4688b9b38c69836713fb255f4a2715d93cbaf44", + "sha256:a777c096a49d80f9d2979695b835b0f9c9edab73b59e4ceb51f19724dda887ed", + "sha256:a9a4ac9648d39ce71c2f63fe7dc6db144b9fa567ddfc48b9fde1b54483d26042", + "sha256:aa4969f24d536ae2268c902b2c3d62ab464b5a66bcb247630d208a79a8098e9b", + "sha256:c7390f9b2119b2b43160abb34f63277a638504ef8df99f11cb52c1fda66a2e6f", + "sha256:e18e6ab84dfb0ab997faf8cca25a86ff15dfea4027b986322026cc99e0a892da" ], - "version": "==3.3.1" + "index": "pypi", + "version": "==3.3.2" }, "distlib": { "hashes": [ @@ -993,11 +993,11 @@ }, "secretstorage": { "hashes": [ - "sha256:30cfdef28829dad64d6ea1ed08f8eff6aa115a77068926bcc9f5225d5a3246aa", - "sha256:5c36f6537a523ec5f969ef9fad61c98eb9e017bc601d811e53aa25bece64892f" + "sha256:422d82c36172d88d6a0ed5afdec956514b189ddbfb72fefab0c8a1cee4eaf71f", + "sha256:fd666c51a6bf200643495a04abb261f83229dcb6fd8472ec393df7ffc8b6f195" ], "markers": "sys_platform == 'linux'", - "version": "==3.3.0" + "version": "==3.3.1" }, "setuptools-scm": { "hashes": [ @@ -1081,10 +1081,10 @@ }, "tqdm": { "hashes": [ - "sha256:4621f6823bab46a9cc33d48105753ccbea671b68bab2c50a9f0be23d4065cb5a", - "sha256:fe3d08dd00a526850568d542ff9de9bbc2a09a791da3c334f3213d8d0bbbca65" + "sha256:2874fa525c051177583ec59c0fb4583e91f28ccd3f217ffad2acdb32d2c789ac", + "sha256:ab9b659241d82b8b51b2269ee243ec95286046bf06015c4e15a947cc15914211" ], - "version": "==4.56.0" + "version": "==4.56.1" }, "twine": { "hashes": [ From b8c1020b526b488a1a216d9a4d58fc8616b61a99 Mon Sep 17 00:00:00 2001 From: James Addison Date: Thu, 11 Feb 2021 20:11:42 +0000 Subject: [PATCH 08/54] Stability fixup: interaction between newlines and comments (#1975) * Add test case to illustrate the issue * Accept carriage returns as valid separators while enumerating comments Without this acceptance, escaped multi-line statments that use carriage returns will not be counted into the 'ignored_lines' variable since the emitted line values will end with a CR and not an escape character. That leads to comments associated with the line being incorrectly labeled with the STANDALONE_COMMENT type, affecting comment placement and line space management. * Remove comment linking to ephemeral build log --- src/black/__init__.py | 2 +- tests/test_black.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/black/__init__.py b/src/black/__init__.py index 7c1a013aae3..6dbb765cf7a 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -2635,7 +2635,7 @@ def list_comments(prefix: str, *, is_endmarker: bool) -> List[ProtoComment]: consumed = 0 nlines = 0 ignored_lines = 0 - for index, line in enumerate(prefix.split("\n")): + for index, line in enumerate(re.split("\r?\n", prefix)): consumed += len(line) + 1 # adding the length of the split '\n' line = line.lstrip() if not line: diff --git a/tests/test_black.py b/tests/test_black.py index cfd3cbd91b3..a2efef82422 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -1793,6 +1793,11 @@ def test_bpo_33660_workaround(self) -> None: finally: os.chdir(str(old_cwd)) + def test_newline_comment_interaction(self) -> None: + source = "class A:\\\r\n# type: ignore\n pass\n" + output = black.format_str(source, mode=DEFAULT_MODE) + black.assert_stable(source, output, mode=DEFAULT_MODE) + with open(black.__file__, "r", encoding="utf-8") as _bf: black_source_lines = _bf.readlines() From 76268ab0c9b4e4d030b2d16272bfbdcad5172aad Mon Sep 17 00:00:00 2001 From: Richard Si <63936253+ichard26@users.noreply.github.com> Date: Sun, 14 Feb 2021 10:23:47 -0500 Subject: [PATCH 09/54] Fix duplication of checks on internal PRs (#1986) Internal PRs (that come from branches of psf/black) match both the push and pull_request events. This leads to a duplication of test, lint, etc. checks on such PRs. Not only is it a waste of resources, it makes the Status Checks UI more frustrating to go through. Patch taken from: https://github.community/t/duplicate-checks-on-push-and-pull-request-simultaneous-event/18012 --- .github/workflows/doc.yml | 8 +++++++- .github/workflows/fuzz.yml | 7 +++++++ .github/workflows/lint.yml | 7 +++++++ .github/workflows/primer.yml | 7 +++++++ .github/workflows/test.yml | 7 +++++++ 5 files changed, 35 insertions(+), 1 deletion(-) diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index d266e55aa02..930b6d440ff 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -16,8 +16,14 @@ on: jobs: build: - runs-on: ubuntu-latest + # We want to run on external PRs, but not on our own internal PRs as they'll be run + # by the push to the branch. Without this if check, checks are duplicated since + # internal PRs match both the push and pull_request events. + if: + github.event_name == 'push' || github.event.pull_request.head.repo.full_name != + github.repository + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index 0153767509a..f3b688f3ef6 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -4,6 +4,13 @@ on: [push, pull_request] jobs: build: + # We want to run on external PRs, but not on our own internal PRs as they'll be run + # by the push to the branch. Without this if check, checks are duplicated since + # internal PRs match both the push and pull_request events. + if: + github.event_name == 'push' || github.event.pull_request.head.repo.full_name != + github.repository + runs-on: ubuntu-latest strategy: fail-fast: false diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index fa7286eec1f..e01e9ade5e2 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -4,6 +4,13 @@ on: [push, pull_request] jobs: build: + # We want to run on external PRs, but not on our own internal PRs as they'll be run + # by the push to the branch. Without this if check, checks are duplicated since + # internal PRs match both the push and pull_request events. + if: + github.event_name == 'push' || github.event.pull_request.head.repo.full_name != + github.repository + runs-on: ubuntu-latest strategy: matrix: diff --git a/.github/workflows/primer.yml b/.github/workflows/primer.yml index b623b938345..4c5751ae996 100644 --- a/.github/workflows/primer.yml +++ b/.github/workflows/primer.yml @@ -4,6 +4,13 @@ on: [push, pull_request] jobs: build: + # We want to run on external PRs, but not on our own internal PRs as they'll be run + # by the push to the branch. Without this if check, checks are duplicated since + # internal PRs match both the push and pull_request events. + if: + github.event_name == 'push' || github.event.pull_request.head.repo.full_name != + github.repository + runs-on: ${{ matrix.os }} strategy: fail-fast: false diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8dd4e4f59fd..bec769064c2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,6 +4,13 @@ on: [push, pull_request] jobs: build: + # We want to run on external PRs, but not on our own internal PRs as they'll be run + # by the push to the branch. Without this if check, checks are duplicated since + # internal PRs match both the push and pull_request events. + if: + github.event_name == 'push' || github.event.pull_request.head.repo.full_name != + github.repository + runs-on: ${{ matrix.os }} strategy: fail-fast: false From 3a309a36fcfc30a96a7fdd68b6b2c3aa2aa5341c Mon Sep 17 00:00:00 2001 From: rht Date: Sun, 14 Feb 2021 10:32:29 -0500 Subject: [PATCH 10/54] readme: Include Zulip in used-by section (#1987) Zulip has recently formatted their code in Black and also set Black as a linter: https://github.com/zulip/zulip/pull/15662. See also https://chat.zulip.org/#narrow/stream/2-general/topic/black. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 83ecb89d6c9..97df938eab2 100644 --- a/README.md +++ b/README.md @@ -454,7 +454,7 @@ then write the above files to `.cache/black//`. The following notable open-source projects trust _Black_ with enforcing a consistent code style: pytest, tox, Pyramid, Django Channels, Hypothesis, attrs, SQLAlchemy, Poetry, PyPA applications (Warehouse, Bandersnatch, Pipenv, virtualenv), pandas, Pillow, -every Datadog Agent Integration, Home Assistant. +every Datadog Agent Integration, Home Assistant, Zulip. The following organizations use _Black_: Facebook, Dropbox, Mozilla, Quora. From 6a105e019fcaa10cc0b6fb59edea4a4018eac97e Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Mon, 15 Feb 2021 18:02:48 +0200 Subject: [PATCH 11/54] Add "# fmt: skip" directive to black (#1800) Fixes #1162 --- README.md | 5 +- src/black/__init__.py | 104 +++++++++++++++++++++++++---------------- tests/data/fmtskip.py | 3 ++ tests/data/fmtskip2.py | 17 +++++++ tests/data/fmtskip3.py | 20 ++++++++ tests/data/fmtskip4.py | 13 ++++++ tests/data/fmtskip5.py | 22 +++++++++ tests/test_format.py | 5 ++ 8 files changed, 147 insertions(+), 42 deletions(-) create mode 100644 tests/data/fmtskip.py create mode 100644 tests/data/fmtskip2.py create mode 100644 tests/data/fmtskip3.py create mode 100644 tests/data/fmtskip4.py create mode 100644 tests/data/fmtskip5.py diff --git a/README.md b/README.md index 97df938eab2..89ef4271d41 100644 --- a/README.md +++ b/README.md @@ -239,8 +239,9 @@ feeling confident, use `--fast`. _Black_ is a PEP 8 compliant opinionated formatter. _Black_ reformats entire files in place. It is not configurable. It doesn't take previous formatting into account. Your main option of configuring _Black_ is that it doesn't reformat blocks that start with -`# fmt: off` and end with `# fmt: on`. `# fmt: on/off` have to be on the same level of -indentation. To learn more about _Black_'s opinions, to go +`# fmt: off` and end with `# fmt: on`, or lines that ends with `# fmt: skip`. Pay +attention that `# fmt: on/off` have to be on the same level of indentation. To learn +more about _Black_'s opinions, to go [the_black_code_style](https://github.com/psf/black/blob/master/docs/the_black_code_style.md). Please refer to this document before submitting an issue. What seems like a bug might be diff --git a/src/black/__init__.py b/src/black/__init__.py index 6dbb765cf7a..08930d11cea 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -2581,6 +2581,8 @@ def is_split_before_delimiter(leaf: Leaf, previous: Optional[Leaf] = None) -> Pr FMT_OFF = {"# fmt: off", "# fmt:off", "# yapf: disable"} +FMT_SKIP = {"# fmt: skip", "# fmt:skip"} +FMT_PASS = {*FMT_OFF, *FMT_SKIP} FMT_ON = {"# fmt: on", "# fmt:on", "# yapf: enable"} @@ -5404,58 +5406,80 @@ def convert_one_fmt_off_pair(node: Node) -> bool: for leaf in node.leaves(): previous_consumed = 0 for comment in list_comments(leaf.prefix, is_endmarker=False): - if comment.value in FMT_OFF: - # We only want standalone comments. If there's no previous leaf or - # the previous leaf is indentation, it's a standalone comment in - # disguise. - if comment.type != STANDALONE_COMMENT: - prev = preceding_leaf(leaf) - if prev and prev.type not in WHITESPACE: + if comment.value not in FMT_PASS: + previous_consumed = comment.consumed + continue + # We only want standalone comments. If there's no previous leaf or + # the previous leaf is indentation, it's a standalone comment in + # disguise. + if comment.value in FMT_PASS and comment.type != STANDALONE_COMMENT: + prev = preceding_leaf(leaf) + if prev: + if comment.value in FMT_OFF and prev.type not in WHITESPACE: + continue + if comment.value in FMT_SKIP and prev.type in WHITESPACE: continue - ignored_nodes = list(generate_ignored_nodes(leaf)) - if not ignored_nodes: - continue - - first = ignored_nodes[0] # Can be a container node with the `leaf`. - parent = first.parent - prefix = first.prefix - first.prefix = prefix[comment.consumed :] - hidden_value = ( - comment.value + "\n" + "".join(str(n) for n in ignored_nodes) - ) - if hidden_value.endswith("\n"): - # That happens when one of the `ignored_nodes` ended with a NEWLINE - # leaf (possibly followed by a DEDENT). - hidden_value = hidden_value[:-1] - first_idx: Optional[int] = None - for ignored in ignored_nodes: - index = ignored.remove() - if first_idx is None: - first_idx = index - assert parent is not None, "INTERNAL ERROR: fmt: on/off handling (1)" - assert first_idx is not None, "INTERNAL ERROR: fmt: on/off handling (2)" - parent.insert_child( - first_idx, - Leaf( - STANDALONE_COMMENT, - hidden_value, - prefix=prefix[:previous_consumed] + "\n" * comment.newlines, - ), - ) - return True + ignored_nodes = list(generate_ignored_nodes(leaf, comment)) + if not ignored_nodes: + continue - previous_consumed = comment.consumed + first = ignored_nodes[0] # Can be a container node with the `leaf`. + parent = first.parent + prefix = first.prefix + first.prefix = prefix[comment.consumed :] + hidden_value = "".join(str(n) for n in ignored_nodes) + if comment.value in FMT_OFF: + hidden_value = comment.value + "\n" + hidden_value + if comment.value in FMT_SKIP: + hidden_value += " " + comment.value + if hidden_value.endswith("\n"): + # That happens when one of the `ignored_nodes` ended with a NEWLINE + # leaf (possibly followed by a DEDENT). + hidden_value = hidden_value[:-1] + first_idx: Optional[int] = None + for ignored in ignored_nodes: + index = ignored.remove() + if first_idx is None: + first_idx = index + assert parent is not None, "INTERNAL ERROR: fmt: on/off handling (1)" + assert first_idx is not None, "INTERNAL ERROR: fmt: on/off handling (2)" + parent.insert_child( + first_idx, + Leaf( + STANDALONE_COMMENT, + hidden_value, + prefix=prefix[:previous_consumed] + "\n" * comment.newlines, + ), + ) + return True return False -def generate_ignored_nodes(leaf: Leaf) -> Iterator[LN]: +def generate_ignored_nodes(leaf: Leaf, comment: ProtoComment) -> Iterator[LN]: """Starting from the container of `leaf`, generate all leaves until `# fmt: on`. + If comment is skip, returns leaf only. Stops at the end of the block. """ container: Optional[LN] = container_of(leaf) + if comment.value in FMT_SKIP: + prev_sibling = leaf.prev_sibling + if comment.value in leaf.prefix and prev_sibling is not None: + leaf.prefix = leaf.prefix.replace(comment.value, "") + siblings = [prev_sibling] + while ( + "\n" not in prev_sibling.prefix + and prev_sibling.prev_sibling is not None + ): + prev_sibling = prev_sibling.prev_sibling + siblings.insert(0, prev_sibling) + for sibling in siblings: + yield sibling + elif leaf.parent is not None: + yield leaf.parent + return while container is not None and container.type != token.ENDMARKER: if is_fmt_on(container): return diff --git a/tests/data/fmtskip.py b/tests/data/fmtskip.py new file mode 100644 index 00000000000..1d5836fc031 --- /dev/null +++ b/tests/data/fmtskip.py @@ -0,0 +1,3 @@ +a, b = 1, 2 +c = 6 # fmt: skip +d = 5 diff --git a/tests/data/fmtskip2.py b/tests/data/fmtskip2.py new file mode 100644 index 00000000000..e6248117aa9 --- /dev/null +++ b/tests/data/fmtskip2.py @@ -0,0 +1,17 @@ +l1 = ["This list should be broken up", "into multiple lines", "because it is way too long"] +l2 = ["But this list shouldn't", "even though it also has", "way too many characters in it"] # fmt: skip +l3 = ["I have", "trailing comma", "so I should be braked",] + +# output + +l1 = [ + "This list should be broken up", + "into multiple lines", + "because it is way too long", +] +l2 = ["But this list shouldn't", "even though it also has", "way too many characters in it"] # fmt: skip +l3 = [ + "I have", + "trailing comma", + "so I should be braked", +] \ No newline at end of file diff --git a/tests/data/fmtskip3.py b/tests/data/fmtskip3.py new file mode 100644 index 00000000000..6e166888e21 --- /dev/null +++ b/tests/data/fmtskip3.py @@ -0,0 +1,20 @@ +a = 3 +# fmt: off +b, c = 1, 2 +d = 6 # fmt: skip +e = 5 +# fmt: on +f = ["This is a very long line that should be formatted into a clearer line ", "by rearranging."] + +# output + +a = 3 +# fmt: off +b, c = 1, 2 +d = 6 # fmt: skip +e = 5 +# fmt: on +f = [ + "This is a very long line that should be formatted into a clearer line ", + "by rearranging.", +] diff --git a/tests/data/fmtskip4.py b/tests/data/fmtskip4.py new file mode 100644 index 00000000000..aadd77d0e53 --- /dev/null +++ b/tests/data/fmtskip4.py @@ -0,0 +1,13 @@ +a = 2 +# fmt: skip +l = [1, 2, 3,] + +# output + +a = 2 +# fmt: skip +l = [ + 1, + 2, + 3, +] \ No newline at end of file diff --git a/tests/data/fmtskip5.py b/tests/data/fmtskip5.py new file mode 100644 index 00000000000..d7b15e0ff41 --- /dev/null +++ b/tests/data/fmtskip5.py @@ -0,0 +1,22 @@ +a, b, c = 3, 4, 5 +if ( + a == 3 + and b != 9 # fmt: skip + and c is not None +): + print("I'm good!") +else: + print("I'm bad") + + +# output + +a, b, c = 3, 4, 5 +if ( + a == 3 + and b != 9 # fmt: skip + and c is not None +): + print("I'm good!") +else: + print("I'm bad") diff --git a/tests/test_format.py b/tests/test_format.py index e4677707e3c..e0cb0b74195 100644 --- a/tests/test_format.py +++ b/tests/test_format.py @@ -37,6 +37,11 @@ "fmtonoff2", "fmtonoff3", "fmtonoff4", + "fmtskip", + "fmtskip2", + "fmtskip3", + "fmtskip4", + "fmtskip5", "fstring", "function", "function2", From 71bbb678b9f3ad1b18eab9c967b39f22a0d19535 Mon Sep 17 00:00:00 2001 From: Archit Gopal <73956153+Architrixs@users.noreply.github.com> Date: Mon, 15 Feb 2021 21:35:23 +0530 Subject: [PATCH 12/54] add gedit integration (#1988) --- docs/editor_integration.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/editor_integration.md b/docs/editor_integration.md index 037b265b9a0..aa3a1eeedec 100644 --- a/docs/editor_integration.md +++ b/docs/editor_integration.md @@ -233,6 +233,36 @@ If you later want to update _Black_, you should do it like this: $ pip install -U black --no-binary regex,typed-ast ``` +## Gedit + +gedit is the default text editor of the GNOME, Unix like Operating Systems. Open gedit +as + +```console +$ gedit +``` + +1. `Go to edit > preferences > plugins` +2. Search for `external tools` and activate it. +3. In `Tools menu -> Manage external tools` +4. Add a new tool using `+` button. +5. Copy the below content to the code window. + +```console +#!/bin/bash +Name=$GEDIT_CURRENT_DOCUMENT_NAME +black $Name +``` + +- Set a keyboard shortcut if you like, Ex. `ctrl-B` +- Save: `Nothing` +- Input: `Nothing` +- Output: `Display in bottom pane` if you like. +- Change the name of the tool if you like. + +Use your keyboard shortcut or `Tools -> External Tools` to use your new tool. When you +close and reopen your File, _Black_ will be done with its job. + ## Visual Studio Code Use the From 97b8496d67741a10f30eefbb3d6c97a0e541fba4 Mon Sep 17 00:00:00 2001 From: Romain Rigaux Date: Tue, 16 Feb 2021 13:10:23 -0800 Subject: [PATCH 13/54] Use 'args' to Avoid GH workflow warning (#1990) Unexpected input(s) 'black_args', valid inputs are ['entryPoint', 'args'] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 89ef4271d41..178f763c32d 100644 --- a/README.md +++ b/README.md @@ -419,7 +419,7 @@ jobs: - uses: actions/setup-python@v2 - uses: psf/black@stable with: - black_args: ". --check" + args: ". --check" ``` ### Inputs From 306a513137ec93a5053d415319e24bd4057d4045 Mon Sep 17 00:00:00 2001 From: James Addison Date: Sat, 20 Feb 2021 16:44:48 +0000 Subject: [PATCH 14/54] fuzzer: add special-case for multi-line EOF TokenError (#1991) * Add special-case for multi-line EOF TokenError under Python3.7 * Update conditional check to correspond to original issue description (and include issue hyperlink) * Add warning and hint regarding replaying the fuzzer code generation * Include code review suggestion (with modifications for this to follow) Co-authored-by: Zac Hatfield-Dodds * Remove Python version check, since this issue does exist across more recent Python versions than 3.7 * Update explanatory comment * Add clarification for potentially-ambiguous blib2to3 import * Update explanatory comment * Bring comment into consistent format with previous comment * Revert "Add clarification for potentially-ambiguous blib2to3 import" This reverts commit 357b7cc03bdb19dd924f1accd428352f4bb44e5c. Co-authored-by: Zac Hatfield-Dodds --- fuzz.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/fuzz.py b/fuzz.py index 6330c58cc81..6e2068690b5 100644 --- a/fuzz.py +++ b/fuzz.py @@ -5,10 +5,13 @@ a coverage-guided fuzzer I'm working on. """ +import re + import hypothesmith from hypothesis import HealthCheck, given, settings, strategies as st import black +from blib2to3.pgen2.tokenize import TokenError # This test uses the Hypothesis and Hypothesmith libraries to generate random @@ -46,6 +49,16 @@ def test_idempotent_any_syntatically_valid_python( # able to cope with it. See issues #970, #1012, #1358, and #1557. # TODO: remove this try-except block when issues are resolved. return + except TokenError as e: + if ( + e.args[0] == "EOF in multi-line statement" + and re.search(r"\r?\n\\\r?\n", src_contents) is not None + ): + # This is a bug - if it's valid Python code, as above, Black should be + # able to cope with it. See issue #1012. + # TODO: remove this block when the issue is resolved. + return + raise # And check that we got equivalent and stable output. black.assert_equivalent(src_contents, dst_contents) From afc8c326bf97ce7a22e8fc0b8cc5ced1586ef022 Mon Sep 17 00:00:00 2001 From: James Addison Date: Thu, 4 Feb 2021 17:26:29 +0000 Subject: [PATCH 15/54] Brevity: rename method --- src/black/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/black/__init__.py b/src/black/__init__.py index 08930d11cea..e398ed04f43 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -5005,7 +5005,7 @@ def bracket_split_build_line( result.append(leaf, preformatted=True) for comment_after in original.comments_after(leaf): result.append(comment_after, preformatted=True) - if is_body and should_split_body_explode(result, opening_bracket): + if is_body and should_split(result, opening_bracket): result.should_explode = True return result @@ -5810,7 +5810,7 @@ def ensure_visible(leaf: Leaf) -> None: leaf.value = ")" -def should_split_body_explode(line: Line, opening_bracket: Leaf) -> bool: +def should_split(line: Line, opening_bracket: Leaf) -> bool: """Should `line` be immediately split with `delimiter_split()` after RHS?""" if not (opening_bracket.parent and opening_bracket.value in "[{("): From caa3fcc2de3cfb6162bee0bb6f68b10bc38e612f Mon Sep 17 00:00:00 2001 From: James Addison Date: Thu, 4 Feb 2021 17:30:05 +0000 Subject: [PATCH 16/54] Clarity: isolate and extract each responsibility from an overloaded variable --- src/black/__init__.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/black/__init__.py b/src/black/__init__.py index e398ed04f43..44017b59602 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -1481,6 +1481,7 @@ class Line: bracket_tracker: BracketTracker = field(default_factory=BracketTracker) inside_brackets: bool = False should_explode: bool = False + magic_trailing_comma: Optional[Leaf] = None def append(self, leaf: Leaf, preformatted: bool = False) -> None: """Add a new `leaf` to the end of the line. @@ -1508,7 +1509,7 @@ def append(self, leaf: Leaf, preformatted: bool = False) -> None: self.bracket_tracker.mark(leaf) if self.mode.magic_trailing_comma: if self.has_magic_trailing_comma(leaf): - self.should_explode = True + self.magic_trailing_comma = leaf elif self.has_magic_trailing_comma(leaf, ensure_removable=True): self.remove_trailing_comma() if not self.append_comment(leaf): @@ -1792,6 +1793,7 @@ def clone(self) -> "Line": depth=self.depth, inside_brackets=self.inside_brackets, should_explode=self.should_explode, + magic_trailing_comma=self.magic_trailing_comma, ) def __str__(self) -> str: @@ -2710,7 +2712,7 @@ def init_st(ST: Type[StringTransformer]) -> StringTransformer: transformers: List[Transformer] if ( not line.contains_uncollapsable_type_comments() - and not line.should_explode + and not (line.should_explode or line.magic_trailing_comma) and ( is_line_short_enough(line, line_length=mode.line_length, line_str=line_str) or line.contains_unsplittable_type_ignore() @@ -4385,6 +4387,7 @@ def do_transform(self, line: Line, string_idx: int) -> Iterator[TResult[Line]]: depth=line.depth + 1, inside_brackets=True, should_explode=line.should_explode, + magic_trailing_comma=line.magic_trailing_comma, ) string_leaf = Leaf(token.STRING, string_value) insert_str_child(string_leaf) @@ -5946,7 +5949,7 @@ def generate_trailers_to_omit(line: Line, line_length: int) -> Iterator[Set[Leaf """ omit: Set[LeafID] = set() - if not line.should_explode: + if not line.should_explode and not line.magic_trailing_comma: yield omit length = 4 * line.depth @@ -5968,7 +5971,7 @@ def generate_trailers_to_omit(line: Line, line_length: int) -> Iterator[Set[Leaf elif leaf.type in CLOSING_BRACKETS: prev = line.leaves[index - 1] if index > 0 else None if ( - line.should_explode + (line.should_explode or line.magic_trailing_comma) and prev and prev.type == token.COMMA and not is_one_tuple_between( @@ -5996,7 +5999,7 @@ def generate_trailers_to_omit(line: Line, line_length: int) -> Iterator[Set[Leaf yield omit if ( - line.should_explode + (line.should_explode or line.magic_trailing_comma) and prev and prev.type == token.COMMA and not is_one_tuple_between(leaf.opening_bracket, leaf, line.leaves) @@ -6629,7 +6632,7 @@ def can_omit_invisible_parens( penultimate = line.leaves[-2] last = line.leaves[-1] - if line.should_explode: + if line.should_explode or line.magic_trailing_comma: try: penultimate, last = last_two_except(line.leaves, omit=omit_on_explode) except LookupError: @@ -6656,7 +6659,9 @@ def can_omit_invisible_parens( # unnecessary. return True - if line.should_explode and penultimate.type == token.COMMA: + if ( + line.should_explode or line.magic_trailing_comma + ) and penultimate.type == token.COMMA: # The rightmost non-omitted bracket pair is the one we want to explode on. return True From a23f521fee1b283b10000d94267ef93069b7f7ec Mon Sep 17 00:00:00 2001 From: James Addison Date: Thu, 4 Feb 2021 17:37:25 +0000 Subject: [PATCH 17/54] Brevity: only use the variables required to convey the intended expressions --- src/black/__init__.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/black/__init__.py b/src/black/__init__.py index 44017b59602..67eef95390d 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -5971,7 +5971,7 @@ def generate_trailers_to_omit(line: Line, line_length: int) -> Iterator[Set[Leaf elif leaf.type in CLOSING_BRACKETS: prev = line.leaves[index - 1] if index > 0 else None if ( - (line.should_explode or line.magic_trailing_comma) + line.magic_trailing_comma and prev and prev.type == token.COMMA and not is_one_tuple_between( @@ -5999,7 +5999,7 @@ def generate_trailers_to_omit(line: Line, line_length: int) -> Iterator[Set[Leaf yield omit if ( - (line.should_explode or line.magic_trailing_comma) + line.magic_trailing_comma and prev and prev.type == token.COMMA and not is_one_tuple_between(leaf.opening_bracket, leaf, line.leaves) @@ -6659,9 +6659,7 @@ def can_omit_invisible_parens( # unnecessary. return True - if ( - line.should_explode or line.magic_trailing_comma - ) and penultimate.type == token.COMMA: + if line.magic_trailing_comma and penultimate.type == token.COMMA: # The rightmost non-omitted bracket pair is the one we want to explode on. return True From 51141f1af4aab0e0c7f71932ffe06482a884f1d5 Mon Sep 17 00:00:00 2001 From: James Addison Date: Thu, 4 Feb 2021 17:38:55 +0000 Subject: [PATCH 18/54] Consistency: use variable names that correspond to the methods they invoke --- src/black/__init__.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/black/__init__.py b/src/black/__init__.py index 67eef95390d..c836b2b46eb 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -1480,7 +1480,7 @@ class Line: comments: Dict[LeafID, List[Leaf]] = field(default_factory=dict) bracket_tracker: BracketTracker = field(default_factory=BracketTracker) inside_brackets: bool = False - should_explode: bool = False + should_split: bool = False magic_trailing_comma: Optional[Leaf] = None def append(self, leaf: Leaf, preformatted: bool = False) -> None: @@ -1792,7 +1792,7 @@ def clone(self) -> "Line": mode=self.mode, depth=self.depth, inside_brackets=self.inside_brackets, - should_explode=self.should_explode, + should_split=self.should_split, magic_trailing_comma=self.magic_trailing_comma, ) @@ -2712,7 +2712,7 @@ def init_st(ST: Type[StringTransformer]) -> StringTransformer: transformers: List[Transformer] if ( not line.contains_uncollapsable_type_comments() - and not (line.should_explode or line.magic_trailing_comma) + and not (line.should_split or line.magic_trailing_comma) and ( is_line_short_enough(line, line_length=mode.line_length, line_str=line_str) or line.contains_unsplittable_type_ignore() @@ -4386,7 +4386,7 @@ def do_transform(self, line: Line, string_idx: int) -> Iterator[TResult[Line]]: mode=line.mode, depth=line.depth + 1, inside_brackets=True, - should_explode=line.should_explode, + should_split=line.should_split, magic_trailing_comma=line.magic_trailing_comma, ) string_leaf = Leaf(token.STRING, string_value) @@ -5009,7 +5009,7 @@ def bracket_split_build_line( for comment_after in original.comments_after(leaf): result.append(comment_after, preformatted=True) if is_body and should_split(result, opening_bracket): - result.should_explode = True + result.should_split = True return result @@ -5949,7 +5949,7 @@ def generate_trailers_to_omit(line: Line, line_length: int) -> Iterator[Set[Leaf """ omit: Set[LeafID] = set() - if not line.should_explode and not line.magic_trailing_comma: + if not line.should_split and not line.magic_trailing_comma: yield omit length = 4 * line.depth @@ -6632,7 +6632,7 @@ def can_omit_invisible_parens( penultimate = line.leaves[-2] last = line.leaves[-1] - if line.should_explode or line.magic_trailing_comma: + if line.should_split or line.magic_trailing_comma: try: penultimate, last = last_two_except(line.leaves, omit=omit_on_explode) except LookupError: From 89c42a0011721e164738c17a192452ee77d9cc99 Mon Sep 17 00:00:00 2001 From: James Addison Date: Thu, 4 Feb 2021 17:40:42 +0000 Subject: [PATCH 19/54] Clarity: special case: avoid using variables that have the same names as methods --- src/black/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/black/__init__.py b/src/black/__init__.py index c836b2b46eb..7f727b18bf0 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -5008,7 +5008,7 @@ def bracket_split_build_line( result.append(leaf, preformatted=True) for comment_after in original.comments_after(leaf): result.append(comment_after, preformatted=True) - if is_body and should_split(result, opening_bracket): + if is_body and should_split_line(result, opening_bracket): result.should_split = True return result @@ -5813,7 +5813,7 @@ def ensure_visible(leaf: Leaf) -> None: leaf.value = ")" -def should_split(line: Line, opening_bracket: Leaf) -> bool: +def should_split_line(line: Line, opening_bracket: Leaf) -> bool: """Should `line` be immediately split with `delimiter_split()` after RHS?""" if not (opening_bracket.parent and opening_bracket.value in "[{("): From 829331a8777aa758c6fc2a5032d38d8fbb5b5ac6 Mon Sep 17 00:00:00 2001 From: James Addison Date: Thu, 4 Feb 2021 17:45:45 +0000 Subject: [PATCH 20/54] Simplification: only use special-case token retrieval logic when magic trailing comma is present --- src/black/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/black/__init__.py b/src/black/__init__.py index 7f727b18bf0..56f180ac8a6 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -6632,7 +6632,7 @@ def can_omit_invisible_parens( penultimate = line.leaves[-2] last = line.leaves[-1] - if line.should_split or line.magic_trailing_comma: + if line.magic_trailing_comma: try: penultimate, last = last_two_except(line.leaves, omit=omit_on_explode) except LookupError: From e0d766727dc87f5c5f39ef751d0bf23fc5ff31a0 Mon Sep 17 00:00:00 2001 From: James Addison Date: Thu, 4 Feb 2021 17:48:38 +0000 Subject: [PATCH 21/54] Simplification: only yield empty omit list when magic trailing comma is present --- src/black/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/black/__init__.py b/src/black/__init__.py index 56f180ac8a6..3eea33ced14 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -5949,7 +5949,7 @@ def generate_trailers_to_omit(line: Line, line_length: int) -> Iterator[Set[Leaf """ omit: Set[LeafID] = set() - if not line.should_split and not line.magic_trailing_comma: + if not line.magic_trailing_comma: yield omit length = 4 * line.depth From 24700806f681f2809a2b85999871e291c36dd948 Mon Sep 17 00:00:00 2001 From: James Addison Date: Thu, 4 Feb 2021 18:07:43 +0000 Subject: [PATCH 22/54] Cleanup: remove unused / redundant variables from conditionals --- src/black/__init__.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/black/__init__.py b/src/black/__init__.py index 3eea33ced14..c2a4bda6061 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -5971,8 +5971,7 @@ def generate_trailers_to_omit(line: Line, line_length: int) -> Iterator[Set[Leaf elif leaf.type in CLOSING_BRACKETS: prev = line.leaves[index - 1] if index > 0 else None if ( - line.magic_trailing_comma - and prev + prev and prev.type == token.COMMA and not is_one_tuple_between( leaf.opening_bracket, leaf, line.leaves @@ -5999,8 +5998,7 @@ def generate_trailers_to_omit(line: Line, line_length: int) -> Iterator[Set[Leaf yield omit if ( - line.magic_trailing_comma - and prev + prev and prev.type == token.COMMA and not is_one_tuple_between(leaf.opening_bracket, leaf, line.leaves) ): @@ -6659,7 +6657,7 @@ def can_omit_invisible_parens( # unnecessary. return True - if line.magic_trailing_comma and penultimate.type == token.COMMA: + if penultimate.type == token.COMMA: # The rightmost non-omitted bracket pair is the one we want to explode on. return True From 22127c633eba10d41519fb562c1252f859e2d7fa Mon Sep 17 00:00:00 2001 From: James Addison Date: Tue, 9 Feb 2021 21:13:57 +0000 Subject: [PATCH 23/54] Readability: reduce boolean nesting --- src/black/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/black/__init__.py b/src/black/__init__.py index c2a4bda6061..c2b0ad43fa8 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -2712,7 +2712,8 @@ def init_st(ST: Type[StringTransformer]) -> StringTransformer: transformers: List[Transformer] if ( not line.contains_uncollapsable_type_comments() - and not (line.should_split or line.magic_trailing_comma) + and not line.should_split + and not line.magic_trailing_comma and ( is_line_short_enough(line, line_length=mode.line_length, line_str=line_str) or line.contains_unsplittable_type_ignore() From 0cbe19c813559d6642e71832242264ab8d5a5d59 Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 10 Feb 2021 12:33:50 +0000 Subject: [PATCH 24/54] Minimize changes: more closely resemble original conditional logic --- src/black/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/black/__init__.py b/src/black/__init__.py index c2b0ad43fa8..0b734adca56 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -6658,7 +6658,7 @@ def can_omit_invisible_parens( # unnecessary. return True - if penultimate.type == token.COMMA: + if line.magic_trailing_comma and penultimate.type == token.COMMA: # The rightmost non-omitted bracket pair is the one we want to explode on. return True From cd4295dd9888f491cfd9aae060d7832b7f831b24 Mon Sep 17 00:00:00 2001 From: "Paul \"TBBle\" Hampson" Date: Mon, 22 Feb 2021 17:43:23 +1100 Subject: [PATCH 25/54] Indicate that a final newline was added in --diff (#1897) (#1897) Fixes: #1662 Work-around for https://bugs.python.org/issue2142 The test has to slightly mess with its input data, because the utility functions default to ensuring the test data has a final newline, which defeats the point of the test. Signed-off-by: Paul "TBBle" Hampson --- CHANGES.md | 2 ++ docs/authors.md | 1 + src/black/__init__.py | 23 ++++++++++++++++------- tests/data/missing_final_newline.diff | 8 ++++++++ tests/data/missing_final_newline.py | 3 +++ tests/test_black.py | 23 ++++++++++++++++++++++- 6 files changed, 52 insertions(+), 8 deletions(-) create mode 100644 tests/data/missing_final_newline.diff create mode 100644 tests/data/missing_final_newline.py diff --git a/CHANGES.md b/CHANGES.md index 5f7ca4f4da7..3fd7ad40496 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -28,6 +28,8 @@ - speed up caching by avoiding pathlib (#1950) +- `--diff` correctly indicates when a file doesn't end in a newline (#1662) + #### _Packaging_ - Self-contained native _Black_ binaries are now provided for releases via GitHub diff --git a/docs/authors.md b/docs/authors.md index cdf5046c446..9f2ea0571b9 100644 --- a/docs/authors.md +++ b/docs/authors.md @@ -132,6 +132,7 @@ Multiple contributions by: - [Pablo Galindo](mailto:Pablogsal@gmail.com) - [Paul Ganssle](mailto:p.ganssle@gmail.com) - [Paul Meinhardt](mailto:mnhrdt@gmail.com) +- [Paul "TBBle" Hampson](mailto:Paul.Hampson@Pobox.com) - [Peter Bengtsson](mailto:mail@peterbe.com) - [Peter Grayson](mailto:pete@jpgrayson.net) - [Peter Stensmyr](mailto:peter.stensmyr@gmail.com) diff --git a/src/black/__init__.py b/src/black/__init__.py index 0b734adca56..c1907d9b1f1 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -6425,14 +6425,14 @@ def assert_stable(src: str, dst: str, mode: Mode) -> None: @mypyc_attr(patchable=True) -def dump_to_file(*output: str) -> str: +def dump_to_file(*output: str, ensure_final_newline: bool = True) -> str: """Dump `output` to a temporary file. Return path to the file.""" with tempfile.NamedTemporaryFile( mode="w", prefix="blk_", suffix=".log", delete=False, encoding="utf8" ) as f: for lines in output: f.write(lines) - if lines and lines[-1] != "\n": + if ensure_final_newline and lines and lines[-1] != "\n": f.write("\n") return f.name @@ -6450,11 +6450,20 @@ def diff(a: str, b: str, a_name: str, b_name: str) -> str: """Return a unified diff string between strings `a` and `b`.""" import difflib - a_lines = [line + "\n" for line in a.splitlines()] - b_lines = [line + "\n" for line in b.splitlines()] - return "".join( - difflib.unified_diff(a_lines, b_lines, fromfile=a_name, tofile=b_name, n=5) - ) + a_lines = [line for line in a.splitlines(keepends=True)] + b_lines = [line for line in b.splitlines(keepends=True)] + diff_lines = [] + for line in difflib.unified_diff( + a_lines, b_lines, fromfile=a_name, tofile=b_name, n=5 + ): + # Work around https://bugs.python.org/issue2142 + # See https://www.gnu.org/software/diffutils/manual/html_node/Incomplete-Lines.html + if line[-1] == "\n": + diff_lines.append(line) + else: + diff_lines.append(line + "\n") + diff_lines.append("\\ No newline at end of file\n") + return "".join(diff_lines) def cancel(tasks: Iterable["asyncio.Task[Any]"]) -> None: diff --git a/tests/data/missing_final_newline.diff b/tests/data/missing_final_newline.diff new file mode 100644 index 00000000000..6d991c74f8f --- /dev/null +++ b/tests/data/missing_final_newline.diff @@ -0,0 +1,8 @@ +--- [Deterministic header] ++++ [Deterministic header] +@@ -1,3 +1,3 @@ + # A comment-only file, with no final EOL character + # This triggers https://bugs.python.org/issue2142 +-# This is the line without the EOL character +\ No newline at end of file ++# This is the line without the EOL character diff --git a/tests/data/missing_final_newline.py b/tests/data/missing_final_newline.py new file mode 100644 index 00000000000..687e1367552 --- /dev/null +++ b/tests/data/missing_final_newline.py @@ -0,0 +1,3 @@ +# A comment-only file, with no final EOL character +# This triggers https://bugs.python.org/issue2142 +# This is the line without the EOL character \ No newline at end of file diff --git a/tests/test_black.py b/tests/test_black.py index a2efef82422..5d14ceda8f4 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -300,7 +300,6 @@ def test_expression_diff(self) -> None: os.unlink(tmp_file) actual = result.output actual = diff_header.sub(DETERMINISTIC_HEADER, actual) - actual = actual.rstrip() + "\n" # the diff output has a trailing space if expected != actual: dump = black.dump_to_file(actual) msg = ( @@ -1798,6 +1797,28 @@ def test_newline_comment_interaction(self) -> None: output = black.format_str(source, mode=DEFAULT_MODE) black.assert_stable(source, output, mode=DEFAULT_MODE) + def test_bpo_2142_workaround(self) -> None: + + # https://bugs.python.org/issue2142 + + source, _ = read_data("missing_final_newline.py") + # read_data adds a trailing newline + source = source.rstrip() + expected, _ = read_data("missing_final_newline.diff") + tmp_file = Path(black.dump_to_file(source, ensure_final_newline=False)) + diff_header = re.compile( + rf"{re.escape(str(tmp_file))}\t\d\d\d\d-\d\d-\d\d " + r"\d\d:\d\d:\d\d\.\d\d\d\d\d\d \+\d\d\d\d" + ) + try: + result = BlackRunner().invoke(black.main, ["--diff", str(tmp_file)]) + self.assertEqual(result.exit_code, 0) + finally: + os.unlink(tmp_file) + actual = result.output + actual = diff_header.sub(DETERMINISTIC_HEADER, actual) + self.assertEqual(actual, expected) + with open(black.__file__, "r", encoding="utf-8") as _bf: black_source_lines = _bf.readlines() From 24e8dad575f2ae373e64b583f6ad103cf9193781 Mon Sep 17 00:00:00 2001 From: James <50501825+Gobot1234@users.noreply.github.com> Date: Mon, 22 Feb 2021 15:42:05 +0000 Subject: [PATCH 26/54] Fix for enum changes in 3.10 (#1999) --- src/black/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/black/__init__.py b/src/black/__init__.py index c1907d9b1f1..e09f08df7df 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -883,7 +883,7 @@ def format_file_in_place( dst_name = f"{src}\t{now} +0000" diff_contents = diff(src_contents, dst_contents, src_name, dst_name) - if write_back == write_back.COLOR_DIFF: + if write_back == WriteBack.COLOR_DIFF: diff_contents = color_diff(diff_contents) with lock or nullcontext(): From fe4a9d6bee21c471139e07fa27b464187477556c Mon Sep 17 00:00:00 2001 From: James Addison Date: Mon, 22 Feb 2021 15:46:38 +0000 Subject: [PATCH 27/54] Fixup: update function name in docs to match source (#1997) --- docs/reference/reference_functions.rst | 2 +- src/black/__init__.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/reference/reference_functions.rst b/docs/reference/reference_functions.rst index a7184115c94..bffce7e9e32 100644 --- a/docs/reference/reference_functions.rst +++ b/docs/reference/reference_functions.rst @@ -171,7 +171,7 @@ Utilities .. autofunction:: black.re_compile_maybe_verbose -.. autofunction:: black.should_split_body_explode +.. autofunction:: black.should_split_line .. autofunction:: black.shutdown diff --git a/src/black/__init__.py b/src/black/__init__.py index e09f08df7df..07251d55fb5 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -1480,7 +1480,7 @@ class Line: comments: Dict[LeafID, List[Leaf]] = field(default_factory=dict) bracket_tracker: BracketTracker = field(default_factory=BracketTracker) inside_brackets: bool = False - should_split: bool = False + should_split_rhs: bool = False magic_trailing_comma: Optional[Leaf] = None def append(self, leaf: Leaf, preformatted: bool = False) -> None: @@ -1792,7 +1792,7 @@ def clone(self) -> "Line": mode=self.mode, depth=self.depth, inside_brackets=self.inside_brackets, - should_split=self.should_split, + should_split_rhs=self.should_split_rhs, magic_trailing_comma=self.magic_trailing_comma, ) @@ -2712,7 +2712,7 @@ def init_st(ST: Type[StringTransformer]) -> StringTransformer: transformers: List[Transformer] if ( not line.contains_uncollapsable_type_comments() - and not line.should_split + and not line.should_split_rhs and not line.magic_trailing_comma and ( is_line_short_enough(line, line_length=mode.line_length, line_str=line_str) @@ -4387,7 +4387,7 @@ def do_transform(self, line: Line, string_idx: int) -> Iterator[TResult[Line]]: mode=line.mode, depth=line.depth + 1, inside_brackets=True, - should_split=line.should_split, + should_split_rhs=line.should_split_rhs, magic_trailing_comma=line.magic_trailing_comma, ) string_leaf = Leaf(token.STRING, string_value) @@ -5010,7 +5010,7 @@ def bracket_split_build_line( for comment_after in original.comments_after(leaf): result.append(comment_after, preformatted=True) if is_body and should_split_line(result, opening_bracket): - result.should_split = True + result.should_split_rhs = True return result From e1c86f987eca7e532f7d69f7ff4b9c70432fabbf Mon Sep 17 00:00:00 2001 From: James Addison Date: Mon, 22 Feb 2021 15:49:38 +0000 Subject: [PATCH 28/54] Fuzzer testing: less strict special-case regex match passthrough for multi-line EOF exceptions (#1998) --- fuzz.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fuzz.py b/fuzz.py index 6e2068690b5..a9ca8eff8b0 100644 --- a/fuzz.py +++ b/fuzz.py @@ -50,9 +50,9 @@ def test_idempotent_any_syntatically_valid_python( # TODO: remove this try-except block when issues are resolved. return except TokenError as e: - if ( + if ( # Special-case logic for backslashes followed by newlines or end-of-input e.args[0] == "EOF in multi-line statement" - and re.search(r"\r?\n\\\r?\n", src_contents) is not None + and re.search(r"\\($|\r?\n)", src_contents) is not None ): # This is a bug - if it's valid Python code, as above, Black should be # able to cope with it. See issue #1012. From b06cd15666e5d766347cda0434dc6c828a96c74a Mon Sep 17 00:00:00 2001 From: tpilewicz <31728184+tpilewicz@users.noreply.github.com> Date: Wed, 24 Feb 2021 12:56:56 +0100 Subject: [PATCH 29/54] Wrap arithmetic and binary arithmetic expressions in invisible parentheses (#2001) --- src/black/__init__.py | 13 ++++++++ tests/data/expression.diff | 30 +++++++++++++++++-- tests/data/expression.py | 24 +++++++++++++++ .../expression_skip_magic_trailing_comma.diff | 30 +++++++++++++++++-- 4 files changed, 91 insertions(+), 6 deletions(-) diff --git a/src/black/__init__.py b/src/black/__init__.py index 07251d55fb5..6919468609c 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -2049,6 +2049,8 @@ def visit_suite(self, node: Node) -> Iterator[Line]: def visit_simple_stmt(self, node: Node) -> Iterator[Line]: """Visit a statement without nested statements.""" + if first_child_is_arith(node): + wrap_in_parentheses(node, node.children[0], visible=False) is_suite_like = node.parent and node.parent.type in STATEMENT if is_suite_like: if self.mode.is_pyi and is_stub_body(node): @@ -5613,6 +5615,17 @@ def unwrap_singleton_parenthesis(node: LN) -> Optional[LN]: return wrapped +def first_child_is_arith(node: Node) -> bool: + """Whether first child is an arithmetic or a binary arithmetic expression""" + expr_types = { + syms.arith_expr, + syms.shift_expr, + syms.xor_expr, + syms.and_expr, + } + return bool(node.children and node.children[0].type in expr_types) + + def wrap_in_parentheses(parent: Node, child: LN, *, visible: bool = True) -> None: """Wrap `child` in parentheses. diff --git a/tests/data/expression.diff b/tests/data/expression.diff index 684f92cd3b7..721a07d2141 100644 --- a/tests/data/expression.diff +++ b/tests/data/expression.diff @@ -166,7 +166,7 @@ slice[0:1:2] slice[:] slice[:-1] -@@ -137,113 +173,180 @@ +@@ -137,118 +173,199 @@ numpy[-(c + 1) :, d] numpy[:, l[-2]] numpy[:, ::-1] @@ -346,6 +346,9 @@ - return True -if ( - ~ aaaaaaaaaaaaaaaa.a + aaaaaaaaaaaaaaaa.b - aaaaaaaaaaaaaaaa.c * aaaaaaaaaaaaaaaa.d @ aaaaaaaaaaaaaaaa.e | aaaaaaaaaaaaaaaa.f & aaaaaaaaaaaaaaaa.g % aaaaaaaaaaaaaaaa.h ^ aaaaaaaaaaaaaaaa.i << aaaaaaaaaaaaaaaa.k >> aaaaaaaaaaaaaaaa.l ** aaaaaaaaaaaaaaaa.m // aaaaaaaaaaaaaaaa.n +-): +- return True +-aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa - aaaaaaaaaaaaaaaa * (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa) / (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa) +a = ( + aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp + in qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz @@ -417,7 +420,28 @@ + ^ aaaaaaaaaaaaaaaa.i + << aaaaaaaaaaaaaaaa.k + >> aaaaaaaaaaaaaaaa.l ** aaaaaaaaaaaaaaaa.m // aaaaaaaaaaaaaaaa.n - ): - return True ++): ++ return True ++( ++ aaaaaaaaaaaaaaaa ++ + aaaaaaaaaaaaaaaa ++ - aaaaaaaaaaaaaaaa ++ * (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa) ++ / (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa) ++) + aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa +-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa >> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ++( ++ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ++ >> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ++ << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ++) + bbbb >> bbbb * bbbb +-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ^bbbb.a & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ++( ++ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ++ ^ bbbb.a & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ++ ^ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ++) last_call() # standalone comment at ENDMARKER diff --git a/tests/data/expression.py b/tests/data/expression.py index 8e63bdcdf9b..d13450cda68 100644 --- a/tests/data/expression.py +++ b/tests/data/expression.py @@ -245,6 +245,11 @@ async def f(): ~ aaaaaaaaaaaaaaaa.a + aaaaaaaaaaaaaaaa.b - aaaaaaaaaaaaaaaa.c * aaaaaaaaaaaaaaaa.d @ aaaaaaaaaaaaaaaa.e | aaaaaaaaaaaaaaaa.f & aaaaaaaaaaaaaaaa.g % aaaaaaaaaaaaaaaa.h ^ aaaaaaaaaaaaaaaa.i << aaaaaaaaaaaaaaaa.k >> aaaaaaaaaaaaaaaa.l ** aaaaaaaaaaaaaaaa.m // aaaaaaaaaaaaaaaa.n ): return True +aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa - aaaaaaaaaaaaaaaa * (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa) / (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa) +aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa >> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +bbbb >> bbbb * bbbb +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ^bbbb.a & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa last_call() # standalone comment at ENDMARKER @@ -602,5 +607,24 @@ async def f(): >> aaaaaaaaaaaaaaaa.l ** aaaaaaaaaaaaaaaa.m // aaaaaaaaaaaaaaaa.n ): return True +( + aaaaaaaaaaaaaaaa + + aaaaaaaaaaaaaaaa + - aaaaaaaaaaaaaaaa + * (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa) + / (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa) +) +aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa +( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + >> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +) +bbbb >> bbbb * bbbb +( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ^ bbbb.a & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ^ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +) last_call() # standalone comment at ENDMARKER diff --git a/tests/data/expression_skip_magic_trailing_comma.diff b/tests/data/expression_skip_magic_trailing_comma.diff index 8a0225bceb5..4a8a95c7237 100644 --- a/tests/data/expression_skip_magic_trailing_comma.diff +++ b/tests/data/expression_skip_magic_trailing_comma.diff @@ -149,7 +149,7 @@ slice[0:1:2] slice[:] slice[:-1] -@@ -137,113 +156,178 @@ +@@ -137,118 +156,197 @@ numpy[-(c + 1) :, d] numpy[:, l[-2]] numpy[:, ::-1] @@ -327,6 +327,9 @@ - return True -if ( - ~ aaaaaaaaaaaaaaaa.a + aaaaaaaaaaaaaaaa.b - aaaaaaaaaaaaaaaa.c * aaaaaaaaaaaaaaaa.d @ aaaaaaaaaaaaaaaa.e | aaaaaaaaaaaaaaaa.f & aaaaaaaaaaaaaaaa.g % aaaaaaaaaaaaaaaa.h ^ aaaaaaaaaaaaaaaa.i << aaaaaaaaaaaaaaaa.k >> aaaaaaaaaaaaaaaa.l ** aaaaaaaaaaaaaaaa.m // aaaaaaaaaaaaaaaa.n +-): +- return True +-aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa - aaaaaaaaaaaaaaaa * (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa) / (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa) +a = ( + aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp + in qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz @@ -398,7 +401,28 @@ + ^ aaaaaaaaaaaaaaaa.i + << aaaaaaaaaaaaaaaa.k + >> aaaaaaaaaaaaaaaa.l ** aaaaaaaaaaaaaaaa.m // aaaaaaaaaaaaaaaa.n - ): - return True ++): ++ return True ++( ++ aaaaaaaaaaaaaaaa ++ + aaaaaaaaaaaaaaaa ++ - aaaaaaaaaaaaaaaa ++ * (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa) ++ / (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa) ++) + aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa +-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa >> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ++( ++ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ++ >> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ++ << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ++) + bbbb >> bbbb * bbbb +-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ^bbbb.a & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ++( ++ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ++ ^ bbbb.a & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ++ ^ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ++) last_call() # standalone comment at ENDMARKER From 858225d34dc49ca353f9e573dd82dd5845766115 Mon Sep 17 00:00:00 2001 From: Rishav Kundu Date: Sun, 28 Feb 2021 06:50:23 +0530 Subject: [PATCH 30/54] Strip redundant parentheses from assignment exprs (#1906) Fixes #1656 --- src/black/__init__.py | 10 +++++--- tests/data/pep_572.py | 4 +-- tests/data/pep_572_remove_parens.py | 38 +++++++++++++++++++++++++++++ tests/data/remove_parens.py | 2 -- tests/test_black.py | 9 +++++++ 5 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 tests/data/pep_572_remove_parens.py diff --git a/src/black/__init__.py b/src/black/__init__.py index 6919468609c..a1d16d9bdeb 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -5370,10 +5370,7 @@ def normalize_invisible_parens(node: Node, parens_after: Set[str]) -> None: check_lpar = True if check_lpar: - if is_walrus_assignment(child): - pass - - elif child.type == syms.atom: + if child.type == syms.atom: if maybe_make_parens_invisible_in_atom(child, parent=node): wrap_in_parentheses(node, child, visible=False) elif is_one_tuple(child): @@ -5545,6 +5542,7 @@ def maybe_make_parens_invisible_in_atom(node: LN, parent: LN) -> bool: Returns whether the node should itself be wrapped in invisible parentheses. """ + if ( node.type != syms.atom or is_empty_tuple(node) @@ -5554,6 +5552,10 @@ def maybe_make_parens_invisible_in_atom(node: LN, parent: LN) -> bool: ): return False + if is_walrus_assignment(node): + if parent.type in [syms.annassign, syms.expr_stmt]: + return False + first = node.children[0] last = node.children[-1] if first.type == token.LPAR and last.type == token.RPAR: diff --git a/tests/data/pep_572.py b/tests/data/pep_572.py index 637b3bb38c6..c6867f26258 100644 --- a/tests/data/pep_572.py +++ b/tests/data/pep_572.py @@ -2,7 +2,7 @@ (a := a) if (match := pattern.search(data)) is None: pass -if (match := pattern.search(data)): +if match := pattern.search(data): pass [y := f(x), y ** 2, y ** 3] filtered_data = [y for x in data if (y := f(x)) is None] @@ -43,5 +43,5 @@ def foo(answer: (p := 42) = 5): while x := f(x): pass -while (x := f(x)): +while x := f(x): pass diff --git a/tests/data/pep_572_remove_parens.py b/tests/data/pep_572_remove_parens.py new file mode 100644 index 00000000000..04cc75bc36c --- /dev/null +++ b/tests/data/pep_572_remove_parens.py @@ -0,0 +1,38 @@ +if (foo := 0): + pass + +if (foo := 1): + pass + +if (y := 5 + 5): + pass + +y = (x := 0) + +y += (x := 0) + +(y := 5 + 5) + +test: int = (test2 := 2) + +a, b = (test := (1, 2)) + +# output +if foo := 0: + pass + +if foo := 1: + pass + +if y := 5 + 5: + pass + +y = (x := 0) + +y += (x := 0) + +(y := 5 + 5) + +test: int = (test2 := 2) + +a, b = (test := (1, 2)) diff --git a/tests/data/remove_parens.py b/tests/data/remove_parens.py index afc34010c30..abd5f71fcd0 100644 --- a/tests/data/remove_parens.py +++ b/tests/data/remove_parens.py @@ -54,7 +54,6 @@ def example7(): def example8(): return (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((None))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) - # output x = 1 x = 1.2 @@ -141,4 +140,3 @@ def example7(): def example8(): return None - diff --git a/tests/test_black.py b/tests/test_black.py index 5d14ceda8f4..9c3cc64387b 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -263,6 +263,15 @@ def test_pep_572(self) -> None: if sys.version_info >= (3, 8): black.assert_equivalent(source, actual) + @patch("black.dump_to_file", dump_to_stderr) + def test_pep_572_remove_parens(self) -> None: + source, expected = read_data("pep_572_remove_parens") + actual = fs(source) + self.assertFormatEqual(expected, actual) + black.assert_stable(source, actual, DEFAULT_MODE) + if sys.version_info >= (3, 8): + black.assert_equivalent(source, actual) + def test_pep_572_version_detection(self) -> None: source, _ = read_data("pep_572") root = black.lib2to3_parse(source) From beecd6fd0a9103aa91b1019dcf8fc774b667ea6c Mon Sep 17 00:00:00 2001 From: Joshua Cannon Date: Mon, 1 Mar 2021 16:07:36 -0600 Subject: [PATCH 31/54] Add --extend-exclude parameter (#2005) Look ma! I contribute to open source! Co-authored-by: Richard Si <63936253+ichard26@users.noreply.github.com> --- README.md | 30 +++++------- docs/change_log.md | 2 + docs/installation_and_usage.md | 7 ++- docs/pyproject_toml.md | 22 ++------- pyproject.toml | 13 +---- src/black/__init__.py | 78 ++++++++++++++++++++---------- tests/test_black.py | 86 ++++++++++++++++++++++++++++------ 7 files changed, 148 insertions(+), 90 deletions(-) diff --git a/README.md b/README.md index 178f763c32d..5f8b52cb823 100644 --- a/README.md +++ b/README.md @@ -135,11 +135,17 @@ Options: hg|\.mypy_cache|\.nox|\.tox|\.venv|\.svn|_bu ild|buck-out|build|dist)/] + --extend-exclude TEXT Like --exclude, but adds additional files + and directories on top of the excluded + ones (useful if you simply want to add to + the default). + --force-exclude TEXT Like --exclude, but files and directories matching this regex will be excluded even when they are passed explicitly as arguments. + --stdin-filename TEXT The name of the file when passing it through stdin. Useful to make sure Black will respect --force-exclude option on some @@ -151,7 +157,7 @@ Options: -v, --verbose Also emit messages to stderr about files that were not changed or were ignored due to - --exclude=. + exclusion patterns. --version Show the version and exit. --config FILE Read configuration from FILE path. @@ -263,7 +269,7 @@ above. What seems like a bug might be intended behaviour. _Black_ is able to read project-specific default values for its command line options from a `pyproject.toml` file. This is especially useful for specifying custom -`--include` and `--exclude` patterns for your project. +`--include` and `--exclude`/`--extend-exclude` patterns for your project. **Pro-tip**: If you're asking yourself "Do I need to configure anything?" the answer is "No". _Black_ is all about sensible defaults. @@ -313,25 +319,10 @@ expressions by Black. Use `[ ]` to denote a significant space character. line-length = 88 target-version = ['py37'] include = '\.pyi?$' -exclude = ''' +extend-exclude = ''' # A regex preceded with ^/ will apply only to files and directories # in the root of the project. -^/( - ( - \.eggs # exclude a few common directories in the - | \.git # root of the project - | \.hg - | \.mypy_cache - | \.tox - | \.venv - | _build - | buck-out - | build - | dist - )/ - | foo.py # also separately exclude a file named foo.py in - # the root of the project -) +^/foo.py # exclude a file named foo.py in the root of the project (in addition to the defaults) ''' ``` @@ -616,6 +607,7 @@ Multiple contributions by: - [Joseph Larson](mailto:larson.joseph@gmail.com) - [Josh Bode](mailto:joshbode@fastmail.com) - [Josh Holland](mailto:anowlcalledjosh@gmail.com) +- [Joshua Cannon](mailto:joshdcannon@gmail.com) - [José Padilla](mailto:jpadilla@webapplicate.com) - [Juan Luis Cano Rodríguez](mailto:hello@juanlu.space) - [kaiix](mailto:kvn.hou@gmail.com) diff --git a/docs/change_log.md b/docs/change_log.md index 066be76c06c..01c27553fca 100644 --- a/docs/change_log.md +++ b/docs/change_log.md @@ -28,6 +28,8 @@ - use lowercase hex strings (#1692) +- added `--extend-exclude` argument (#1571) + #### _Packaging_ - Self-contained native _Black_ binaries are now provided for releases via GitHub diff --git a/docs/installation_and_usage.md b/docs/installation_and_usage.md index ee45c934da8..bb554eb6744 100644 --- a/docs/installation_and_usage.md +++ b/docs/installation_and_usage.md @@ -95,6 +95,11 @@ Options: when they are passed explicitly as arguments. + --extend-exclude TEXT Like --exclude, but adds additional files + and directories on top of the excluded + ones. (useful if you simply want to add to + the default) + --stdin-filename TEXT The name of the file when passing it through stdin. Useful to make sure Black will respect --force-exclude option on some @@ -106,7 +111,7 @@ Options: -v, --verbose Also emit messages to stderr about files that were not changed or were ignored due to - --exclude=. + exclusion patterns. --version Show the version and exit. --config FILE Read configuration from FILE path. diff --git a/docs/pyproject_toml.md b/docs/pyproject_toml.md index 453f533bf96..9acc4c03d7c 100644 --- a/docs/pyproject_toml.md +++ b/docs/pyproject_toml.md @@ -4,7 +4,8 @@ _Black_ is able to read project-specific default values for its command line options from a `pyproject.toml` file. This is especially useful for specifying custom -`--include` and `--exclude` patterns for your project. +`--include` and `--exclude`/`--force-exclude`/`--extend-exclude` patterns for your +project. **Pro-tip**: If you're asking yourself "Do I need to configure anything?" the answer is "No". _Black_ is all about sensible defaults. @@ -54,25 +55,10 @@ expressions by Black. Use `[ ]` to denote a significant space character. line-length = 88 target-version = ['py37'] include = '\.pyi?$' -exclude = ''' +extend-exclude = ''' # A regex preceded with ^/ will apply only to files and directories # in the root of the project. -^/( - ( - \.eggs # exclude a few common directories in the - | \.git # root of the project - | \.hg - | \.mypy_cache - | \.tox - | \.venv - | _build - | buck-out - | build - | dist - )/ - | foo.py # also separately exclude a file named foo.py in - # the root of the project -) +^/foo.py # exclude a file named foo.py in the root of the project (in addition to the defaults) ''' ``` diff --git a/pyproject.toml b/pyproject.toml index 9d4da0bf692..7f632f2839d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,19 +9,8 @@ line-length = 88 target-version = ['py36', 'py37', 'py38'] include = '\.pyi?$' -exclude = ''' +extend-exclude = ''' /( - \.eggs - | \.git - | \.hg - | \.mypy_cache - | \.tox - | \.venv - | _build - | buck-out - | build - | dist - # The following are specific to Black, you probably don't want those. | blib2to3 | tests/data diff --git a/src/black/__init__.py b/src/black/__init__.py index a1d16d9bdeb..e21e2af5bd1 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -461,6 +461,14 @@ def target_version_option_callback( ), show_default=True, ) +@click.option( + "--extend-exclude", + type=str, + help=( + "Like --exclude, but adds additional files and directories on top of the" + " excluded ones. (Useful if you simply want to add to the default)" + ), +) @click.option( "--force-exclude", type=str, @@ -493,7 +501,7 @@ def target_version_option_callback( is_flag=True, help=( "Also emit messages to stderr about files that were not changed or were ignored" - " due to --exclude=." + " due to exclusion patterns." ), ) @click.version_option(version=__version__) @@ -537,6 +545,7 @@ def main( verbose: bool, include: str, exclude: str, + extend_exclude: Optional[str], force_exclude: Optional[str], stdin_filename: Optional[str], src: Tuple[str, ...], @@ -570,6 +579,7 @@ def main( verbose=verbose, include=include, exclude=exclude, + extend_exclude=extend_exclude, force_exclude=force_exclude, report=report, stdin_filename=stdin_filename, @@ -602,6 +612,18 @@ def main( ctx.exit(report.return_code) +def test_regex( + ctx: click.Context, + regex_name: str, + regex: Optional[str], +) -> Optional[Pattern]: + try: + return re_compile_maybe_verbose(regex) if regex is not None else None + except re.error: + err(f"Invalid regular expression for {regex_name} given: {regex!r}") + ctx.exit(2) + + def get_sources( *, ctx: click.Context, @@ -610,28 +632,18 @@ def get_sources( verbose: bool, include: str, exclude: str, + extend_exclude: Optional[str], force_exclude: Optional[str], report: "Report", stdin_filename: Optional[str], ) -> Set[Path]: """Compute the set of files to be formatted.""" - try: - include_regex = re_compile_maybe_verbose(include) - except re.error: - err(f"Invalid regular expression for include given: {include!r}") - ctx.exit(2) - try: - exclude_regex = re_compile_maybe_verbose(exclude) - except re.error: - err(f"Invalid regular expression for exclude given: {exclude!r}") - ctx.exit(2) - try: - force_exclude_regex = ( - re_compile_maybe_verbose(force_exclude) if force_exclude else None - ) - except re.error: - err(f"Invalid regular expression for force_exclude given: {force_exclude!r}") - ctx.exit(2) + + include_regex = test_regex(ctx, "include", include) + exclude_regex = test_regex(ctx, "exclude", exclude) + assert exclude_regex is not None + extend_exclude_regex = test_regex(ctx, "extend_exclude", extend_exclude) + force_exclude_regex = test_regex(ctx, "force_exclude", force_exclude) root = find_project_root(src) sources: Set[Path] = set() @@ -672,6 +684,7 @@ def get_sources( root, include_regex, exclude_regex, + extend_exclude_regex, force_exclude_regex, report, gitignore, @@ -6112,17 +6125,27 @@ def normalize_path_maybe_ignore( return normalized_path +def path_is_excluded( + normalized_path: str, + pattern: Optional[Pattern[str]], +) -> bool: + match = pattern.search(normalized_path) if pattern else None + return bool(match and match.group(0)) + + def gen_python_files( paths: Iterable[Path], root: Path, include: Optional[Pattern[str]], exclude: Pattern[str], + extend_exclude: Optional[Pattern[str]], force_exclude: Optional[Pattern[str]], report: "Report", gitignore: PathSpec, ) -> Iterator[Path]: """Generate all files under `path` whose paths are not excluded by the - `exclude_regex` or `force_exclude` regexes, but are included by the `include` regex. + `exclude_regex`, `extend_exclude`, or `force_exclude` regexes, + but are included by the `include` regex. Symbolic links pointing outside of the `root` directory are ignored. @@ -6139,20 +6162,22 @@ def gen_python_files( report.path_ignored(child, "matches the .gitignore file content") continue - # Then ignore with `--exclude` and `--force-exclude` options. + # Then ignore with `--exclude` `--extend-exclude` and `--force-exclude` options. normalized_path = "/" + normalized_path if child.is_dir(): normalized_path += "/" - exclude_match = exclude.search(normalized_path) if exclude else None - if exclude_match and exclude_match.group(0): + if path_is_excluded(normalized_path, exclude): report.path_ignored(child, "matches the --exclude regular expression") continue - force_exclude_match = ( - force_exclude.search(normalized_path) if force_exclude else None - ) - if force_exclude_match and force_exclude_match.group(0): + if path_is_excluded(normalized_path, extend_exclude): + report.path_ignored( + child, "matches the --extend-exclude regular expression" + ) + continue + + if path_is_excluded(normalized_path, force_exclude): report.path_ignored(child, "matches the --force-exclude regular expression") continue @@ -6162,6 +6187,7 @@ def gen_python_files( root, include, exclude, + extend_exclude, force_exclude, report, gitignore, diff --git a/tests/test_black.py b/tests/test_black.py index 9c3cc64387b..ba1869aa4c5 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -1346,7 +1346,14 @@ def test_include_exclude(self) -> None: this_abs = THIS_DIR.resolve() sources.extend( black.gen_python_files( - path.iterdir(), this_abs, include, exclude, None, report, gitignore + path.iterdir(), + this_abs, + include, + exclude, + None, + None, + report, + gitignore, ) ) self.assertEqual(sorted(expected), sorted(sources)) @@ -1370,6 +1377,7 @@ def test_exclude_for_issue_1572(self) -> None: verbose=False, include=include, exclude=exclude, + extend_exclude=None, force_exclude=None, report=report, stdin_filename=None, @@ -1392,6 +1400,7 @@ def test_get_sources_with_stdin(self) -> None: verbose=False, include=include, exclude=exclude, + extend_exclude=None, force_exclude=None, report=report, stdin_filename=None, @@ -1415,6 +1424,7 @@ def test_get_sources_with_stdin_filename(self) -> None: verbose=False, include=include, exclude=exclude, + extend_exclude=None, force_exclude=None, report=report, stdin_filename=stdin_filename, @@ -1442,6 +1452,35 @@ def test_get_sources_with_stdin_filename_and_exclude(self) -> None: verbose=False, include=include, exclude=exclude, + extend_exclude=None, + force_exclude=None, + report=report, + stdin_filename=stdin_filename, + ) + ) + self.assertEqual(sorted(expected), sorted(sources)) + + @patch("black.find_project_root", lambda *args: THIS_DIR.resolve()) + def test_get_sources_with_stdin_filename_and_extend_exclude(self) -> None: + # Extend exclude shouldn't exclude stdin_filename since it is mimicking the + # file being passed directly. This is the same as + # test_exclude_for_issue_1572 + path = THIS_DIR / "data" / "include_exclude_tests" + include = "" + extend_exclude = r"/exclude/|a\.py" + src = "-" + report = black.Report() + stdin_filename = str(path / "b/exclude/a.py") + expected = [Path(f"__BLACK_STDIN_FILENAME__{stdin_filename}")] + sources = list( + black.get_sources( + ctx=FakeContext(), + src=(src,), + quiet=True, + verbose=False, + include=include, + exclude="", + extend_exclude=extend_exclude, force_exclude=None, report=report, stdin_filename=stdin_filename, @@ -1467,6 +1506,7 @@ def test_get_sources_with_stdin_filename_and_force_exclude(self) -> None: verbose=False, include=include, exclude="", + extend_exclude=None, force_exclude=force_exclude, report=report, stdin_filename=stdin_filename, @@ -1551,7 +1591,14 @@ def test_gitignore_exclude(self) -> None: this_abs = THIS_DIR.resolve() sources.extend( black.gen_python_files( - path.iterdir(), this_abs, include, exclude, None, report, gitignore + path.iterdir(), + this_abs, + include, + exclude, + None, + None, + report, + gitignore, ) ) self.assertEqual(sorted(expected), sorted(sources)) @@ -1581,25 +1628,21 @@ def test_empty_include(self) -> None: empty, re.compile(black.DEFAULT_EXCLUDES), None, + None, report, gitignore, ) ) self.assertEqual(sorted(expected), sorted(sources)) - def test_empty_exclude(self) -> None: + def test_extend_exclude(self) -> None: path = THIS_DIR / "data" / "include_exclude_tests" report = black.Report() gitignore = PathSpec.from_lines("gitwildmatch", []) - empty = re.compile(r"") sources: List[Path] = [] expected = [ - Path(path / "b/dont_exclude/a.py"), - Path(path / "b/dont_exclude/a.pyi"), Path(path / "b/exclude/a.py"), - Path(path / "b/exclude/a.pyi"), - Path(path / "b/.definitely_exclude/a.py"), - Path(path / "b/.definitely_exclude/a.pyi"), + Path(path / "b/dont_exclude/a.py"), ] this_abs = THIS_DIR.resolve() sources.extend( @@ -1607,7 +1650,8 @@ def test_empty_exclude(self) -> None: path.iterdir(), this_abs, re.compile(black.DEFAULT_INCLUDES), - empty, + re.compile(r"\.pyi$"), + re.compile(r"\.definitely_exclude"), None, report, gitignore, @@ -1615,8 +1659,8 @@ def test_empty_exclude(self) -> None: ) self.assertEqual(sorted(expected), sorted(sources)) - def test_invalid_include_exclude(self) -> None: - for option in ["--include", "--exclude"]: + def test_invalid_cli_regex(self) -> None: + for option in ["--include", "--exclude", "--extend-exclude", "--force-exclude"]: self.invokeBlack(["-", option, "**()(!!*)"], exit_code=2) def test_preserves_line_endings(self) -> None: @@ -1665,7 +1709,14 @@ def test_symlink_out_of_root_directory(self) -> None: try: list( black.gen_python_files( - path.iterdir(), root, include, exclude, None, report, gitignore + path.iterdir(), + root, + include, + exclude, + None, + None, + report, + gitignore, ) ) except ValueError as ve: @@ -1679,7 +1730,14 @@ def test_symlink_out_of_root_directory(self) -> None: with self.assertRaises(ValueError): list( black.gen_python_files( - path.iterdir(), root, include, exclude, None, report, gitignore + path.iterdir(), + root, + include, + exclude, + None, + None, + report, + gitignore, ) ) path.iterdir.assert_called() From cac18293d5a6bd6b34a953f9cb5413f9826e505f Mon Sep 17 00:00:00 2001 From: Austin Pray <71290498+austinpray-mixpanel@users.noreply.github.com> Date: Mon, 1 Mar 2021 18:35:57 -0600 Subject: [PATCH 32/54] Adds --stdin-filename back to changelog (#2017) * Adds --stdin-filename back to changelog Looks like this went missing https://github.com/psf/black/commit/dea81b7ad5cfa04c3572771c34af823449d0a8f3#diff-729efdd61772b108539268bdbfd7472521bdc05a7cae6113f62ed2649a3ad9c7 * Update CHANGES.md Co-authored-by: Jelle Zijlstra * Update CHANGES.md Co-authored-by: Jelle Zijlstra Co-authored-by: Jelle Zijlstra --- CHANGES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 3fd7ad40496..90e5143fafe 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -30,6 +30,9 @@ - `--diff` correctly indicates when a file doesn't end in a newline (#1662) +- Added `--stdin-filename` argument to allow stdin to respect `--force-exclude` rules + (#1780) + #### _Packaging_ - Self-contained native _Black_ binaries are now provided for releases via GitHub From e3c71c3a477a44e6d817d37825a59bc6ba6a9897 Mon Sep 17 00:00:00 2001 From: Joshua Cannon Date: Tue, 2 Mar 2021 19:21:50 -0600 Subject: [PATCH 33/54] Turn test_regex into a click callback (#2016) Co-authored-by: Richard Si <63936253+ichard26@users.noreply.github.com> --- src/black/__init__.py | 61 ++++++++++++++++++++----------------------- tests/test_black.py | 28 ++++++++++---------- 2 files changed, 43 insertions(+), 46 deletions(-) diff --git a/src/black/__init__.py b/src/black/__init__.py index e21e2af5bd1..a8f4f89a6bb 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -363,6 +363,17 @@ def target_version_option_callback( return [TargetVersion[val.upper()] for val in v] +def validate_regex( + ctx: click.Context, + param: click.Parameter, + value: Optional[str], +) -> Optional[Pattern]: + try: + return re_compile_maybe_verbose(value) if value is not None else None + except re.error: + raise click.BadParameter("Not a valid regular expression") + + @click.command(context_settings=dict(help_option_names=["-h", "--help"])) @click.option("-c", "--code", type=str, help="Format the code passed in as a string.") @click.option( @@ -441,6 +452,7 @@ def target_version_option_callback( "--include", type=str, default=DEFAULT_INCLUDES, + callback=validate_regex, help=( "A regular expression that matches files and directories that should be" " included on recursive searches. An empty value means all files are included" @@ -453,6 +465,7 @@ def target_version_option_callback( "--exclude", type=str, default=DEFAULT_EXCLUDES, + callback=validate_regex, help=( "A regular expression that matches files and directories that should be" " excluded on recursive searches. An empty value means no paths are excluded." @@ -464,6 +477,7 @@ def target_version_option_callback( @click.option( "--extend-exclude", type=str, + callback=validate_regex, help=( "Like --exclude, but adds additional files and directories on top of the" " excluded ones. (Useful if you simply want to add to the default)" @@ -472,6 +486,7 @@ def target_version_option_callback( @click.option( "--force-exclude", type=str, + callback=validate_regex, help=( "Like --exclude, but files and directories matching this regex will be " "excluded even when they are passed explicitly as arguments." @@ -543,10 +558,10 @@ def main( experimental_string_processing: bool, quiet: bool, verbose: bool, - include: str, - exclude: str, - extend_exclude: Optional[str], - force_exclude: Optional[str], + include: Pattern, + exclude: Pattern, + extend_exclude: Optional[Pattern], + force_exclude: Optional[Pattern], stdin_filename: Optional[str], src: Tuple[str, ...], config: Optional[str], @@ -612,39 +627,21 @@ def main( ctx.exit(report.return_code) -def test_regex( - ctx: click.Context, - regex_name: str, - regex: Optional[str], -) -> Optional[Pattern]: - try: - return re_compile_maybe_verbose(regex) if regex is not None else None - except re.error: - err(f"Invalid regular expression for {regex_name} given: {regex!r}") - ctx.exit(2) - - def get_sources( *, ctx: click.Context, src: Tuple[str, ...], quiet: bool, verbose: bool, - include: str, - exclude: str, - extend_exclude: Optional[str], - force_exclude: Optional[str], + include: Pattern[str], + exclude: Pattern[str], + extend_exclude: Optional[Pattern[str]], + force_exclude: Optional[Pattern[str]], report: "Report", stdin_filename: Optional[str], ) -> Set[Path]: """Compute the set of files to be formatted.""" - include_regex = test_regex(ctx, "include", include) - exclude_regex = test_regex(ctx, "exclude", exclude) - assert exclude_regex is not None - extend_exclude_regex = test_regex(ctx, "extend_exclude", extend_exclude) - force_exclude_regex = test_regex(ctx, "force_exclude", force_exclude) - root = find_project_root(src) sources: Set[Path] = set() path_empty(src, "No Path provided. Nothing to do 😴", quiet, verbose, ctx) @@ -665,8 +662,8 @@ def get_sources( normalized_path = "/" + normalized_path # Hard-exclude any files that matches the `--force-exclude` regex. - if force_exclude_regex: - force_exclude_match = force_exclude_regex.search(normalized_path) + if force_exclude: + force_exclude_match = force_exclude.search(normalized_path) else: force_exclude_match = None if force_exclude_match and force_exclude_match.group(0): @@ -682,10 +679,10 @@ def get_sources( gen_python_files( p.iterdir(), root, - include_regex, - exclude_regex, - extend_exclude_regex, - force_exclude_regex, + include, + exclude, + extend_exclude, + force_exclude, report, gitignore, ) diff --git a/tests/test_black.py b/tests/test_black.py index ba1869aa4c5..72e16a324a5 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -1375,8 +1375,8 @@ def test_exclude_for_issue_1572(self) -> None: src=(src,), quiet=True, verbose=False, - include=include, - exclude=exclude, + include=re.compile(include), + exclude=re.compile(exclude), extend_exclude=None, force_exclude=None, report=report, @@ -1398,8 +1398,8 @@ def test_get_sources_with_stdin(self) -> None: src=(src,), quiet=True, verbose=False, - include=include, - exclude=exclude, + include=re.compile(include), + exclude=re.compile(exclude), extend_exclude=None, force_exclude=None, report=report, @@ -1422,8 +1422,8 @@ def test_get_sources_with_stdin_filename(self) -> None: src=(src,), quiet=True, verbose=False, - include=include, - exclude=exclude, + include=re.compile(include), + exclude=re.compile(exclude), extend_exclude=None, force_exclude=None, report=report, @@ -1450,8 +1450,8 @@ def test_get_sources_with_stdin_filename_and_exclude(self) -> None: src=(src,), quiet=True, verbose=False, - include=include, - exclude=exclude, + include=re.compile(include), + exclude=re.compile(exclude), extend_exclude=None, force_exclude=None, report=report, @@ -1478,9 +1478,9 @@ def test_get_sources_with_stdin_filename_and_extend_exclude(self) -> None: src=(src,), quiet=True, verbose=False, - include=include, - exclude="", - extend_exclude=extend_exclude, + include=re.compile(include), + exclude=re.compile(""), + extend_exclude=re.compile(extend_exclude), force_exclude=None, report=report, stdin_filename=stdin_filename, @@ -1504,10 +1504,10 @@ def test_get_sources_with_stdin_filename_and_force_exclude(self) -> None: src=(src,), quiet=True, verbose=False, - include=include, - exclude="", + include=re.compile(include), + exclude=re.compile(""), extend_exclude=None, - force_exclude=force_exclude, + force_exclude=re.compile(force_exclude), report=report, stdin_filename=stdin_filename, ) From e293473ea9c6a4408d4eb489d9d61fc87dbec639 Mon Sep 17 00:00:00 2001 From: Utkarsh Gupta Date: Thu, 4 Mar 2021 06:16:27 +0530 Subject: [PATCH 34/54] Add formatters-python for atom to editor_integration (#1834) --- docs/editor_integration.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/editor_integration.md b/docs/editor_integration.md index aa3a1eeedec..bc7c2e7b7be 100644 --- a/docs/editor_integration.md +++ b/docs/editor_integration.md @@ -286,7 +286,8 @@ Sublime Text, Visual Studio Code and many more), you can use the ## Atom/Nuclide -Use [python-black](https://atom.io/packages/python-black). +Use [python-black](https://atom.io/packages/python-black) or +[formatters-python](https://atom.io/packages/formatters-python). ## Gradle (the build tool) From 24418a54501381e1cdbe0ab1de4e4ced7537c124 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Thu, 4 Mar 2021 15:59:31 +0200 Subject: [PATCH 35/54] Black requires Python 3.6.2+ (#1668) --- README.md | 2 +- plugin/black.vim | 6 +++--- setup.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 5f8b52cb823..411a8c8609d 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ _Contents:_ **[Installation and usage](#installation-and-usage)** | ### Installation -_Black_ can be installed by running `pip install black`. It requires Python 3.6.0+ to +_Black_ can be installed by running `pip install black`. It requires Python 3.6.2+ to run but you can reformat Python 2 code with it, too. #### Install from GitHub diff --git a/plugin/black.vim b/plugin/black.vim index c5f0313f4ac..39a31f14b52 100644 --- a/plugin/black.vim +++ b/plugin/black.vim @@ -103,9 +103,9 @@ def _get_virtualenv_site_packages(venv_path, pyver): return venv_path / 'lib' / f'python{pyver[0]}.{pyver[1]}' / 'site-packages' def _initialize_black_env(upgrade=False): - pyver = sys.version_info[:2] - if pyver < (3, 6): - print("Sorry, Black requires Python 3.6+ to run.") + pyver = sys.version_info[:3] + if pyver < (3, 6, 2): + print("Sorry, Black requires Python 3.6.2+ to run.") return False from pathlib import Path diff --git a/setup.py b/setup.py index 48160568265..efdf6933025 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ import sys import os -assert sys.version_info >= (3, 6, 0), "black requires Python 3.6+" +assert sys.version_info >= (3, 6, 2), "black requires Python 3.6.2+" from pathlib import Path # noqa E402 CURRENT_DIR = Path(__file__).parent @@ -65,7 +65,7 @@ def get_long_description() -> str: packages=["blackd", "black", "blib2to3", "blib2to3.pgen2", "black_primer"], package_dir={"": "src"}, package_data={"blib2to3": ["*.txt"], "black": ["py.typed"]}, - python_requires=">=3.6", + python_requires=">=3.6.2", zip_safe=False, install_requires=[ "click>=7.1.2", From 12f98219bc83fa186cc97db7b614dccfb2a1db71 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Mar 2021 10:43:54 -0800 Subject: [PATCH 36/54] Bump aiohttp from 3.7.3 to 3.7.4 (#2009) Bumps [aiohttp](https://github.com/aio-libs/aiohttp) from 3.7.3 to 3.7.4. - [Release notes](https://github.com/aio-libs/aiohttp/releases) - [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst) - [Commits](https://github.com/aio-libs/aiohttp/compare/v3.7.3...v3.7.4) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Pipfile.lock | 279 +++++++++++++++++++++++++-------------------------- 1 file changed, 138 insertions(+), 141 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 9aa2d0e7ce8..9cdcba2a0ea 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -16,46 +16,46 @@ "default": { "aiohttp": { "hashes": [ - "sha256:0b795072bb1bf87b8620120a6373a3c61bfcb8da7e5c2377f4bb23ff4f0b62c9", - "sha256:0d438c8ca703b1b714e82ed5b7a4412c82577040dadff479c08405e2a715564f", - "sha256:16a3cb5df5c56f696234ea9e65e227d1ebe9c18aa774d36ff42f532139066a5f", - "sha256:1edfd82a98c5161497bbb111b2b70c0813102ad7e0aa81cbeb34e64c93863005", - "sha256:2406dc1dda01c7f6060ab586e4601f18affb7a6b965c50a8c90ff07569cf782a", - "sha256:2858b2504c8697beb9357be01dc47ef86438cc1cb36ecb6991796d19475faa3e", - "sha256:2a7b7640167ab536c3cb90cfc3977c7094f1c5890d7eeede8b273c175c3910fd", - "sha256:3228b7a51e3ed533f5472f54f70fd0b0a64c48dc1649a0f0e809bec312934d7a", - "sha256:328b552513d4f95b0a2eea4c8573e112866107227661834652a8984766aa7656", - "sha256:39f4b0a6ae22a1c567cb0630c30dd082481f95c13ca528dc501a7766b9c718c0", - "sha256:3b0036c978cbcc4a4512278e98e3e6d9e6b834dc973206162eddf98b586ef1c6", - "sha256:3ea8c252d8df5e9166bcf3d9edced2af132f4ead8ac422eac723c5781063709a", - "sha256:41608c0acbe0899c852281978492f9ce2c6fbfaf60aff0cefc54a7c4516b822c", - "sha256:59d11674964b74a81b149d4ceaff2b674b3b0e4d0f10f0be1533e49c4a28408b", - "sha256:5e479df4b2d0f8f02133b7e4430098699450e1b2a826438af6bec9a400530957", - "sha256:684850fb1e3e55c9220aad007f8386d8e3e477c4ec9211ae54d968ecdca8c6f9", - "sha256:6ccc43d68b81c424e46192a778f97da94ee0630337c9bbe5b2ecc9b0c1c59001", - "sha256:6d42debaf55450643146fabe4b6817bb2a55b23698b0434107e892a43117285e", - "sha256:710376bf67d8ff4500a31d0c207b8941ff4fba5de6890a701d71680474fe2a60", - "sha256:756ae7efddd68d4ea7d89c636b703e14a0c686688d42f588b90778a3c2fc0564", - "sha256:77149002d9386fae303a4a162e6bce75cc2161347ad2ba06c2f0182561875d45", - "sha256:78e2f18a82b88cbc37d22365cf8d2b879a492faedb3f2975adb4ed8dfe994d3a", - "sha256:7d9b42127a6c0bdcc25c3dcf252bb3ddc70454fac593b1b6933ae091396deb13", - "sha256:8389d6044ee4e2037dca83e3f6994738550f6ee8cfb746762283fad9b932868f", - "sha256:9c1a81af067e72261c9cbe33ea792893e83bc6aa987bfbd6fdc1e5e7b22777c4", - "sha256:c1e0920909d916d3375c7a1fdb0b1c78e46170e8bb42792312b6eb6676b2f87f", - "sha256:c68fdf21c6f3573ae19c7ee65f9ff185649a060c9a06535e9c3a0ee0bbac9235", - "sha256:c733ef3bdcfe52a1a75564389bad4064352274036e7e234730526d155f04d914", - "sha256:c9c58b0b84055d8bc27b7df5a9d141df4ee6ff59821f922dd73155861282f6a3", - "sha256:d03abec50df423b026a5aa09656bd9d37f1e6a49271f123f31f9b8aed5dc3ea3", - "sha256:d2cfac21e31e841d60dc28c0ec7d4ec47a35c608cb8906435d47ef83ffb22150", - "sha256:dcc119db14757b0c7bce64042158307b9b1c76471e655751a61b57f5a0e4d78e", - "sha256:df3a7b258cc230a65245167a202dd07320a5af05f3d41da1488ba0fa05bc9347", - "sha256:df48a623c58180874d7407b4d9ec06a19b84ed47f60a3884345b1a5099c1818b", - "sha256:e1b95972a0ae3f248a899cdbac92ba2e01d731225f566569311043ce2226f5e7", - "sha256:f326b3c1bbfda5b9308252ee0dcb30b612ee92b0e105d4abec70335fab5b1245", - "sha256:f411cb22115cb15452d099fec0ee636b06cf81bfb40ed9c02d30c8dc2bc2e3d1" + "sha256:119feb2bd551e58d83d1b38bfa4cb921af8ddedec9fad7183132db334c3133e0", + "sha256:16d0683ef8a6d803207f02b899c928223eb219111bd52420ef3d7a8aa76227b6", + "sha256:2eb3efe243e0f4ecbb654b08444ae6ffab37ac0ef8f69d3a2ffb958905379daf", + "sha256:2ffea7904e70350da429568113ae422c88d2234ae776519549513c8f217f58a9", + "sha256:40bd1b101b71a18a528ffce812cc14ff77d4a2a1272dfb8b11b200967489ef3e", + "sha256:418597633b5cd9639e514b1d748f358832c08cd5d9ef0870026535bd5eaefdd0", + "sha256:481d4b96969fbfdcc3ff35eea5305d8565a8300410d3d269ccac69e7256b1329", + "sha256:4c1bdbfdd231a20eee3e56bd0ac1cd88c4ff41b64ab679ed65b75c9c74b6c5c2", + "sha256:5563ad7fde451b1986d42b9bb9140e2599ecf4f8e42241f6da0d3d624b776f40", + "sha256:58c62152c4c8731a3152e7e650b29ace18304d086cb5552d317a54ff2749d32a", + "sha256:5b50e0b9460100fe05d7472264d1975f21ac007b35dcd6fd50279b72925a27f4", + "sha256:5d84ecc73141d0a0d61ece0742bb7ff5751b0657dab8405f899d3ceb104cc7de", + "sha256:5dde6d24bacac480be03f4f864e9a67faac5032e28841b00533cd168ab39cad9", + "sha256:5e91e927003d1ed9283dee9abcb989334fc8e72cf89ebe94dc3e07e3ff0b11e9", + "sha256:62bc216eafac3204877241569209d9ba6226185aa6d561c19159f2e1cbb6abfb", + "sha256:6c8200abc9dc5f27203986100579fc19ccad7a832c07d2bc151ce4ff17190076", + "sha256:6ca56bdfaf825f4439e9e3673775e1032d8b6ea63b8953d3812c71bd6a8b81de", + "sha256:71680321a8a7176a58dfbc230789790639db78dad61a6e120b39f314f43f1907", + "sha256:7c7820099e8b3171e54e7eedc33e9450afe7cd08172632d32128bd527f8cb77d", + "sha256:7dbd087ff2f4046b9b37ba28ed73f15fd0bc9f4fdc8ef6781913da7f808d9536", + "sha256:822bd4fd21abaa7b28d65fc9871ecabaddc42767884a626317ef5b75c20e8a2d", + "sha256:8ec1a38074f68d66ccb467ed9a673a726bb397142c273f90d4ba954666e87d54", + "sha256:950b7ef08b2afdab2488ee2edaff92a03ca500a48f1e1aaa5900e73d6cf992bc", + "sha256:99c5a5bf7135607959441b7d720d96c8e5c46a1f96e9d6d4c9498be8d5f24212", + "sha256:b84ad94868e1e6a5e30d30ec419956042815dfaea1b1df1cef623e4564c374d9", + "sha256:bc3d14bf71a3fb94e5acf5bbf67331ab335467129af6416a437bd6024e4f743d", + "sha256:c2a80fd9a8d7e41b4e38ea9fe149deed0d6aaede255c497e66b8213274d6d61b", + "sha256:c44d3c82a933c6cbc21039326767e778eface44fca55c65719921c4b9661a3f7", + "sha256:cc31e906be1cc121ee201adbdf844522ea3349600dd0a40366611ca18cd40e81", + "sha256:d5d102e945ecca93bcd9801a7bb2fa703e37ad188a2f81b1e65e4abe4b51b00c", + "sha256:dd7936f2a6daa861143e376b3a1fb56e9b802f4980923594edd9ca5670974895", + "sha256:dee68ec462ff10c1d836c0ea2642116aba6151c6880b688e56b4c0246770f297", + "sha256:e76e78863a4eaec3aee5722d85d04dcbd9844bc6cd3bfa6aa880ff46ad16bfcb", + "sha256:eab51036cac2da8a50d7ff0ea30be47750547c9aa1aa2cf1a1b710a1827e7dbe", + "sha256:f4496d8d04da2e98cc9133e238ccebf6a13ef39a93da2e87146c8c8ac9768242", + "sha256:fbd3b5e18d34683decc00d9a360179ac1e7a320a5fee10ab8053ffd6deab76e0", + "sha256:feb24ff1226beeb056e247cf2e24bba5232519efb5645121c4aea5b6ad74c1f2" ], "index": "pypi", - "version": "==3.7.3" + "version": "==3.7.4" }, "aiohttp-cors": { "hashes": [ @@ -328,46 +328,46 @@ "develop": { "aiohttp": { "hashes": [ - "sha256:0b795072bb1bf87b8620120a6373a3c61bfcb8da7e5c2377f4bb23ff4f0b62c9", - "sha256:0d438c8ca703b1b714e82ed5b7a4412c82577040dadff479c08405e2a715564f", - "sha256:16a3cb5df5c56f696234ea9e65e227d1ebe9c18aa774d36ff42f532139066a5f", - "sha256:1edfd82a98c5161497bbb111b2b70c0813102ad7e0aa81cbeb34e64c93863005", - "sha256:2406dc1dda01c7f6060ab586e4601f18affb7a6b965c50a8c90ff07569cf782a", - "sha256:2858b2504c8697beb9357be01dc47ef86438cc1cb36ecb6991796d19475faa3e", - "sha256:2a7b7640167ab536c3cb90cfc3977c7094f1c5890d7eeede8b273c175c3910fd", - "sha256:3228b7a51e3ed533f5472f54f70fd0b0a64c48dc1649a0f0e809bec312934d7a", - "sha256:328b552513d4f95b0a2eea4c8573e112866107227661834652a8984766aa7656", - "sha256:39f4b0a6ae22a1c567cb0630c30dd082481f95c13ca528dc501a7766b9c718c0", - "sha256:3b0036c978cbcc4a4512278e98e3e6d9e6b834dc973206162eddf98b586ef1c6", - "sha256:3ea8c252d8df5e9166bcf3d9edced2af132f4ead8ac422eac723c5781063709a", - "sha256:41608c0acbe0899c852281978492f9ce2c6fbfaf60aff0cefc54a7c4516b822c", - "sha256:59d11674964b74a81b149d4ceaff2b674b3b0e4d0f10f0be1533e49c4a28408b", - "sha256:5e479df4b2d0f8f02133b7e4430098699450e1b2a826438af6bec9a400530957", - "sha256:684850fb1e3e55c9220aad007f8386d8e3e477c4ec9211ae54d968ecdca8c6f9", - "sha256:6ccc43d68b81c424e46192a778f97da94ee0630337c9bbe5b2ecc9b0c1c59001", - "sha256:6d42debaf55450643146fabe4b6817bb2a55b23698b0434107e892a43117285e", - "sha256:710376bf67d8ff4500a31d0c207b8941ff4fba5de6890a701d71680474fe2a60", - "sha256:756ae7efddd68d4ea7d89c636b703e14a0c686688d42f588b90778a3c2fc0564", - "sha256:77149002d9386fae303a4a162e6bce75cc2161347ad2ba06c2f0182561875d45", - "sha256:78e2f18a82b88cbc37d22365cf8d2b879a492faedb3f2975adb4ed8dfe994d3a", - "sha256:7d9b42127a6c0bdcc25c3dcf252bb3ddc70454fac593b1b6933ae091396deb13", - "sha256:8389d6044ee4e2037dca83e3f6994738550f6ee8cfb746762283fad9b932868f", - "sha256:9c1a81af067e72261c9cbe33ea792893e83bc6aa987bfbd6fdc1e5e7b22777c4", - "sha256:c1e0920909d916d3375c7a1fdb0b1c78e46170e8bb42792312b6eb6676b2f87f", - "sha256:c68fdf21c6f3573ae19c7ee65f9ff185649a060c9a06535e9c3a0ee0bbac9235", - "sha256:c733ef3bdcfe52a1a75564389bad4064352274036e7e234730526d155f04d914", - "sha256:c9c58b0b84055d8bc27b7df5a9d141df4ee6ff59821f922dd73155861282f6a3", - "sha256:d03abec50df423b026a5aa09656bd9d37f1e6a49271f123f31f9b8aed5dc3ea3", - "sha256:d2cfac21e31e841d60dc28c0ec7d4ec47a35c608cb8906435d47ef83ffb22150", - "sha256:dcc119db14757b0c7bce64042158307b9b1c76471e655751a61b57f5a0e4d78e", - "sha256:df3a7b258cc230a65245167a202dd07320a5af05f3d41da1488ba0fa05bc9347", - "sha256:df48a623c58180874d7407b4d9ec06a19b84ed47f60a3884345b1a5099c1818b", - "sha256:e1b95972a0ae3f248a899cdbac92ba2e01d731225f566569311043ce2226f5e7", - "sha256:f326b3c1bbfda5b9308252ee0dcb30b612ee92b0e105d4abec70335fab5b1245", - "sha256:f411cb22115cb15452d099fec0ee636b06cf81bfb40ed9c02d30c8dc2bc2e3d1" + "sha256:119feb2bd551e58d83d1b38bfa4cb921af8ddedec9fad7183132db334c3133e0", + "sha256:16d0683ef8a6d803207f02b899c928223eb219111bd52420ef3d7a8aa76227b6", + "sha256:2eb3efe243e0f4ecbb654b08444ae6ffab37ac0ef8f69d3a2ffb958905379daf", + "sha256:2ffea7904e70350da429568113ae422c88d2234ae776519549513c8f217f58a9", + "sha256:40bd1b101b71a18a528ffce812cc14ff77d4a2a1272dfb8b11b200967489ef3e", + "sha256:418597633b5cd9639e514b1d748f358832c08cd5d9ef0870026535bd5eaefdd0", + "sha256:481d4b96969fbfdcc3ff35eea5305d8565a8300410d3d269ccac69e7256b1329", + "sha256:4c1bdbfdd231a20eee3e56bd0ac1cd88c4ff41b64ab679ed65b75c9c74b6c5c2", + "sha256:5563ad7fde451b1986d42b9bb9140e2599ecf4f8e42241f6da0d3d624b776f40", + "sha256:58c62152c4c8731a3152e7e650b29ace18304d086cb5552d317a54ff2749d32a", + "sha256:5b50e0b9460100fe05d7472264d1975f21ac007b35dcd6fd50279b72925a27f4", + "sha256:5d84ecc73141d0a0d61ece0742bb7ff5751b0657dab8405f899d3ceb104cc7de", + "sha256:5dde6d24bacac480be03f4f864e9a67faac5032e28841b00533cd168ab39cad9", + "sha256:5e91e927003d1ed9283dee9abcb989334fc8e72cf89ebe94dc3e07e3ff0b11e9", + "sha256:62bc216eafac3204877241569209d9ba6226185aa6d561c19159f2e1cbb6abfb", + "sha256:6c8200abc9dc5f27203986100579fc19ccad7a832c07d2bc151ce4ff17190076", + "sha256:6ca56bdfaf825f4439e9e3673775e1032d8b6ea63b8953d3812c71bd6a8b81de", + "sha256:71680321a8a7176a58dfbc230789790639db78dad61a6e120b39f314f43f1907", + "sha256:7c7820099e8b3171e54e7eedc33e9450afe7cd08172632d32128bd527f8cb77d", + "sha256:7dbd087ff2f4046b9b37ba28ed73f15fd0bc9f4fdc8ef6781913da7f808d9536", + "sha256:822bd4fd21abaa7b28d65fc9871ecabaddc42767884a626317ef5b75c20e8a2d", + "sha256:8ec1a38074f68d66ccb467ed9a673a726bb397142c273f90d4ba954666e87d54", + "sha256:950b7ef08b2afdab2488ee2edaff92a03ca500a48f1e1aaa5900e73d6cf992bc", + "sha256:99c5a5bf7135607959441b7d720d96c8e5c46a1f96e9d6d4c9498be8d5f24212", + "sha256:b84ad94868e1e6a5e30d30ec419956042815dfaea1b1df1cef623e4564c374d9", + "sha256:bc3d14bf71a3fb94e5acf5bbf67331ab335467129af6416a437bd6024e4f743d", + "sha256:c2a80fd9a8d7e41b4e38ea9fe149deed0d6aaede255c497e66b8213274d6d61b", + "sha256:c44d3c82a933c6cbc21039326767e778eface44fca55c65719921c4b9661a3f7", + "sha256:cc31e906be1cc121ee201adbdf844522ea3349600dd0a40366611ca18cd40e81", + "sha256:d5d102e945ecca93bcd9801a7bb2fa703e37ad188a2f81b1e65e4abe4b51b00c", + "sha256:dd7936f2a6daa861143e376b3a1fb56e9b802f4980923594edd9ca5670974895", + "sha256:dee68ec462ff10c1d836c0ea2642116aba6151c6880b688e56b4c0246770f297", + "sha256:e76e78863a4eaec3aee5722d85d04dcbd9844bc6cd3bfa6aa880ff46ad16bfcb", + "sha256:eab51036cac2da8a50d7ff0ea30be47750547c9aa1aa2cf1a1b710a1827e7dbe", + "sha256:f4496d8d04da2e98cc9133e238ccebf6a13ef39a93da2e87146c8c8ac9768242", + "sha256:fbd3b5e18d34683decc00d9a360179ac1e7a320a5fee10ab8053ffd6deab76e0", + "sha256:feb24ff1226beeb056e247cf2e24bba5232519efb5645121c4aea5b6ad74c1f2" ], "index": "pypi", - "version": "==3.7.3" + "version": "==3.7.4" }, "aiohttp-cors": { "hashes": [ @@ -436,45 +436,45 @@ }, "cffi": { "hashes": [ - "sha256:00a1ba5e2e95684448de9b89888ccd02c98d512064b4cb987d48f4b40aa0421e", - "sha256:00e28066507bfc3fe865a31f325c8391a1ac2916219340f87dfad602c3e48e5d", - "sha256:045d792900a75e8b1e1b0ab6787dd733a8190ffcf80e8c8ceb2fb10a29ff238a", - "sha256:0638c3ae1a0edfb77c6765d487fee624d2b1ee1bdfeffc1f0b58c64d149e7eec", - "sha256:105abaf8a6075dc96c1fe5ae7aae073f4696f2905fde6aeada4c9d2926752362", - "sha256:155136b51fd733fa94e1c2ea5211dcd4c8879869008fc811648f16541bf99668", - "sha256:1a465cbe98a7fd391d47dce4b8f7e5b921e6cd805ef421d04f5f66ba8f06086c", - "sha256:1d2c4994f515e5b485fd6d3a73d05526aa0fcf248eb135996b088d25dfa1865b", - "sha256:2c24d61263f511551f740d1a065eb0212db1dbbbbd241db758f5244281590c06", - "sha256:51a8b381b16ddd370178a65360ebe15fbc1c71cf6f584613a7ea08bfad946698", - "sha256:594234691ac0e9b770aee9fcdb8fa02c22e43e5c619456efd0d6c2bf276f3eb2", - "sha256:5cf4be6c304ad0b6602f5c4e90e2f59b47653ac1ed9c662ed379fe48a8f26b0c", - "sha256:64081b3f8f6f3c3de6191ec89d7dc6c86a8a43911f7ecb422c60e90c70be41c7", - "sha256:6bc25fc545a6b3d57b5f8618e59fc13d3a3a68431e8ca5fd4c13241cd70d0009", - "sha256:798caa2a2384b1cbe8a2a139d80734c9db54f9cc155c99d7cc92441a23871c03", - "sha256:7c6b1dece89874d9541fc974917b631406233ea0440d0bdfbb8e03bf39a49b3b", - "sha256:7ef7d4ced6b325e92eb4d3502946c78c5367bc416398d387b39591532536734e", - "sha256:840793c68105fe031f34d6a086eaea153a0cd5c491cde82a74b420edd0a2b909", - "sha256:8d6603078baf4e11edc4168a514c5ce5b3ba6e3e9c374298cb88437957960a53", - "sha256:9cc46bc107224ff5b6d04369e7c595acb700c3613ad7bcf2e2012f62ece80c35", - "sha256:9f7a31251289b2ab6d4012f6e83e58bc3b96bd151f5b5262467f4bb6b34a7c26", - "sha256:9ffb888f19d54a4d4dfd4b3f29bc2c16aa4972f1c2ab9c4ab09b8ab8685b9c2b", - "sha256:a5ed8c05548b54b998b9498753fb9cadbfd92ee88e884641377d8a8b291bcc01", - "sha256:a7711edca4dcef1a75257b50a2fbfe92a65187c47dab5a0f1b9b332c5919a3fb", - "sha256:af5c59122a011049aad5dd87424b8e65a80e4a6477419c0c1015f73fb5ea0293", - "sha256:b18e0a9ef57d2b41f5c68beefa32317d286c3d6ac0484efd10d6e07491bb95dd", - "sha256:b4e248d1087abf9f4c10f3c398896c87ce82a9856494a7155823eb45a892395d", - "sha256:ba4e9e0ae13fc41c6b23299545e5ef73055213e466bd107953e4a013a5ddd7e3", - "sha256:c6332685306b6417a91b1ff9fae889b3ba65c2292d64bd9245c093b1b284809d", - "sha256:d5ff0621c88ce83a28a10d2ce719b2ee85635e85c515f12bac99a95306da4b2e", - "sha256:d9efd8b7a3ef378dd61a1e77367f1924375befc2eba06168b6ebfa903a5e59ca", - "sha256:df5169c4396adc04f9b0a05f13c074df878b6052430e03f50e68adf3a57aa28d", - "sha256:ebb253464a5d0482b191274f1c8bf00e33f7e0b9c66405fbffc61ed2c839c775", - "sha256:ec80dc47f54e6e9a78181ce05feb71a0353854cc26999db963695f950b5fb375", - "sha256:f032b34669220030f905152045dfa27741ce1a6db3324a5bc0b96b6c7420c87b", - "sha256:f60567825f791c6f8a592f3c6e3bd93dd2934e3f9dac189308426bd76b00ef3b", - "sha256:f803eaa94c2fcda012c047e62bc7a51b0bdabda1cad7a92a522694ea2d76e49f" - ], - "version": "==1.14.4" + "sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813", + "sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06", + "sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea", + "sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee", + "sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396", + "sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73", + "sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315", + "sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1", + "sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49", + "sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892", + "sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482", + "sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058", + "sha256:51182f8927c5af975fece87b1b369f722c570fe169f9880764b1ee3bca8347b5", + "sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53", + "sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045", + "sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3", + "sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5", + "sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e", + "sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c", + "sha256:72d8d3ef52c208ee1c7b2e341f7d71c6fd3157138abf1a95166e6165dd5d4369", + "sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827", + "sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053", + "sha256:99cd03ae7988a93dd00bcd9d0b75e1f6c426063d6f03d2f90b89e29b25b82dfa", + "sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4", + "sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322", + "sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132", + "sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62", + "sha256:a465da611f6fa124963b91bf432d960a555563efe4ed1cc403ba5077b15370aa", + "sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0", + "sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396", + "sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e", + "sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991", + "sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6", + "sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1", + "sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406", + "sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d", + "sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c" + ], + "version": "==1.14.5" }, "cfgv": { "hashes": [ @@ -569,23 +569,20 @@ }, "cryptography": { "hashes": [ - "sha256:0d7b69674b738068fa6ffade5c962ecd14969690585aaca0a1b1fc9058938a72", - "sha256:1bd0ccb0a1ed775cd7e2144fe46df9dc03eefd722bbcf587b3e0616ea4a81eff", - "sha256:3c284fc1e504e88e51c428db9c9274f2da9f73fdf5d7e13a36b8ecb039af6e6c", - "sha256:49570438e60f19243e7e0d504527dd5fe9b4b967b5a1ff21cc12b57602dd85d3", - "sha256:541dd758ad49b45920dda3b5b48c968f8b2533d8981bcdb43002798d8f7a89ed", - "sha256:5a60d3780149e13b7a6ff7ad6526b38846354d11a15e21068e57073e29e19bed", - "sha256:7951a966613c4211b6612b0352f5bf29989955ee592c4a885d8c7d0f830d0433", - "sha256:922f9602d67c15ade470c11d616f2b2364950602e370c76f0c94c94ae672742e", - "sha256:a0f0b96c572fc9f25c3f4ddbf4688b9b38c69836713fb255f4a2715d93cbaf44", - "sha256:a777c096a49d80f9d2979695b835b0f9c9edab73b59e4ceb51f19724dda887ed", - "sha256:a9a4ac9648d39ce71c2f63fe7dc6db144b9fa567ddfc48b9fde1b54483d26042", - "sha256:aa4969f24d536ae2268c902b2c3d62ab464b5a66bcb247630d208a79a8098e9b", - "sha256:c7390f9b2119b2b43160abb34f63277a638504ef8df99f11cb52c1fda66a2e6f", - "sha256:e18e6ab84dfb0ab997faf8cca25a86ff15dfea4027b986322026cc99e0a892da" - ], - "index": "pypi", - "version": "==3.3.2" + "sha256:066bc53f052dfeda2f2d7c195cf16fb3e5ff13e1b6b7415b468514b40b381a5b", + "sha256:0923ba600d00718d63a3976f23cab19aef10c1765038945628cd9be047ad0336", + "sha256:2d32223e5b0ee02943f32b19245b61a62db83a882f0e76cc564e1cec60d48f87", + "sha256:4169a27b818de4a1860720108b55a2801f32b6ae79e7f99c00d79f2a2822eeb7", + "sha256:57ad77d32917bc55299b16d3b996ffa42a1c73c6cfa829b14043c561288d2799", + "sha256:5ecf2bcb34d17415e89b546dbb44e73080f747e504273e4d4987630493cded1b", + "sha256:600cf9bfe75e96d965509a4c0b2b183f74a4fa6f5331dcb40fb7b77b7c2484df", + "sha256:66b57a9ca4b3221d51b237094b0303843b914b7d5afd4349970bb26518e350b0", + "sha256:93cfe5b7ff006de13e1e89830810ecbd014791b042cbe5eec253be11ac2b28f3", + "sha256:9e98b452132963678e3ac6c73f7010fe53adf72209a32854d55690acac3f6724", + "sha256:df186fcbf86dc1ce56305becb8434e4b6b7504bc724b71ad7a3239e0c9d14ef2", + "sha256:fec7fb46b10da10d9e1d078d1ff8ed9e05ae14f431fdbd11145edd0550b9a964" + ], + "version": "==3.4.6" }, "distlib": { "hashes": [ @@ -627,10 +624,10 @@ }, "identify": { "hashes": [ - "sha256:70b638cf4743f33042bebb3b51e25261a0a10e80f978739f17e7fd4837664a66", - "sha256:9dfb63a2e871b807e3ba62f029813552a24b5289504f5b071dea9b041aee9fe4" + "sha256:de7129142a5c86d75a52b96f394d94d96d497881d2aaf8eafe320cdbe8ac4bcc", + "sha256:e0dae57c0397629ce13c289f6ddde0204edf518f557bfdb1e56474aa143e77c3" ], - "version": "==1.5.13" + "version": "==1.5.14" }, "idna": { "hashes": [ @@ -862,10 +859,10 @@ }, "pygments": { "hashes": [ - "sha256:bc9591213a8f0e0ca1a5e68a479b4887fdc3e75d0774e5c71c31920c427de435", - "sha256:df49d09b498e83c1a73128295860250b0b7edd4c723a32e9bc0d295c7c2ec337" + "sha256:37a13ba168a02ac54cc5891a42b1caec333e59b66addb7fa633ea8a6d73445c0", + "sha256:b21b072d0ccdf29297a82a2363359d99623597b8a265b8081760e4d0f7153c88" ], - "version": "==2.7.4" + "version": "==2.8.0" }, "pyparsing": { "hashes": [ @@ -1081,10 +1078,10 @@ }, "tqdm": { "hashes": [ - "sha256:2874fa525c051177583ec59c0fb4583e91f28ccd3f217ffad2acdb32d2c789ac", - "sha256:ab9b659241d82b8b51b2269ee243ec95286046bf06015c4e15a947cc15914211" + "sha256:2c44efa73b8914dba7807aefd09653ac63c22b5b4ea34f7a80973f418f1a3089", + "sha256:c23ac707e8e8aabb825e4d91f8e17247f9cc14b0d64dd9e97be0781e9e525bba" ], - "version": "==4.56.1" + "version": "==4.58.0" }, "twine": { "hashes": [ From b3ceb293d9e69295a190fed93517cbe1b7372154 Mon Sep 17 00:00:00 2001 From: Hadi Alqattan Date: Fri, 5 Mar 2021 22:58:00 +0300 Subject: [PATCH 37/54] Remove unused import statements using Pycln. (#2021) * remove unused imports using Pycln. * reverse comma style. --- src/blib2to3/pgen2/driver.py | 3 --- src/blib2to3/pgen2/parse.py | 2 -- src/blib2to3/pgen2/pgen.py | 1 - src/blib2to3/pytree.py | 1 - 4 files changed, 7 deletions(-) diff --git a/src/blib2to3/pgen2/driver.py b/src/blib2to3/pgen2/driver.py index 81940f78f0f..af1dc6b8aeb 100644 --- a/src/blib2to3/pgen2/driver.py +++ b/src/blib2to3/pgen2/driver.py @@ -16,7 +16,6 @@ __all__ = ["Driver", "load_grammar"] # Python imports -import codecs import io import os import logging @@ -24,7 +23,6 @@ import sys from typing import ( Any, - Callable, IO, Iterable, List, @@ -32,7 +30,6 @@ Text, Tuple, Union, - Sequence, ) # Pgen imports diff --git a/src/blib2to3/pgen2/parse.py b/src/blib2to3/pgen2/parse.py index 8c374d35b42..47c8f02b4f5 100644 --- a/src/blib2to3/pgen2/parse.py +++ b/src/blib2to3/pgen2/parse.py @@ -15,8 +15,6 @@ from typing import ( Optional, Text, - Sequence, - Any, Union, Tuple, Dict, diff --git a/src/blib2to3/pgen2/pgen.py b/src/blib2to3/pgen2/pgen.py index a685145933c..564ebbd1184 100644 --- a/src/blib2to3/pgen2/pgen.py +++ b/src/blib2to3/pgen2/pgen.py @@ -8,7 +8,6 @@ Any, Dict, IO, - Iterable, Iterator, List, Optional, diff --git a/src/blib2to3/pytree.py b/src/blib2to3/pytree.py index 6dba3c7bb15..0c074f6a4ac 100644 --- a/src/blib2to3/pytree.py +++ b/src/blib2to3/pytree.py @@ -25,7 +25,6 @@ Union, Set, Iterable, - Sequence, ) from blib2to3.pgen2.grammar import Grammar From 1f7e73506c8b8c37d72becad5c9d8f1ab61644e1 Mon Sep 17 00:00:00 2001 From: John Meow Date: Sat, 6 Mar 2021 07:22:19 +0300 Subject: [PATCH 38/54] Add ALE (#1753) --- docs/editor_integration.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/editor_integration.md b/docs/editor_integration.md index bc7c2e7b7be..ae24c768882 100644 --- a/docs/editor_integration.md +++ b/docs/editor_integration.md @@ -111,6 +111,8 @@ $ black --help ## Vim +### Official plugin + Commands and shortcuts: - `:Black` to format the entire file (ranges not supported); @@ -233,6 +235,17 @@ If you later want to update _Black_, you should do it like this: $ pip install -U black --no-binary regex,typed-ast ``` +### With ALE + +1. Install [`ale`](https://github.com/dense-analysis/ale) +2. Install `black` +3. Add this to your vimrc: + + ```vim + let g:ale_fixers = {} + let g:ale_fixers.python = ['black'] + ``` + ## Gedit gedit is the default text editor of the GNOME, Unix like Operating Systems. Open gedit From b332cfa655dedfeb74974abdac1fb7b55d7e62ea Mon Sep 17 00:00:00 2001 From: Richard Si <63936253+ichard26@users.noreply.github.com> Date: Sat, 6 Mar 2021 15:02:25 -0500 Subject: [PATCH 39/54] Add missing changelog entry for fmt: skip (#2025) --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 90e5143fafe..e6dcc1b967d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -33,6 +33,8 @@ - Added `--stdin-filename` argument to allow stdin to respect `--force-exclude` rules (#1780) +- Lines ending with `fmt: skip` will now be not formatted (#1800) + #### _Packaging_ - Self-contained native _Black_ binaries are now provided for releases via GitHub From 5446a92f0161e398de765bf9532d8c76c5652333 Mon Sep 17 00:00:00 2001 From: Konstantin Alekseev Date: Mon, 8 Mar 2021 03:13:25 +0300 Subject: [PATCH 40/54] Use vim autoload script (#1157) --- autoload/black.vim | 172 +++++++++++++++++++++++++++++++++++++++++++++ plugin/black.vim | 172 ++------------------------------------------- 2 files changed, 179 insertions(+), 165 deletions(-) create mode 100644 autoload/black.vim diff --git a/autoload/black.vim b/autoload/black.vim new file mode 100644 index 00000000000..f0357b07123 --- /dev/null +++ b/autoload/black.vim @@ -0,0 +1,172 @@ +python3 << EndPython3 +import collections +import os +import sys +import vim +from distutils.util import strtobool + + +class Flag(collections.namedtuple("FlagBase", "name, cast")): + @property + def var_name(self): + return self.name.replace("-", "_") + + @property + def vim_rc_name(self): + name = self.var_name + if name == "line_length": + name = name.replace("_", "") + return "g:black_" + name + + +FLAGS = [ + Flag(name="line_length", cast=int), + Flag(name="fast", cast=strtobool), + Flag(name="string_normalization", cast=strtobool), + Flag(name="quiet", cast=strtobool), +] + + +def _get_python_binary(exec_prefix): + try: + default = vim.eval("g:pymode_python").strip() + except vim.error: + default = "" + if default and os.path.exists(default): + return default + if sys.platform[:3] == "win": + return exec_prefix / 'python.exe' + return exec_prefix / 'bin' / 'python3' + +def _get_pip(venv_path): + if sys.platform[:3] == "win": + return venv_path / 'Scripts' / 'pip.exe' + return venv_path / 'bin' / 'pip' + +def _get_virtualenv_site_packages(venv_path, pyver): + if sys.platform[:3] == "win": + return venv_path / 'Lib' / 'site-packages' + return venv_path / 'lib' / f'python{pyver[0]}.{pyver[1]}' / 'site-packages' + +def _initialize_black_env(upgrade=False): + pyver = sys.version_info[:3] + if pyver < (3, 6, 2): + print("Sorry, Black requires Python 3.6.2+ to run.") + return False + + from pathlib import Path + import subprocess + import venv + virtualenv_path = Path(vim.eval("g:black_virtualenv")).expanduser() + virtualenv_site_packages = str(_get_virtualenv_site_packages(virtualenv_path, pyver)) + first_install = False + if not virtualenv_path.is_dir(): + print('Please wait, one time setup for Black.') + _executable = sys.executable + _base_executable = getattr(sys, "_base_executable", _executable) + try: + executable = str(_get_python_binary(Path(sys.exec_prefix))) + sys.executable = executable + sys._base_executable = executable + print(f'Creating a virtualenv in {virtualenv_path}...') + print('(this path can be customized in .vimrc by setting g:black_virtualenv)') + venv.create(virtualenv_path, with_pip=True) + except Exception: + print('Encountered exception while creating virtualenv (see traceback below).') + print(f'Removing {virtualenv_path}...') + import shutil + shutil.rmtree(virtualenv_path) + raise + finally: + sys.executable = _executable + sys._base_executable = _base_executable + first_install = True + if first_install: + print('Installing Black with pip...') + if upgrade: + print('Upgrading Black with pip...') + if first_install or upgrade: + subprocess.run([str(_get_pip(virtualenv_path)), 'install', '-U', 'black'], stdout=subprocess.PIPE) + print('DONE! You are all set, thanks for waiting ✨ 🍰 ✨') + if first_install: + print('Pro-tip: to upgrade Black in the future, use the :BlackUpgrade command and restart Vim.\n') + if virtualenv_site_packages not in sys.path: + sys.path.insert(0, virtualenv_site_packages) + return True + +if _initialize_black_env(): + import black + import time + +def Black(): + start = time.time() + configs = get_configs() + mode = black.FileMode( + line_length=configs["line_length"], + string_normalization=configs["string_normalization"], + is_pyi=vim.current.buffer.name.endswith('.pyi'), + ) + quiet = configs["quiet"] + + buffer_str = '\n'.join(vim.current.buffer) + '\n' + try: + new_buffer_str = black.format_file_contents( + buffer_str, + fast=configs["fast"], + mode=mode, + ) + except black.NothingChanged: + if not quiet: + print(f'Already well formatted, good job. (took {time.time() - start:.4f}s)') + except Exception as exc: + print(exc) + else: + current_buffer = vim.current.window.buffer + cursors = [] + for i, tabpage in enumerate(vim.tabpages): + if tabpage.valid: + for j, window in enumerate(tabpage.windows): + if window.valid and window.buffer == current_buffer: + cursors.append((i, j, window.cursor)) + vim.current.buffer[:] = new_buffer_str.split('\n')[:-1] + for i, j, cursor in cursors: + window = vim.tabpages[i].windows[j] + try: + window.cursor = cursor + except vim.error: + window.cursor = (len(window.buffer), 0) + if not quiet: + print(f'Reformatted in {time.time() - start:.4f}s.') + +def get_configs(): + path_pyproject_toml = black.find_pyproject_toml(vim.eval("fnamemodify(getcwd(), ':t')")) + if path_pyproject_toml: + toml_config = black.parse_pyproject_toml(path_pyproject_toml) + else: + toml_config = {} + + return { + flag.var_name: flag.cast(toml_config.get(flag.name, vim.eval(flag.vim_rc_name))) + for flag in FLAGS + } + + +def BlackUpgrade(): + _initialize_black_env(upgrade=True) + +def BlackVersion(): + print(f'Black, version {black.__version__} on Python {sys.version}.') + +EndPython3 + +function black#Black() + :py3 Black() +endfunction + +function black#BlackUpgrade() + :py3 BlackUpgrade() +endfunction + +function black#BlackVersion() + :py3 BlackVersion() +endfunction diff --git a/plugin/black.vim b/plugin/black.vim index 39a31f14b52..b5edb2a6ade 100644 --- a/plugin/black.vim +++ b/plugin/black.vim @@ -2,7 +2,7 @@ " Author: Łukasz Langa " Created: Mon Mar 26 23:27:53 2018 -0700 " Requires: Vim Ver7.0+ -" Version: 1.1 +" Version: 1.2 " " Documentation: " This plugin formats Python files. @@ -12,6 +12,8 @@ " - initial version " 1.1: " - restore cursor/window position after formatting +" 1.2: +" - use autoload script if v:version < 700 || !has('python3') func! __BLACK_MISSING() @@ -24,7 +26,7 @@ if v:version < 700 || !has('python3') endif if exists("g:load_black") - finish + finish endif let g:load_black = "py1.0" @@ -52,167 +54,7 @@ if !exists("g:black_quiet") let g:black_quiet = 0 endif -python3 << EndPython3 -import collections -import os -import sys -import vim -from distutils.util import strtobool - -class Flag(collections.namedtuple("FlagBase", "name, cast")): - @property - def var_name(self): - return self.name.replace("-", "_") - - @property - def vim_rc_name(self): - name = self.var_name - if name == "line_length": - name = name.replace("_", "") - return "g:black_" + name - - -FLAGS = [ - Flag(name="line_length", cast=int), - Flag(name="fast", cast=strtobool), - Flag(name="string_normalization", cast=strtobool), - Flag(name="quiet", cast=strtobool), -] - - -def _get_python_binary(exec_prefix): - try: - default = vim.eval("g:pymode_python").strip() - except vim.error: - default = "" - if default and os.path.exists(default): - return default - if sys.platform[:3] == "win": - return exec_prefix / 'python.exe' - return exec_prefix / 'bin' / 'python3' - -def _get_pip(venv_path): - if sys.platform[:3] == "win": - return venv_path / 'Scripts' / 'pip.exe' - return venv_path / 'bin' / 'pip' - -def _get_virtualenv_site_packages(venv_path, pyver): - if sys.platform[:3] == "win": - return venv_path / 'Lib' / 'site-packages' - return venv_path / 'lib' / f'python{pyver[0]}.{pyver[1]}' / 'site-packages' - -def _initialize_black_env(upgrade=False): - pyver = sys.version_info[:3] - if pyver < (3, 6, 2): - print("Sorry, Black requires Python 3.6.2+ to run.") - return False - - from pathlib import Path - import subprocess - import venv - virtualenv_path = Path(vim.eval("g:black_virtualenv")).expanduser() - virtualenv_site_packages = str(_get_virtualenv_site_packages(virtualenv_path, pyver)) - first_install = False - if not virtualenv_path.is_dir(): - print('Please wait, one time setup for Black.') - _executable = sys.executable - _base_executable = getattr(sys, "_base_executable", _executable) - try: - executable = str(_get_python_binary(Path(sys.exec_prefix))) - sys.executable = executable - sys._base_executable = executable - print(f'Creating a virtualenv in {virtualenv_path}...') - print('(this path can be customized in .vimrc by setting g:black_virtualenv)') - venv.create(virtualenv_path, with_pip=True) - except Exception: - print('Encountered exception while creating virtualenv (see traceback below).') - print(f'Removing {virtualenv_path}...') - import shutil - shutil.rmtree(virtualenv_path) - raise - finally: - sys.executable = _executable - sys._base_executable = _base_executable - first_install = True - if first_install: - print('Installing Black with pip...') - if upgrade: - print('Upgrading Black with pip...') - if first_install or upgrade: - subprocess.run([str(_get_pip(virtualenv_path)), 'install', '-U', 'black'], stdout=subprocess.PIPE) - print('DONE! You are all set, thanks for waiting ✨ 🍰 ✨') - if first_install: - print('Pro-tip: to upgrade Black in the future, use the :BlackUpgrade command and restart Vim.\n') - if virtualenv_site_packages not in sys.path: - sys.path.insert(0, virtualenv_site_packages) - return True - -if _initialize_black_env(): - import black - import time - -def Black(): - start = time.time() - configs = get_configs() - mode = black.FileMode( - line_length=configs["line_length"], - string_normalization=configs["string_normalization"], - is_pyi=vim.current.buffer.name.endswith('.pyi'), - ) - quiet = configs["quiet"] - - buffer_str = '\n'.join(vim.current.buffer) + '\n' - try: - new_buffer_str = black.format_file_contents( - buffer_str, - fast=configs["fast"], - mode=mode, - ) - except black.NothingChanged: - if not quiet: - print(f'Already well formatted, good job. (took {time.time() - start:.4f}s)') - except Exception as exc: - print(exc) - else: - current_buffer = vim.current.window.buffer - cursors = [] - for i, tabpage in enumerate(vim.tabpages): - if tabpage.valid: - for j, window in enumerate(tabpage.windows): - if window.valid and window.buffer == current_buffer: - cursors.append((i, j, window.cursor)) - vim.current.buffer[:] = new_buffer_str.split('\n')[:-1] - for i, j, cursor in cursors: - window = vim.tabpages[i].windows[j] - try: - window.cursor = cursor - except vim.error: - window.cursor = (len(window.buffer), 0) - if not quiet: - print(f'Reformatted in {time.time() - start:.4f}s.') - -def get_configs(): - path_pyproject_toml = black.find_pyproject_toml(vim.eval("fnamemodify(getcwd(), ':t')")) - if path_pyproject_toml: - toml_config = black.parse_pyproject_toml(path_pyproject_toml) - else: - toml_config = {} - - return { - flag.var_name: flag.cast(toml_config.get(flag.name, vim.eval(flag.vim_rc_name))) - for flag in FLAGS - } - - -def BlackUpgrade(): - _initialize_black_env(upgrade=True) - -def BlackVersion(): - print(f'Black, version {black.__version__} on Python {sys.version}.') - -EndPython3 - -command! Black :py3 Black() -command! BlackUpgrade :py3 BlackUpgrade() -command! BlackVersion :py3 BlackVersion() +command! Black :call black#Black() +command! BlackUpgrade :call black#BlackUpgrade() +command! BlackVersion :call black#BlackVersion() From d62d677ca2135714d6159f6b4839983fb0a557c8 Mon Sep 17 00:00:00 2001 From: Jairo Llopis Date: Thu, 18 Mar 2021 15:14:15 +0000 Subject: [PATCH 41/54] Recommend B950 + 88 char limit instead of 80 (#2050) [The section about line length][1] was contradictory. On one side, it said: > Black will try to respect that [line length limit]. However, sometimes it won't be able to without breaking other rules. In those rare cases, auto-formatted code will exceed your allotted limit. So black doesn't guarantee that your code is formatted at 88 chars, even when configured with `--line-length=88` (default). Black uses this limit as a "hint" more than a "rule". OTOH, it also said: > If you're using Flake8, you can bump max-line-length to 88 and forget about it. Alternatively, use Bugbear's B950 warning instead of E501 and keep the max line length at 80 which you are probably already using. But that's not true. You can't "forget about it" because Black sometimes won't respect the limit. Both E501 at 88 and B950 at 80 behave the same: linter error at 89+ length. So, if Black happens to decide that a line of code is better at 90 characters that some other fancy style, you land on a unlucky situation where both tools will fight. So, AFAICS, the best way to align flake8 and black is to: 1. Use flake8-bugbear 2. Enable B950 3. Disable E501 4. Set `max-line-length = 88` This way, we also tell flake8 that 88 limit is a "hint" and not a "rule". The real rule will be 88 + 10%. If black decides that a line fits better in 97 characters than in 88 + some formatting, _that_ probably means your code has a real problem. To avoid further confusion, I change the official recommendation here. [1]: https://github.com/PyCQA/flake8-bugbear/tree/e82bb8d8b855adbf1f6f9757fb1527e93039e0d9#opinionated-warnings --- docs/the_black_code_style.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/the_black_code_style.md b/docs/the_black_code_style.md index a4e55c1744c..1cc591b8031 100644 --- a/docs/the_black_code_style.md +++ b/docs/the_black_code_style.md @@ -189,22 +189,22 @@ harder to work with line lengths exceeding 100 characters. It also adversely aff side-by-side diff review on typical screen resolutions. Long lines also make it harder to present code neatly in documentation or talk slides. -If you're using Flake8, you can bump `max-line-length` to 88 and forget about it. -Alternatively, use [Bugbear](https://github.com/PyCQA/flake8-bugbear)'s B950 warning -instead of E501 and keep the max line length at 80 which you are probably already using. -You'd do it like this: +If you're using Flake8, you can bump `max-line-length` to 88 and mostly forget about it. +However, it's better if you use [Bugbear](https://github.com/PyCQA/flake8-bugbear)'s +B950 warning instead of E501, and bump the max line length to 88 (or the `--line-length` +you used for black), which will align more with black's _"try to respect +`--line-length`, but don't become crazy if you can't"_. You'd do it like this: ```ini [flake8] -max-line-length = 80 +max-line-length = 88 ... select = C,E,F,W,B,B950 extend-ignore = E203, E501 ``` -You'll find _Black_'s own .flake8 config file is configured like this. Explanation of -why E203 is disabled can be found further in this documentation. And if you're curious -about the reasoning behind B950, +Explanation of why E203 is disabled can be found further in this documentation. And if +you're curious about the reasoning behind B950, [Bugbear's documentation](https://github.com/PyCQA/flake8-bugbear#opinionated-warnings) explains it. The tl;dr is "it's like highway speed limits, we won't bother you if you overdo it by a few km/h". From 0be7f96d9ce764db1b2b6e176f6e74a3cdece665 Mon Sep 17 00:00:00 2001 From: Richard Si <63936253+ichard26@users.noreply.github.com> Date: Sat, 20 Mar 2021 15:15:55 -0400 Subject: [PATCH 42/54] Fix indentation in docs/editor_integration.md (#2056) Numbered list entries' bodies need to be indented or else the list won't render correctly. --- docs/editor_integration.md | 68 +++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/docs/editor_integration.md b/docs/editor_integration.md index ae24c768882..f2d21f21113 100644 --- a/docs/editor_integration.md +++ b/docs/editor_integration.md @@ -12,38 +12,38 @@ Options include the following: 1. Install `black`. -```console -$ pip install black -``` + ```console + $ pip install black + ``` 2. Locate your `black` installation folder. -On macOS / Linux / BSD: + On macOS / Linux / BSD: -```console -$ which black -/usr/local/bin/black # possible location -``` + ```console + $ which black + /usr/local/bin/black # possible location + ``` -On Windows: + On Windows: -```console -$ where black -%LocalAppData%\Programs\Python\Python36-32\Scripts\black.exe # possible location -``` + ```console + $ where black + %LocalAppData%\Programs\Python\Python36-32\Scripts\black.exe # possible location + ``` -Note that if you are using a virtual environment detected by PyCharm, this is an -unneeded step. In this case the path to `black` is `$PyInterpreterDirectory$/black`. + Note that if you are using a virtual environment detected by PyCharm, this is an + unneeded step. In this case the path to `black` is `$PyInterpreterDirectory$/black`. 3. Open External tools in PyCharm/IntelliJ IDEA -On macOS: + On macOS: -`PyCharm -> Preferences -> Tools -> External Tools` + `PyCharm -> Preferences -> Tools -> External Tools` -On Windows / Linux / BSD: + On Windows / Linux / BSD: -`File -> Settings -> Tools -> External Tools` + `File -> Settings -> Tools -> External Tools` 4. Click the + icon to add a new external tool with the following values: @@ -83,28 +83,28 @@ Wing supports black via the OS Commands tool, as explained in the Wing documenta 1. Install `black`. -```console -$ pip install black -``` + ```console + $ pip install black + ``` 2. Make sure it runs from the command line, e.g. -```console -$ black --help -``` + ```console + $ black --help + ``` 3. In Wing IDE, activate the **OS Commands** panel and define the command **black** to execute black on the currently selected file: -- Use the Tools -> OS Commands menu selection -- click on **+** in **OS Commands** -> New: Command line.. - - Title: black - - Command Line: black %s - - I/O Encoding: Use Default - - Key Binding: F1 - - [x] Raise OS Commands when executed - - [x] Auto-save files before execution - - [x] Line mode + - Use the Tools -> OS Commands menu selection + - click on **+** in **OS Commands** -> New: Command line.. + - Title: black + - Command Line: black %s + - I/O Encoding: Use Default + - Key Binding: F1 + - [x] Raise OS Commands when executed + - [x] Auto-save files before execution + - [x] Line mode 4. Select a file in the editor and press **F1** , or whatever key binding you selected in step 3, to reformat the file. From 5d33f20a2a2c85cfb521ae9c5f9254bfe9fc2fd9 Mon Sep 17 00:00:00 2001 From: Cooper Lees Date: Sun, 21 Mar 2021 13:05:24 -0700 Subject: [PATCH 43/54] Add a GitHub CHANGELOG/News Check (#2057) - Run grep to see commit has a line mentioning it to CHANGES.md - Also add a label to disable this being required for PRs that don't need a change entry --- .github/workflows/changelog.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/changelog.yml diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml new file mode 100644 index 00000000000..434950d24f9 --- /dev/null +++ b/.github/workflows/changelog.yml @@ -0,0 +1,21 @@ +name: changelog + +on: + pull_request: + types: [opened, synchronize, labeled, unlabeled, reopened] + +jobs: + build: + name: Changelog Entry Check + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Grep CHANGES.md for PR number + if: contains(github.event.pull_request.labels.*.name, 'skip news') != true + run: | + grep -P "PR #${{ github.event.pull_request.number }}[^0-9]" CHANGES.md || \ + (echo "Please add 'PR #${{ github.event.pull_request.number }}' change line to CHANGES.md" && \ + exit 1) From 580b4fe8bc8d859c228f2eea1c8335bb3e911b12 Mon Sep 17 00:00:00 2001 From: Richard Si <63936253+ichard26@users.noreply.github.com> Date: Wed, 24 Mar 2021 19:38:07 -0400 Subject: [PATCH 44/54] Add entry for `--extend-exclude` in the right place (#2061) The PR author added the changelog entry for their `extend-exclude` addition in `docs/change_log.md` which is understandable but incorrect as it will be overwritten since it's autogenerated from the readme. --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index e6dcc1b967d..61fc35f43a4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -26,6 +26,8 @@ - use lowercase hex strings (#1692) +- added `--extend-exclude` argument (PR #2005) + - speed up caching by avoiding pathlib (#1950) - `--diff` correctly indicates when a file doesn't end in a newline (#1662) From 4218ae18c06df82904b9c9eac166510ac0ebee7c Mon Sep 17 00:00:00 2001 From: Shantanu <12621235+hauntsaninja@users.noreply.github.com> Date: Fri, 26 Mar 2021 07:21:18 -0700 Subject: [PATCH 45/54] Add `--skip-magic-trailing-comma` to CHANGES.md (#2064) --- CHANGES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 61fc35f43a4..7da7be7b842 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,9 @@ - `Black` no longer adds an incorrect space after a parenthesized assignment expression in if/while statements (#1655) +- Added `--skip-magic-trailing-comma` / `-C` to avoid using trailing commas as a reason + to split lines (#1824) + - fixed a crash when PWD=/ on POSIX (#1631) - fixed "I/O operation on closed file" when using --diff (#1664) From dc8b0a43837a6280e0d7d7d4e71a5282083c6b01 Mon Sep 17 00:00:00 2001 From: Mark Bell Date: Mon, 29 Mar 2021 00:01:37 +0100 Subject: [PATCH 46/54] GREP for PR reference accepts references that are split over a line (#2072) Fixes #2070 --- .github/workflows/changelog.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index 434950d24f9..58a8c092edb 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -16,6 +16,6 @@ jobs: - name: Grep CHANGES.md for PR number if: contains(github.event.pull_request.labels.*.name, 'skip news') != true run: | - grep -P "PR #${{ github.event.pull_request.number }}[^0-9]" CHANGES.md || \ + grep -Pz "PR( |\n\s*)#${{ github.event.pull_request.number }}[^0-9]" CHANGES.md || \ (echo "Please add 'PR #${{ github.event.pull_request.number }}' change line to CHANGES.md" && \ exit 1) From c702588daa9f75855119d0656661ac17934efe35 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Mar 2021 18:59:57 -0700 Subject: [PATCH 47/54] Bump pygments from 2.6.1 to 2.7.4 in /docs (#2076) Bumps [pygments](https://github.com/pygments/pygments) from 2.6.1 to 2.7.4. - [Release notes](https://github.com/pygments/pygments/releases) - [Changelog](https://github.com/pygments/pygments/blob/master/CHANGES) - [Commits](https://github.com/pygments/pygments/compare/2.6.1...2.7.4) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 4cad9bc205b..fcb6809cadc 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,3 @@ recommonmark==0.6.0 Sphinx==3.2.1 -Pygments==2.6.1 \ No newline at end of file +Pygments==2.7.4 \ No newline at end of file From ed9d58b7410f24446cedebd0f767b71b154f5f5b Mon Sep 17 00:00:00 2001 From: KotlinIsland Date: Tue, 16 Mar 2021 19:31:18 +1000 Subject: [PATCH 48/54] don't require typed-ast --- CHANGES.md | 5 +++++ README.md | 3 ++- setup.py | 3 ++- src/black/__init__.py | 22 ++++++++++++++++++++-- tox.ini | 2 +- 5 files changed, 30 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 7da7be7b842..97a3be33c93 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -40,6 +40,11 @@ - Lines ending with `fmt: skip` will now be not formatted (#1800) +- PR #2053: Black no longer relies on typed-ast for Python 3.8 and higher + +- PR #2053: Python 2 support is now optional, install with + `python3 -m pip install black[python2]` to maintain support. + #### _Packaging_ - Self-contained native _Black_ binaries are now provided for releases via GitHub diff --git a/README.md b/README.md index 411a8c8609d..0be356e3b84 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,8 @@ _Contents:_ **[Installation and usage](#installation-and-usage)** | ### Installation _Black_ can be installed by running `pip install black`. It requires Python 3.6.2+ to -run but you can reformat Python 2 code with it, too. +run. If you want to format Python 2 code as well, install with +`pip install black[python2]`. #### Install from GitHub diff --git a/setup.py b/setup.py index efdf6933025..856c7fadb0c 100644 --- a/setup.py +++ b/setup.py @@ -71,7 +71,7 @@ def get_long_description() -> str: "click>=7.1.2", "appdirs", "toml>=0.10.1", - "typed-ast>=1.4.2", + "typed-ast>=1.4.2; python_version < '3.8'", "regex>=2020.1.8", "pathspec>=0.6, <1", "dataclasses>=0.6; python_version < '3.7'", @@ -81,6 +81,7 @@ def get_long_description() -> str: extras_require={ "d": ["aiohttp>=3.3.2", "aiohttp-cors"], "colorama": ["colorama>=0.4.3"], + "python2": ["typed-ast>=1.4.2"], }, test_suite="tests.test_black", classifiers=[ diff --git a/src/black/__init__.py b/src/black/__init__.py index a8f4f89a6bb..52a57695aef 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -48,7 +48,20 @@ from dataclasses import dataclass, field, replace import click import toml -from typed_ast import ast3, ast27 + +try: + from typed_ast import ast3, ast27 +except ImportError: + if sys.version_info < (3, 8): + print( + "The typed_ast package is not installed.\n" + "You can install it with `python3 -m pip install typed-ast`.", + file=sys.stderr, + ) + sys.exit(1) + else: + ast3 = ast27 = ast + from pathspec import PathSpec # lib2to3 fork @@ -6336,7 +6349,12 @@ def parse_ast(src: str) -> Union[ast.AST, ast3.AST, ast27.AST]: return ast3.parse(src, filename, feature_version=feature_version) except SyntaxError: continue - + if ast27.__name__ == "ast": + raise SyntaxError( + "The requested source code has invalid Python 3 syntax.\n" + "If you are trying to format Python 2 files please reinstall Black" + " with the 'python2' extra: `python3 -m pip install black[python2]`." + ) return ast27.parse(src) diff --git a/tox.ini b/tox.ini index 500a2cad579..9bb809abe41 100644 --- a/tox.ini +++ b/tox.ini @@ -7,7 +7,7 @@ skip_install = True deps = -r{toxinidir}/test_requirements.txt commands = - pip install -e .[d] + pip install -e .[d,python2] coverage erase coverage run -m pytest tests coverage report From 9451c57d1c60d70ddd55e21b44382ca96637398e Mon Sep 17 00:00:00 2001 From: Harish Rajagopal Date: Thu, 1 Apr 2021 18:39:18 +0200 Subject: [PATCH 49/54] Support for top-level user configuration (#1899) * Added support for top-level user configuration At the user level, a TOML config can be specified in the following locations: * Windows: ~\.black * Unix-like: $XDG_CONFIG_HOME/black (~/.config/black fallback) Instead of changing env vars for the entire black-primer process, they are now changed only for the black subprocess, using a tmpdir. --- README.md | 14 ++++++++++++ docs/pyproject_toml.md | 14 ++++++++++++ src/black/__init__.py | 22 ++++++++++++++++++- src/black_primer/lib.py | 47 ++++++++++++++++++++++++----------------- tests/test_black.py | 36 +++++++++++++++++++++++++++++-- 5 files changed, 111 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 0be356e3b84..b19e6e5e098 100644 --- a/README.md +++ b/README.md @@ -293,6 +293,20 @@ parent directories. It stops looking when it finds the file, or a `.git` directo If you're formatting standard input, _Black_ will look for configuration starting from the current working directory. +You can use a "global" configuration, stored in a specific location in your home +directory. This will be used as a fallback configuration, that is, it will be used if +and only if _Black_ doesn't find any configuration as mentioned above. Depending on your +operating system, this configuration file should be stored as: + +- Windows: `~\.black` +- Unix-like (Linux, MacOS, etc.): `$XDG_CONFIG_HOME/black` (`~/.config/black` if the + `XDG_CONFIG_HOME` environment variable is not set) + +Note that these are paths to the TOML file itself (meaning that they shouldn't be named +as `pyproject.toml`), not directories where you store the configuration. Here, `~` +refers to the path to your home directory. On Windows, this will be something like +`C:\\Users\UserName`. + You can also explicitly specify the path to a particular file that you want with `--config`. In this situation _Black_ will not look for any other file. diff --git a/docs/pyproject_toml.md b/docs/pyproject_toml.md index 9acc4c03d7c..77c12b76be9 100644 --- a/docs/pyproject_toml.md +++ b/docs/pyproject_toml.md @@ -28,6 +28,20 @@ parent directories. It stops looking when it finds the file, or a `.git` directo If you're formatting standard input, _Black_ will look for configuration starting from the current working directory. +You can use a "global" configuration, stored in a specific location in your home +directory. This will be used as a fallback configuration, that is, it will be used if +and only if _Black_ doesn't find any configuration as mentioned above. Depending on your +operating system, this configuration file should be stored as: + +- Windows: `~\.black` +- Unix-like (Linux, MacOS, etc.): `$XDG_CONFIG_HOME/black` (`~/.config/black` if the + `XDG_CONFIG_HOME` environment variable is not set) + +Note that these are paths to the TOML file itself (meaning that they shouldn't be named +as `pyproject.toml`), not directories where you store the configuration. Here, `~` +refers to the path to your home directory. On Windows, this will be something like +`C:\\Users\UserName`. + You can also explicitly specify the path to a particular file that you want with `--config`. In this situation _Black_ will not look for any other file. diff --git a/src/black/__init__.py b/src/black/__init__.py index 52a57695aef..e85ffb37f88 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -306,7 +306,11 @@ def find_pyproject_toml(path_search_start: Iterable[str]) -> Optional[str]: """Find the absolute filepath to a pyproject.toml if it exists""" path_project_root = find_project_root(path_search_start) path_pyproject_toml = path_project_root / "pyproject.toml" - return str(path_pyproject_toml) if path_pyproject_toml.is_file() else None + if path_pyproject_toml.is_file(): + return str(path_pyproject_toml) + + path_user_pyproject_toml = find_user_pyproject_toml() + return str(path_user_pyproject_toml) if path_user_pyproject_toml.is_file() else None def parse_pyproject_toml(path_config: str) -> Dict[str, Any]: @@ -6248,6 +6252,22 @@ def find_project_root(srcs: Iterable[str]) -> Path: return directory +@lru_cache() +def find_user_pyproject_toml() -> Path: + r"""Return the path to the top-level user configuration for black. + + This looks for ~\.black on Windows and ~/.config/black on Linux and other + Unix systems. + """ + if sys.platform == "win32": + # Windows + user_config_path = Path.home() / ".black" + else: + config_root = os.environ.get("XDG_CONFIG_HOME", "~/.config") + user_config_path = Path(config_root).expanduser() / "black" + return user_config_path.resolve() + + @dataclass class Report: """Provides a reformatting counter. Can be rendered with `str(report)`.""" diff --git a/src/black_primer/lib.py b/src/black_primer/lib.py index 39ae93ba516..7999f6a3e36 100644 --- a/src/black_primer/lib.py +++ b/src/black_primer/lib.py @@ -13,6 +13,7 @@ from shutil import rmtree, which from subprocess import CalledProcessError from sys import version_info +from tempfile import TemporaryDirectory from typing import Any, Callable, Dict, NamedTuple, Optional, Sequence, Tuple from urllib.parse import urlparse @@ -121,28 +122,36 @@ async def black_run( cmd.extend(*project_config["cli_arguments"]) cmd.extend(["--check", "--diff", "."]) - try: - _stdout, _stderr = await _gen_check_output(cmd, cwd=repo_path) - except asyncio.TimeoutError: - results.stats["failed"] += 1 - LOG.error(f"Running black for {repo_path} timed out ({cmd})") - except CalledProcessError as cpe: - # TODO: Tune for smarter for higher signal - # If any other return value than 1 we raise - can disable project in config - if cpe.returncode == 1: - if not project_config["expect_formatting_changes"]: + with TemporaryDirectory() as tmp_path: + # Prevent reading top-level user configs by manipulating envionment variables + env = { + **os.environ, + "XDG_CONFIG_HOME": tmp_path, # Unix-like + "USERPROFILE": tmp_path, # Windows (changes `Path.home()` output) + } + + try: + _stdout, _stderr = await _gen_check_output(cmd, cwd=repo_path, env=env) + except asyncio.TimeoutError: + results.stats["failed"] += 1 + LOG.error(f"Running black for {repo_path} timed out ({cmd})") + except CalledProcessError as cpe: + # TODO: Tune for smarter for higher signal + # If any other return value than 1 we raise - can disable project in config + if cpe.returncode == 1: + if not project_config["expect_formatting_changes"]: + results.stats["failed"] += 1 + results.failed_projects[repo_path.name] = cpe + else: + results.stats["success"] += 1 + return + elif cpe.returncode > 1: results.stats["failed"] += 1 results.failed_projects[repo_path.name] = cpe - else: - results.stats["success"] += 1 - return - elif cpe.returncode > 1: - results.stats["failed"] += 1 - results.failed_projects[repo_path.name] = cpe - return + return - LOG.error(f"Unknown error with {repo_path}") - raise + LOG.error(f"Unknown error with {repo_path}") + raise # If we get here and expect formatting changes something is up if project_config["expect_formatting_changes"]: diff --git a/tests/test_black.py b/tests/test_black.py index 72e16a324a5..c603233efc4 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -296,6 +296,7 @@ def test_expression_ff(self) -> None: def test_expression_diff(self) -> None: source, _ = read_data("expression.py") + config = THIS_DIR / "data" / "empty_pyproject.toml" expected, _ = read_data("expression.diff") tmp_file = Path(black.dump_to_file(source)) diff_header = re.compile( @@ -303,7 +304,9 @@ def test_expression_diff(self) -> None: r"\d\d:\d\d:\d\d\.\d\d\d\d\d\d \+\d\d\d\d" ) try: - result = BlackRunner().invoke(black.main, ["--diff", str(tmp_file)]) + result = BlackRunner().invoke( + black.main, ["--diff", str(tmp_file), f"--config={config}"] + ) self.assertEqual(result.exit_code, 0) finally: os.unlink(tmp_file) @@ -320,11 +323,12 @@ def test_expression_diff(self) -> None: def test_expression_diff_with_color(self) -> None: source, _ = read_data("expression.py") + config = THIS_DIR / "data" / "empty_pyproject.toml" expected, _ = read_data("expression.diff") tmp_file = Path(black.dump_to_file(source)) try: result = BlackRunner().invoke( - black.main, ["--diff", "--color", str(tmp_file)] + black.main, ["--diff", "--color", str(tmp_file), f"--config={config}"] ) finally: os.unlink(tmp_file) @@ -1842,6 +1846,34 @@ def test_find_project_root(self) -> None: self.assertEqual(black.find_project_root((src_dir,)), src_dir.resolve()) self.assertEqual(black.find_project_root((src_python,)), src_dir.resolve()) + @patch("black.find_user_pyproject_toml", black.find_user_pyproject_toml.__wrapped__) + def test_find_user_pyproject_toml_linux(self) -> None: + if system() == "Windows": + return + + # Test if XDG_CONFIG_HOME is checked + with TemporaryDirectory() as workspace: + tmp_user_config = Path(workspace) / "black" + with patch.dict("os.environ", {"XDG_CONFIG_HOME": workspace}): + self.assertEqual( + black.find_user_pyproject_toml(), tmp_user_config.resolve() + ) + + # Test fallback for XDG_CONFIG_HOME + with patch.dict("os.environ"): + os.environ.pop("XDG_CONFIG_HOME", None) + fallback_user_config = Path("~/.config").expanduser() / "black" + self.assertEqual( + black.find_user_pyproject_toml(), fallback_user_config.resolve() + ) + + def test_find_user_pyproject_toml_windows(self) -> None: + if system() != "Windows": + return + + user_config_path = Path.home() / ".black" + self.assertEqual(black.find_user_pyproject_toml(), user_config_path.resolve()) + def test_bpo_33660_workaround(self) -> None: if system() == "Windows": return From 125ed5b2601f0e74ded03b666132e3c37ae8af07 Mon Sep 17 00:00:00 2001 From: Cooper Lees Date: Thu, 1 Apr 2021 09:41:55 -0700 Subject: [PATCH 50/54] Add a GitHub Action to build + Upload black to PyPI (#1848) * Add a GitHub Action to build + Upload black to PyPI - Build a wheel + sdist - Upload via twine using token stored in GitHub secrets --- .github/workflows/lint.yml | 7 ++----- .github/workflows/pypi_upload.yml | 31 +++++++++++++++++++++++++++++++ .pre-commit-config.yaml | 2 +- 3 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/pypi_upload.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index e01e9ade5e2..c46042d71b9 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -12,17 +12,14 @@ jobs: github.repository runs-on: ubuntu-latest - strategy: - matrix: - python-version: [3.7] steps: - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} + - name: Set up Python uses: actions/setup-python@v2 with: - python-version: ${{ matrix.python-version }} + python-version: 3.7 - name: Install dependencies run: | diff --git a/.github/workflows/pypi_upload.yml b/.github/workflows/pypi_upload.yml new file mode 100644 index 00000000000..5df91d92165 --- /dev/null +++ b/.github/workflows/pypi_upload.yml @@ -0,0 +1,31 @@ +name: pypi_upload + +on: + release: + types: created + +jobs: + build: + name: PyPI Upload + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + + - name: Install latest pip, setuptools, twine + wheel + run: | + python -m pip install --upgrade pip setuptools twine wheel + + - name: Build wheels + run: | + python setup.py bdist_wheel + python setup.py sdist + + - name: Upload to PyPI via Twine + env: + TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} + run: | + twine upload --verbose -u '__token__' dist/* diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 292ed5727d9..48a7429c1f2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,7 @@ repos: types_or: [python, pyi] - repo: https://gitlab.com/pycqa/flake8 - rev: 3.8.1 + rev: 3.8.4 hooks: - id: flake8 additional_dependencies: [flake8-bugbear] From 53a6216cd57955837e84f6ea82ca650c86320b03 Mon Sep 17 00:00:00 2001 From: Cooper Lees Date: Thu, 1 Apr 2021 09:54:45 -0700 Subject: [PATCH 51/54] Add CONTRBUTING info about CHANGES.md requirement (#2073) Instruct contributors to add the change line to help save maintainer / releaser time --- .github/workflows/changelog.yml | 4 ++-- CONTRIBUTING.md | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index 58a8c092edb..d7ee50558d3 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -16,6 +16,6 @@ jobs: - name: Grep CHANGES.md for PR number if: contains(github.event.pull_request.labels.*.name, 'skip news') != true run: | - grep -Pz "PR( |\n\s*)#${{ github.event.pull_request.number }}[^0-9]" CHANGES.md || \ - (echo "Please add 'PR #${{ github.event.pull_request.number }}' change line to CHANGES.md" && \ + grep -Pz "\((\n\s*)?#${{ github.event.pull_request.number }}(\n\s*)?\)" CHANGES.md || \ + (echo "Please add '(#${{ github.event.pull_request.number }})' change line to CHANGES.md" && \ exit 1) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 571d870452b..8a3d8bf2830 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -58,6 +58,23 @@ $ tox -e fuzz $ black-primer [-k -w /tmp/black_test_repos] ``` +### News / Changelog Requirement + +`Black` has CI that will check for an entry corresponding to your PR in `CHANGES.md`. If +you feel this PR not require a changelog entry please state that in a comment and a +maintainer can add a `skip news` label to make the CI pass. Otherwise, please ensure you +have a line in the following format: + +```md +- `Black` is now more awesome (#X) +``` + +To workout X, checkout the latest issue and PR number and add 1. This is not perfect but +saves a lot of release overhead as now the releaser does not need to go back and workout +what to add to the `CHANGES.md` for each release. + +_Suggestions welcome on how this could be a better less invasive flow._ + ### Docs Testing If you make changes to docs, you can test they still build locally too. From 48dfda084a8c854a73c11b6c91c67deae5f86ca3 Mon Sep 17 00:00:00 2001 From: Richard Si <63936253+ichard26@users.noreply.github.com> Date: Thu, 1 Apr 2021 17:24:18 -0400 Subject: [PATCH 52/54] Push contributors to use Next PR Number (#2080) This is a tool of my own making. Right now our requirement to have the PR number in the changelog entry is pretty painful / annoying since the contributor either has to guess or add the # retroactively after the PR creation. This tool should make it way less painful by making it simple to get your PR number beforehand. --- CONTRIBUTING.md | 9 ++++----- docs/contributing_to_black.md | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8a3d8bf2830..bd6ebfca114 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -69,11 +69,10 @@ have a line in the following format: - `Black` is now more awesome (#X) ``` -To workout X, checkout the latest issue and PR number and add 1. This is not perfect but -saves a lot of release overhead as now the releaser does not need to go back and workout -what to add to the `CHANGES.md` for each release. - -_Suggestions welcome on how this could be a better less invasive flow._ +To workout X, please use +[Next PR Number](https://ichard26.github.io/next-pr-number/?owner=psf&name=black). This +is not perfect but saves a lot of release overhead as now the releaser does not need to +go back and workout what to add to the `CHANGES.md` for each release. ### Docs Testing diff --git a/docs/contributing_to_black.md b/docs/contributing_to_black.md index 562b43a76ac..b911b465afd 100644 --- a/docs/contributing_to_black.md +++ b/docs/contributing_to_black.md @@ -60,6 +60,22 @@ $ tox -e fuzz $ black-primer [-k -w /tmp/black_test_repos] ``` +### News / Changelog Requirement + +`Black` has CI that will check for an entry corresponding to your PR in `CHANGES.md`. If +you feel this PR not require a changelog entry please state that in a comment and a +maintainer can add a `skip news` label to make the CI pass. Otherwise, please ensure you +have a line in the following format: + +```md +- `Black` is now more awesome (#X) +``` + +To workout X, please use +[Next PR Number](https://ichard26.github.io/next-pr-number/?owner=psf&name=black). This +is not perfect but saves a lot of release overhead as now the releaser does not need to +go back and workout what to add to the `CHANGES.md` for each release. + ### Docs Testing If you make changes to docs, you can test they still build locally too. From 201b331e55948d187fc150101bebf5262e160290 Mon Sep 17 00:00:00 2001 From: Cooper Lees Date: Thu, 1 Apr 2021 16:15:50 -0700 Subject: [PATCH 53/54] Run lint in latest python + update precommit (#2081) - Lets move to latest and greatest of lints --- .github/workflows/lint.yml | 2 -- .pre-commit-config.yaml | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index c46042d71b9..2480a5ec131 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -18,8 +18,6 @@ jobs: - name: Set up Python uses: actions/setup-python@v2 - with: - python-version: 3.7 - name: Install dependencies run: | diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 48a7429c1f2..e461aa39c9d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,13 +13,13 @@ repos: types_or: [python, pyi] - repo: https://gitlab.com/pycqa/flake8 - rev: 3.8.4 + rev: 3.9.0 hooks: - id: flake8 additional_dependencies: [flake8-bugbear] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.780 + rev: v0.812 hooks: - id: mypy exclude: ^docs/conf.py From e114ef5514e95cb9908b38c2397978f2070c1b0e Mon Sep 17 00:00:00 2001 From: Jakub Warczarek Date: Sun, 4 Apr 2021 16:21:33 +0200 Subject: [PATCH 54/54] Get rid of redundant spaces in docs (#2085) Thanks! --- README.md | 14 +++++++------- src/black/__init__.py | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index b19e6e5e098..0bc0228b7d0 100644 --- a/README.md +++ b/README.md @@ -103,8 +103,8 @@ Options: split lines. --check Don't write the files back, just return the - status. Return code 0 means nothing would - change. Return code 1 means some files + status. Return code 0 means nothing would + change. Return code 1 means some files would be reformatted. Return code 123 means there was an internal error. @@ -119,20 +119,20 @@ Options: --include TEXT A regular expression that matches files and directories that should be included on - recursive searches. An empty value means + recursive searches. An empty value means all files are included regardless of the - name. Use forward slashes for directories - on all platforms (Windows, too). Exclusions + name. Use forward slashes for directories + on all platforms (Windows, too). Exclusions are calculated first, inclusions later. [default: \.pyi?$] --exclude TEXT A regular expression that matches files and directories that should be excluded on - recursive searches. An empty value means no + recursive searches. An empty value means no paths are excluded. Use forward slashes for directories on all platforms (Windows, too). Exclusions are calculated first, inclusions - later. [default: /(\.direnv|\.eggs|\.git|\. + later. [default: /(\.direnv|\.eggs|\.git|\. hg|\.mypy_cache|\.nox|\.tox|\.venv|\.svn|_bu ild|buck-out|build|dist)/] diff --git a/src/black/__init__.py b/src/black/__init__.py index e85ffb37f88..431ee027270 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -445,8 +445,8 @@ def validate_regex( "--check", is_flag=True, help=( - "Don't write the files back, just return the status. Return code 0 means" - " nothing would change. Return code 1 means some files would be reformatted." + "Don't write the files back, just return the status. Return code 0 means" + " nothing would change. Return code 1 means some files would be reformatted." " Return code 123 means there was an internal error." ), ) @@ -472,9 +472,9 @@ def validate_regex( callback=validate_regex, help=( "A regular expression that matches files and directories that should be" - " included on recursive searches. An empty value means all files are included" - " regardless of the name. Use forward slashes for directories on all platforms" - " (Windows, too). Exclusions are calculated first, inclusions later." + " included on recursive searches. An empty value means all files are included" + " regardless of the name. Use forward slashes for directories on all platforms" + " (Windows, too). Exclusions are calculated first, inclusions later." ), show_default=True, ) @@ -485,8 +485,8 @@ def validate_regex( callback=validate_regex, help=( "A regular expression that matches files and directories that should be" - " excluded on recursive searches. An empty value means no paths are excluded." - " Use forward slashes for directories on all platforms (Windows, too). " + " excluded on recursive searches. An empty value means no paths are excluded." + " Use forward slashes for directories on all platforms (Windows, too)." " Exclusions are calculated first, inclusions later." ), show_default=True,