From 977ccaa1f867521d1fbc48649f32308f623c0e60 Mon Sep 17 00:00:00 2001 From: jackdewinter Date: Sun, 8 Dec 2024 19:42:24 -0800 Subject: [PATCH] https://github.com/jackdewinter/pymarkdown/issues/1268 (#1282) * - [Issue 1208](https://github.com/jackdewinter/pymarkdown/issues/1208) --- Pipfile.lock | 593 ++++++++++++------------------ newdocs/src/changelog.md | 5 +- publish/coverage.json | 8 +- publish/pylint_suppression.json | 6 +- publish/test-results.json | 2 +- pymarkdown/plugins/rule_md_022.py | 39 +- test/rules/test_md022.py | 410 +++++++++++++++++++++ 7 files changed, 684 insertions(+), 379 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index aadcc842..b356e2d3 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "dc91cc8d53f578d832f96cc579e620b224c6bd01fe1f3b6504f2359a6979d640" + "sha256": "08f89d3ae311073b1e6ab7374965cca96d7b74ea6d7bf933b36271344e63502b" }, "pipfile-spec": 6, "requires": { @@ -24,133 +24,6 @@ "index": "pypi", "version": "==0.8.2" }, - "backports.tarfile": { - "hashes": [ - "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34", - "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991" - ], - "markers": "python_version < '3.12'", - "version": "==1.2.0" - }, - "certifi": { - "hashes": [ - "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", - "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9" - ], - "markers": "python_version >= '3.6'", - "version": "==2024.8.30" - }, - "charset-normalizer": { - "hashes": [ - "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621", - "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6", - "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8", - "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912", - "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c", - "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b", - "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d", - "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d", - "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95", - "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e", - "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", - "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64", - "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab", - "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be", - "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", - "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907", - "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0", - "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2", - "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62", - "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62", - "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23", - "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc", - "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284", - "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca", - "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455", - "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858", - "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b", - "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594", - "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc", - "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db", - "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b", - "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea", - "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6", - "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920", - "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749", - "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", - "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd", - "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99", - "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242", - "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee", - "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129", - "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2", - "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51", - "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee", - "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8", - "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", - "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613", - "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742", - "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe", - "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3", - "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5", - "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631", - "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7", - "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15", - "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c", - "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea", - "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417", - "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250", - "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88", - "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca", - "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa", - "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99", - "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149", - "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41", - "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574", - "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0", - "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f", - "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d", - "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654", - "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3", - "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19", - "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90", - "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578", - "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", - "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1", - "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51", - "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719", - "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236", - "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a", - "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c", - "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade", - "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944", - "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc", - "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6", - "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6", - "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27", - "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6", - "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2", - "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12", - "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf", - "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114", - "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7", - "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf", - "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d", - "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b", - "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed", - "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03", - "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4", - "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", - "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365", - "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a", - "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748", - "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b", - "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", - "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482" - ], - "markers": "python_full_version >= '3.7.0'", - "version": "==3.4.0" - }, "columnar": { "hashes": [ "sha256:8efb692a7e6ca07dcc8f4ea889960421331a5dffa8e5af81f0a67ad8ea1fc798", @@ -159,139 +32,6 @@ "index": "pypi", "version": "==1.4.1" }, - "docutils": { - "hashes": [ - "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6", - "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b" - ], - "markers": "python_version >= '3.7'", - "version": "==0.20.1" - }, - "idna": { - "hashes": [ - "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", - "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" - ], - "markers": "python_version >= '3.6'", - "version": "==3.10" - }, - "importlib-metadata": { - "hashes": [ - "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b", - "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7" - ], - "markers": "python_version >= '3.8'", - "version": "==8.5.0" - }, - "importlib-resources": { - "hashes": [ - "sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065", - "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717" - ], - "markers": "python_version < '3.9'", - "version": "==6.4.5" - }, - "jaraco.classes": { - "hashes": [ - "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", - "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790" - ], - "markers": "python_version >= '3.8'", - "version": "==3.4.0" - }, - "jaraco.context": { - "hashes": [ - "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3", - "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4" - ], - "markers": "python_version >= '3.8'", - "version": "==6.0.1" - }, - "jaraco.functools": { - "hashes": [ - "sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d", - "sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649" - ], - "markers": "python_version >= '3.8'", - "version": "==4.1.0" - }, - "keyring": { - "hashes": [ - "sha256:4c753b3ec91717fe713c4edd522d625889d8973a349b0e582622f49766de58e6", - "sha256:e67f8ac32b04be4714b42fe84ce7dad9c40985b9ca827c592cc303e7c26d9741" - ], - "markers": "python_version >= '3.8'", - "version": "==25.5.0" - }, - "markdown-it-py": { - "hashes": [ - "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", - "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb" - ], - "markers": "python_version >= '3.8'", - "version": "==3.0.0" - }, - "mdurl": { - "hashes": [ - "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", - "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" - ], - "markers": "python_version >= '3.7'", - "version": "==0.1.2" - }, - "more-itertools": { - "hashes": [ - "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef", - "sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6" - ], - "markers": "python_version >= '3.8'", - "version": "==10.5.0" - }, - "nh3": { - "hashes": [ - "sha256:0411beb0589eacb6734f28d5497ca2ed379eafab8ad8c84b31bb5c34072b7164", - "sha256:14c5a72e9fe82aea5fe3072116ad4661af5cf8e8ff8fc5ad3450f123e4925e86", - "sha256:19aaba96e0f795bd0a6c56291495ff59364f4300d4a39b29a0abc9cb3774a84b", - "sha256:34c03fa78e328c691f982b7c03d4423bdfd7da69cd707fe572f544cf74ac23ad", - "sha256:36c95d4b70530b320b365659bb5034341316e6a9b30f0b25fa9c9eff4c27a204", - "sha256:3a157ab149e591bb638a55c8c6bcb8cdb559c8b12c13a8affaba6cedfe51713a", - "sha256:42c64511469005058cd17cc1537578eac40ae9f7200bedcfd1fc1a05f4f8c200", - "sha256:5f36b271dae35c465ef5e9090e1fdaba4a60a56f0bb0ba03e0932a66f28b9189", - "sha256:6955369e4d9f48f41e3f238a9e60f9410645db7e07435e62c6a9ea6135a4907f", - "sha256:7b7c2a3c9eb1a827d42539aa64091640bd275b81e097cd1d8d82ef91ffa2e811", - "sha256:8ce0f819d2f1933953fca255db2471ad58184a60508f03e6285e5114b6254844", - "sha256:94a166927e53972a9698af9542ace4e38b9de50c34352b962f4d9a7d4c927af4", - "sha256:a7f1b5b2c15866f2db413a3649a8fe4fd7b428ae58be2c0f6bca5eefd53ca2be", - "sha256:c8b3a1cebcba9b3669ed1a84cc65bf005728d2f0bc1ed2a6594a992e817f3a50", - "sha256:de3ceed6e661954871d6cd78b410213bdcb136f79aafe22aa7182e028b8c7307", - "sha256:f0eca9ca8628dbb4e916ae2491d72957fdd35f7a5d326b7032a345f111ac07fe" - ], - "version": "==0.2.18" - }, - "pkginfo": { - "hashes": [ - "sha256:9ec518eefccd159de7ed45386a6bb4c6ca5fa2cb3bd9b71154fae44f6f1b36a3", - "sha256:c6bc916b8298d159e31f2c216e35ee5b86da7da18874f879798d0a1983537c86" - ], - "markers": "python_version >= '3.8'", - "version": "==1.11.2" - }, - "pygments": { - "hashes": [ - "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", - "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a" - ], - "markers": "python_version >= '3.8'", - "version": "==2.18.0" - }, - "pywin32-ctypes": { - "hashes": [ - "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", - "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755" - ], - "markers": "sys_platform == 'win32'", - "version": "==0.2.3" - }, "pyyaml": { "hashes": [ "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", @@ -351,53 +91,43 @@ "markers": "python_version >= '3.8'", "version": "==6.0.2" }, - "readme-renderer": { - "hashes": [ - "sha256:1818dd28140813509eeed8d62687f7cd4f7bad90d4db586001c5dc09d4fde311", - "sha256:19db308d86ecd60e5affa3b2a98f017af384678c63c88e5d4556a380e674f3f9" - ], - "markers": "python_version >= '3.8'", - "version": "==43.0" - }, - "requests": { - "hashes": [ - "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", - "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" - ], - "markers": "python_version >= '3.8'", - "version": "==2.32.3" - }, - "requests-toolbelt": { - "hashes": [ - "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", - "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.0.0" - }, - "rfc3986": { - "hashes": [ - "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd", - "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c" - ], - "markers": "python_version >= '3.7'", - "version": "==2.0.0" - }, - "rich": { - "hashes": [ - "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", - "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90" - ], - "markers": "python_full_version >= '3.8.0'", - "version": "==13.9.4" - }, "tomli": { "hashes": [ - "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38", - "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed" + "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", + "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", + "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", + "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", + "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", + "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", + "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", + "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", + "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", + "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", + "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", + "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", + "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", + "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", + "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", + "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", + "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", + "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", + "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", + "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", + "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", + "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", + "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", + "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", + "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", + "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", + "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", + "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", + "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", + "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", + "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", + "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7" ], "markers": "python_version >= '3.8'", - "version": "==2.0.2" + "version": "==2.2.1" }, "toolz": { "hashes": [ @@ -407,14 +137,6 @@ "markers": "python_version >= '3.8'", "version": "==1.0.0" }, - "twine": { - "hashes": [ - "sha256:89b0cc7d370a4b66421cc6102f269aa910fe0f1861c124f573cf2ddedbc10cf4", - "sha256:a262933de0b484c53408f9edae2e7821c1c45a3314ff2df9bdd343aa7ab8edc0" - ], - "index": "pypi", - "version": "==5.0.0" - }, "typing-extensions": { "hashes": [ "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", @@ -423,28 +145,12 @@ "index": "pypi", "version": "==4.12.2" }, - "urllib3": { - "hashes": [ - "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", - "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9" - ], - "markers": "python_version >= '3.8'", - "version": "==2.2.3" - }, "wcwidth": { "hashes": [ "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5" ], "version": "==0.2.13" - }, - "zipp": { - "hashes": [ - "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350", - "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29" - ], - "markers": "python_version >= '3.8'", - "version": "==3.20.2" } }, "develop": { @@ -472,6 +178,14 @@ "markers": "python_version >= '3.7'", "version": "==24.2.0" }, + "backports.tarfile": { + "hashes": [ + "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34", + "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991" + ], + "markers": "python_version < '3.12'", + "version": "==1.2.0" + }, "bandit": { "hashes": [ "sha256:59ed5caf5d92b6ada4bf65bc6437feea4a9da1093384445fed4d472acc6cff7b", @@ -857,11 +571,19 @@ }, "importlib-metadata": { "hashes": [ - "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b", - "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7" + "sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f", + "sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812" ], - "markers": "python_version >= '3.8'", - "version": "==8.5.0" + "index": "pypi", + "version": "==8.0.0" + }, + "importlib-resources": { + "hashes": [ + "sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065", + "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717" + ], + "markers": "python_version < '3.9'", + "version": "==6.4.5" }, "iniconfig": { "hashes": [ @@ -879,6 +601,30 @@ "index": "pypi", "version": "==5.13.2" }, + "jaraco.classes": { + "hashes": [ + "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", + "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790" + ], + "markers": "python_version >= '3.8'", + "version": "==3.4.0" + }, + "jaraco.context": { + "hashes": [ + "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3", + "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4" + ], + "markers": "python_version >= '3.8'", + "version": "==6.0.1" + }, + "jaraco.functools": { + "hashes": [ + "sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d", + "sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649" + ], + "markers": "python_version >= '3.8'", + "version": "==4.1.0" + }, "jinja2": { "hashes": [ "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", @@ -887,13 +633,21 @@ "markers": "python_version >= '3.7'", "version": "==3.1.4" }, + "keyring": { + "hashes": [ + "sha256:4c753b3ec91717fe713c4edd522d625889d8973a349b0e582622f49766de58e6", + "sha256:e67f8ac32b04be4714b42fe84ce7dad9c40985b9ca827c592cc303e7c26d9741" + ], + "markers": "python_version >= '3.8'", + "version": "==25.5.0" + }, "mako": { "hashes": [ - "sha256:9ec3a1583713479fae654f83ed9fa8c9a4c16b7bb0daba0e6bbebff50c0d983d", - "sha256:a91198468092a2f1a0de86ca92690fb0cfc43ca90ee17e15d93662b4c04b241a" + "sha256:42f48953c7eb91332040ff567eb7eea69b22e7a4affbc5ba8e845e8f730f6627", + "sha256:577b97e414580d3e088d47c2dbbe9594aa7a5146ed2875d4dfa9075af2dd3cc8" ], "markers": "python_version >= '3.8'", - "version": "==1.3.6" + "version": "==1.3.8" }, "markdown": { "hashes": [ @@ -1041,6 +795,14 @@ "index": "pypi", "version": "==1.11.1" }, + "more-itertools": { + "hashes": [ + "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef", + "sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6" + ], + "markers": "python_version >= '3.8'", + "version": "==10.5.0" + }, "mypy": { "hashes": [ "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc", @@ -1087,6 +849,35 @@ "markers": "python_version >= '3.5'", "version": "==1.0.0" }, + "nh3": { + "hashes": [ + "sha256:00810cd5275f5c3f44b9eb0e521d1a841ee2f8023622de39ffc7d88bd533d8e0", + "sha256:0b6820fc64f2ff7ef3e7253a093c946a87865c877b3889149a6d21d322ed8dbd", + "sha256:11270b16c1b012677e3e2dd166c1aa273388776bf99a3e3677179db5097ee16a", + "sha256:2b926f179eb4bce72b651bfdf76f8aa05d167b2b72bc2f3657fd319f40232adc", + "sha256:2eb021804e9df1761abeb844bb86648d77aa118a663c82f50ea04110d87ed707", + "sha256:3805161c4e12088bd74752ba69630e915bc30fe666034f47217a2f16b16efc37", + "sha256:5d4f5e2189861b352b73acb803b5f4bb409c2f36275d22717e27d4e0c217ae55", + "sha256:75c7cafb840f24430b009f7368945cb5ca88b2b54bb384ebfba495f16bc9c121", + "sha256:790056b54c068ff8dceb443eaefb696b84beff58cca6c07afd754d17692a4804", + "sha256:7e98621856b0a911c21faa5eef8f8ea3e691526c2433f9afc2be713cb6fbdb48", + "sha256:833b3b5f1783ce95834a13030300cea00cbdfd64ea29260d01af9c4821da0aa9", + "sha256:a7b928862daddb29805a1010a0282f77f4b8b238a37b5f76bc6c0d16d930fd22", + "sha256:ac536a4b5c073fdadd8f5f4889adabe1cbdae55305366fb870723c96ca7f49c3", + "sha256:b8eb7affc590e542fa7981ef508cd1644f62176bcd10d4429890fc629b47f0bc", + "sha256:c2e3f0d18cc101132fe10ab7ef5c4f41411297e639e23b64b5e888ccaad63f41", + "sha256:d0adf00e2b2026fa10a42537b60d161e516f206781c7515e4e97e09f72a8c5d0", + "sha256:d53a4577b6123ca1d7e8483fad3e13cb7eda28913d516bd0a648c1a473aa21a9", + "sha256:d8325d51e47cb5b11f649d55e626d56c76041ba508cd59e0cb1cf687cc7612f1", + "sha256:df8eac98fec80bd6f5fd0ae27a65de14f1e1a65a76d8e2237eb695f9cd1121d9", + "sha256:e3dedd7858a21312f7675841529941035a2ac91057db13402c8fe907aa19205a", + "sha256:ec9c8bf86e397cb88c560361f60fdce478b5edb8b93f04ead419b72fbe937ea6", + "sha256:ed06ed78f6b69d57463b46a04f68f270605301e69d80756a8adf7519002de57d", + "sha256:fc483dd8d20f8f8c010783a25a84db3bebeadced92d24d34b40d687f8043ac69", + "sha256:fdb20740d24ab9f2a1341458a00a11205294e97e905de060eeab1ceca020c09c" + ], + "version": "==0.2.19" + }, "nodeenv": { "hashes": [ "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", @@ -1097,11 +888,11 @@ }, "packaging": { "hashes": [ - "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", - "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" + "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", + "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" ], "markers": "python_version >= '3.8'", - "version": "==24.1" + "version": "==24.2" }, "pathspec": { "hashes": [ @@ -1126,6 +917,14 @@ "index": "pypi", "version": "==0.11.0" }, + "pkginfo": { + "hashes": [ + "sha256:8ad91a0445a036782b9366ef8b8c2c50291f83a553478ba8580c73d3215700cf", + "sha256:dcd589c9be4da8973eceffa247733c144812759aa67eaf4bbf97016a02f39088" + ], + "markers": "python_version >= '3.8'", + "version": "==1.12.0" + }, "platformdirs": { "hashes": [ "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", @@ -1294,6 +1093,14 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==2.9.0.post0" }, + "pywin32-ctypes": { + "hashes": [ + "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", + "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755" + ], + "markers": "sys_platform == 'win32'", + "version": "==0.2.3" + }, "pyyaml": { "hashes": [ "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", @@ -1361,6 +1168,14 @@ "markers": "python_version >= '3.6'", "version": "==0.1" }, + "readme-renderer": { + "hashes": [ + "sha256:1818dd28140813509eeed8d62687f7cd4f7bad90d4db586001c5dc09d4fde311", + "sha256:19db308d86ecd60e5affa3b2a98f017af384678c63c88e5d4556a380e674f3f9" + ], + "markers": "python_version >= '3.8'", + "version": "==43.0" + }, "requests": { "hashes": [ "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", @@ -1369,6 +1184,22 @@ "markers": "python_version >= '3.8'", "version": "==2.32.3" }, + "requests-toolbelt": { + "hashes": [ + "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", + "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.0.0" + }, + "rfc3986": { + "hashes": [ + "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd", + "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c" + ], + "markers": "python_version >= '3.7'", + "version": "==2.0.0" + }, "rich": { "hashes": [ "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", @@ -1387,11 +1218,11 @@ }, "six": { "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", + "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", - "version": "==1.16.0" + "version": "==1.17.0" }, "snakeviz": { "hashes": [ @@ -1420,11 +1251,41 @@ }, "tomli": { "hashes": [ - "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38", - "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed" + "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", + "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", + "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", + "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", + "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", + "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", + "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", + "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", + "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", + "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", + "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", + "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", + "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", + "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", + "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", + "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", + "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", + "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", + "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", + "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", + "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", + "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", + "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", + "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", + "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", + "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", + "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", + "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", + "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", + "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", + "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", + "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7" ], "markers": "python_version >= '3.8'", - "version": "==2.0.2" + "version": "==2.2.1" }, "tomlkit": { "hashes": [ @@ -1444,20 +1305,20 @@ }, "tornado": { "hashes": [ - "sha256:163b0aafc8e23d8cdc3c9dfb24c5368af84a81e3364745ccb4427669bf84aec8", - "sha256:25486eb223babe3eed4b8aecbac33b37e3dd6d776bc730ca14e1bf93888b979f", - "sha256:454db8a7ecfcf2ff6042dde58404164d969b6f5d58b926da15e6b23817950fc4", - "sha256:613bf4ddf5c7a95509218b149b555621497a6cc0d46ac341b30bd9ec19eac7f3", - "sha256:6d5ce3437e18a2b66fbadb183c1d3364fb03f2be71299e7d10dbeeb69f4b2a14", - "sha256:8ae50a504a740365267b2a8d1a90c9fbc86b780a39170feca9bcc1787ff80842", - "sha256:92d3ab53183d8c50f8204a51e6f91d18a15d5ef261e84d452800d4ff6fc504e9", - "sha256:a02a08cc7a9314b006f653ce40483b9b3c12cda222d6a46d4ac63bb6c9057698", - "sha256:b24b8982ed444378d7f21d563f4180a2de31ced9d8d84443907a0a64da2072e7", - "sha256:d9a566c40b89757c9aa8e6f032bcdb8ca8795d7c1a9762910c722b1635c9de4d", - "sha256:e2e20b9113cd7293f164dc46fffb13535266e713cdb87bd2d15ddb336e96cfc4" + "sha256:072ce12ada169c5b00b7d92a99ba089447ccc993ea2143c9ede887e0937aa803", + "sha256:1a017d239bd1bb0919f72af256a970624241f070496635784d9bf0db640d3fec", + "sha256:2876cef82e6c5978fde1e0d5b1f919d756968d5b4282418f3146b79b58556482", + "sha256:304463bd0772442ff4d0f5149c6f1c2135a1fae045adf070821c6cdc76980634", + "sha256:908b71bf3ff37d81073356a5fadcc660eb10c1476ee6e2725588626ce7e5ca38", + "sha256:92bad5b4746e9879fd7bf1eb21dce4e3fc5128d71601f80005afa39237ad620b", + "sha256:932d195ca9015956fa502c6b56af9eb06106140d844a335590c1ec7f5277d10c", + "sha256:bca9eb02196e789c9cb5c3c7c0f04fb447dc2adffd95265b2c7223a8a615ccbf", + "sha256:c36e62ce8f63409301537222faffcef7dfc5284f27eec227389f2ad11b09d946", + "sha256:c82c46813ba483a385ab2a99caeaedf92585a1f90defb5693351fa7e4ea0bf73", + "sha256:e828cce1123e9e44ae2a50a9de3055497ab1d0aeb440c5ac23064d9e44880da1" ], "markers": "python_version >= '3.8'", - "version": "==6.4.1" + "version": "==6.4.2" }, "trove-classifiers": { "hashes": [ @@ -1466,6 +1327,14 @@ ], "version": "==2024.10.21.16" }, + "twine": { + "hashes": [ + "sha256:89b0cc7d370a4b66421cc6102f269aa910fe0f1861c124f573cf2ddedbc10cf4", + "sha256:a262933de0b484c53408f9edae2e7821c1c45a3314ff2df9bdd343aa7ab8edc0" + ], + "index": "pypi", + "version": "==5.0.0" + }, "types-pyyaml": { "hashes": [ "sha256:392b267f1c0fe6022952462bf5d6523f31e37f6cea49b14cee7ad634b6301570", @@ -1492,11 +1361,11 @@ }, "virtualenv": { "hashes": [ - "sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba", - "sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4" + "sha256:23eae1b4516ecd610481eda647f3a7c09aea295055337331bb4e6892ecce47b0", + "sha256:2c9c3262bb8e7b87ea801d715fae4495e6032450c71d2309be9550e7364049aa" ], "markers": "python_version >= '3.8'", - "version": "==20.27.1" + "version": "==20.28.0" }, "watchdog": { "hashes": [ @@ -1548,11 +1417,11 @@ }, "wheel": { "hashes": [ - "sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f", - "sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49" + "sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729", + "sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248" ], "markers": "python_version >= '3.8'", - "version": "==0.44.0" + "version": "==0.45.1" }, "zipp": { "hashes": [ diff --git a/newdocs/src/changelog.md b/newdocs/src/changelog.md index 759ca1a2..735f3776 100644 --- a/newdocs/src/changelog.md +++ b/newdocs/src/changelog.md @@ -17,7 +17,7 @@ - [Issue 1259](https://github.com/jackdewinter/pymarkdown/issues/1259) - Fixed asserts and bad parsing from cases where containers are - added and then a "raw" blank line removes all containers + added and then a "raw" blank line removes all containers. - [Issue 1263](https://github.com/jackdewinter/pymarkdown/issues/1263) - Fixed issue where a new unordered list between two block quotes was not being recognized properly. @@ -33,6 +33,9 @@ Markdown, but not the intended Markdown. - [Issue 1267](https://github.com/jackdewinter/pymarkdown/issues/1267) - Fixed reported issue with task lists creating an error in Md018. +- [Issue 1268](https://github.com/jackdewinter/pymarkdown/issues/1268) + - Fixed issue with Md022 and pragmas, similar to + [Issue 1208](https://github.com/jackdewinter/pymarkdown/issues/1208). ### Changed diff --git a/publish/coverage.json b/publish/coverage.json index 4341ec36..5cde9cac 100644 --- a/publish/coverage.json +++ b/publish/coverage.json @@ -2,12 +2,12 @@ "projectName": "pymarkdown", "reportSource": "pytest", "branchLevel": { - "totalMeasured": 5503, - "totalCovered": 5503 + "totalMeasured": 5511, + "totalCovered": 5511 }, "lineLevel": { - "totalMeasured": 21393, - "totalCovered": 21393 + "totalMeasured": 21408, + "totalCovered": 21408 } } diff --git a/publish/pylint_suppression.json b/publish/pylint_suppression.json index eb6e37b0..719f395e 100644 --- a/publish/pylint_suppression.json +++ b/publish/pylint_suppression.json @@ -307,7 +307,9 @@ "too-many-arguments": 1 }, "pymarkdown/plugins/rule_md_021.py": {}, - "pymarkdown/plugins/rule_md_022.py": {}, + "pymarkdown/plugins/rule_md_022.py": { + "too-many-instance-attributes": 1 + }, "pymarkdown/plugins/rule_md_023.py": { "too-many-arguments": 1 }, @@ -505,7 +507,7 @@ "pymarkdown/version.py": {} }, "disables-by-name": { - "too-many-instance-attributes": 26, + "too-many-instance-attributes": 27, "too-many-public-methods": 4, "too-few-public-methods": 39, "too-many-arguments": 253, diff --git a/publish/test-results.json b/publish/test-results.json index 7aceab9c..7ae3a6ce 100644 --- a/publish/test-results.json +++ b/publish/test-results.json @@ -1260,7 +1260,7 @@ }, { "name": "test.rules.test_md022", - "totalTests": 50, + "totalTests": 59, "failedTests": 0, "errorTests": 0, "skippedTests": 0, diff --git a/pymarkdown/plugins/rule_md_022.py b/pymarkdown/plugins/rule_md_022.py index f68d50ab..4379d485 100644 --- a/pymarkdown/plugins/rule_md_022.py +++ b/pymarkdown/plugins/rule_md_022.py @@ -14,6 +14,8 @@ from pymarkdown.plugin_manager.rule_plugin import RulePlugin from pymarkdown.tokens.markdown_token import MarkdownToken +# pylint: disable=too-many-instance-attributes + class RuleMd022(RulePlugin): """ @@ -30,6 +32,7 @@ def __init__(self) -> None: self.__lines_above = 0 self.__lines_below = 0 self.__start_heading_blank_line_count = -1 + self.__last_blank_line: Optional[MarkdownToken] = None def get_details(self) -> PluginDetails: """ @@ -82,13 +85,7 @@ def starting_new_file(self) -> None: self.__did_above_line_count_match = False self.__start_heading_token = None self.__did_heading_end = False - - # def completed_file(self, context: PluginScanContext) -> None: - # """ - # Event that the file being currently scanned is now completed. - # """ - # if (self.__blank_line_count != -1) and self.__blank_line_count >= 0: - # self.perform_close_check(context, None) + self.__last_blank_line = None def __next_token_heading_start(self, token: MarkdownToken) -> None: # print(">>token.is_setext_heading or token.is_atx_heading>>") @@ -119,6 +116,16 @@ def next_token(self, context: PluginScanContext, token: MarkdownToken) -> None: # print(">>self.__blank_line_count>>" + str(self.__blank_line_count)) if (self.__blank_line_count != -1) and self.__blank_line_count >= 0: self.perform_close_check(context, token) + elif ( + self.__blank_line_count == -1 + and token.is_blank_line + and self.__last_blank_line is not None + ): + blank_line_number_delta = ( + token.line_number - self.__last_blank_line.line_number + ) + if blank_line_number_delta != 1: + self.__blank_line_count = 0 if ( token.is_blank_line @@ -133,9 +140,10 @@ def next_token(self, context: PluginScanContext, token: MarkdownToken) -> None: elif token.is_end_token: self.__next_token_heading_end(token) # print(">>self.__blank_line_count>>" + str(self.__blank_line_count)) + self.__last_blank_line = token if token.is_blank_line else None def perform_close_check( - self, context: PluginScanContext, token: Optional[MarkdownToken] + self, context: PluginScanContext, token: MarkdownToken ) -> None: """ Perform any state checks necessary upon closing the heading context. Also @@ -143,14 +151,24 @@ def perform_close_check( document is handled properly. """ + is_eligible_blank_line = token.is_blank_line + is_simple_blank_line = True + if is_eligible_blank_line and self.__last_blank_line is not None: + line_number_delta = token.line_number - self.__last_blank_line.line_number + is_simple_blank_line = line_number_delta == 1 + is_eligible_blank_line = is_simple_blank_line + if (self.__start_heading_token and self.__did_heading_end) and ( - not token or (not token.is_blank_line and not token.is_block_quote_end) + (not is_eligible_blank_line and not token.is_block_quote_end) ): did_end_match = self.__blank_line_count == self.__lines_below # print(">>END: did_end_match>>" + str(did_end_match)) self.report_any_match_failures(context, did_end_match) self.__start_heading_token = None + if token.is_blank_line and not is_simple_blank_line: + self.__blank_line_count = 0 + def report_any_match_failures( self, context: PluginScanContext, did_end_match: bool ) -> None: @@ -177,3 +195,6 @@ def report_any_match_failures( extra_error_information=extra_info, use_original_position=self.__start_heading_token.is_setext_heading, ) + + +# pylint: enable=too-many-instance-attributes diff --git a/test/rules/test_md022.py b/test/rules/test_md022.py index 03bb7bdf..5cafa85a 100644 --- a/test/rules/test_md022.py +++ b/test/rules/test_md022.py @@ -1925,6 +1925,416 @@ def test_md022_fenced_block_before_header(): ) +@pytest.mark.rules +def test_md022_issue_1268(): + """ + Test to make sure this rule + """ + + # Arrange + scanner = MarkdownScanner() + source_file_contents = """# My header + + + +Some long lines +""" + with create_temporary_configuration_file( + source_file_contents, file_name_suffix=".md" + ) as source_path: + supplied_arguments = [ + "scan", + source_path, + ] + + expected_return_code = 0 + expected_output = "" + expected_error = "" + + # Act + execute_results = scanner.invoke_main(arguments=supplied_arguments) + + # Assert + execute_results.assert_results( + expected_output, expected_error, expected_return_code + ) + + +@pytest.mark.rules +def test_md022_good_with_pragmas_blanks_after_around_and_before(): + """ + Test to make sure this rule works properly with pragmas. + """ + + # Arrange + scanner = MarkdownScanner() + source_file_contents = """# Heading 1 + + + +Some text + +Some more text + + + +## Heading 2 + + + +## Heading 3 +""" + with create_temporary_configuration_file( + source_file_contents, file_name_suffix=".md" + ) as source_path: + supplied_configuration = { + "plugins": {"md022": {"lines_below": 1, "lines_above": 1}} + } + with create_temporary_configuration_file( + supplied_configuration + ) as configuration_file: + supplied_arguments = [ + "-c", + configuration_file, + "scan", + source_path, + ] + + expected_return_code = 0 + expected_output = "" + expected_error = "" + + # Act + execute_results = scanner.invoke_main(arguments=supplied_arguments) + + # Assert + execute_results.assert_results( + expected_output, expected_error, expected_return_code + ) + + +@pytest.mark.rules +def test_md022_bad_with_pragmas_blanks_after_around_and_before(): + """ + Test to make sure this rule works properly with pragmas. + """ + + # Arrange + scanner = MarkdownScanner() + source_file_contents = """# Heading 1 + + + +Some text + +Some more text + + + +## Heading 2 + + + +## Heading 3 +""" + with create_temporary_configuration_file( + source_file_contents, file_name_suffix=".md" + ) as source_path: + supplied_configuration = { + "plugins": {"md022": {"lines_below": 2, "lines_above": 2}} + } + with create_temporary_configuration_file( + supplied_configuration + ) as configuration_file: + supplied_arguments = [ + "-c", + configuration_file, + "scan", + source_path, + ] + + expected_return_code = 1 + expected_output = f"""{source_path}:1:1: MD022: Headings should be surrounded by blank lines. [Expected: 2; Actual: 1; Below] (blanks-around-headings,blanks-around-headers) +{source_path}:11:1: MD022: Headings should be surrounded by blank lines. [Expected: 2; Actual: 1; Above] (blanks-around-headings,blanks-around-headers) +{source_path}:11:1: MD022: Headings should be surrounded by blank lines. [Expected: 2; Actual: 1; Below] (blanks-around-headings,blanks-around-headers) +{source_path}:15:1: MD022: Headings should be surrounded by blank lines. [Expected: 2; Actual: 1; Above] (blanks-around-headings,blanks-around-headers) +{source_path}:15:1: MD022: Headings should be surrounded by blank lines. [Expected: 2; Actual: 1; Below] (blanks-around-headings,blanks-around-headers)""" + expected_error = "" + + # Act + execute_results = scanner.invoke_main(arguments=supplied_arguments) + + # Assert + execute_results.assert_results( + expected_output, expected_error, expected_return_code + ) + + +@pytest.mark.rules +def test_md022_good_with_pragmas_blanks_before(): + """ + Test to make sure this rule works properly with pragmas. + """ + + # Arrange + scanner = MarkdownScanner() + source_file_contents = """# Heading 1 + + + +Some text +""" + with create_temporary_configuration_file( + source_file_contents, file_name_suffix=".md" + ) as source_path: + supplied_configuration = { + "plugins": {"md022": {"lines_below": 1, "lines_above": 1}} + } + with create_temporary_configuration_file( + supplied_configuration + ) as configuration_file: + supplied_arguments = [ + "-c", + configuration_file, + "scan", + source_path, + ] + + expected_return_code = 0 + expected_output = "" + expected_error = "" + + # Act + execute_results = scanner.invoke_main(arguments=supplied_arguments) + + # Assert + execute_results.assert_results( + expected_output, expected_error, expected_return_code + ) + + +@pytest.mark.rules +def test_md022_bad_with_pragmas_blanks_before(): + """ + Test to make sure this rule works properly with pragmas. + """ + + # Arrange + scanner = MarkdownScanner() + source_file_contents = """# Heading 1 + + + +Some text +""" + with create_temporary_configuration_file( + source_file_contents, file_name_suffix=".md" + ) as source_path: + supplied_configuration = { + "plugins": {"md022": {"lines_below": 2, "lines_above": 2}} + } + with create_temporary_configuration_file( + supplied_configuration + ) as configuration_file: + supplied_arguments = [ + "-c", + configuration_file, + "scan", + source_path, + ] + + expected_return_code = 1 + expected_output = f"""{source_path}:1:1: MD022: Headings should be surrounded by blank lines. [Expected: 2; Actual: 1; Below] (blanks-around-headings,blanks-around-headers)""" + expected_error = "" + + # Act + execute_results = scanner.invoke_main(arguments=supplied_arguments) + + # Assert + execute_results.assert_results( + expected_output, expected_error, expected_return_code + ) + + +@pytest.mark.rules +def test_md022_good_with_pragmas_blanks_around(): + """ + Test to make sure this rule works properly with pragmas. + """ + + # Arrange + scanner = MarkdownScanner() + source_file_contents = """Some text + + + +## Heading 2 + + + +Some more text +""" + with create_temporary_configuration_file( + source_file_contents, file_name_suffix=".md" + ) as source_path: + supplied_configuration = { + "plugins": {"md022": {"lines_below": 1, "lines_above": 1}} + } + with create_temporary_configuration_file( + supplied_configuration + ) as configuration_file: + supplied_arguments = [ + "-c", + configuration_file, + "scan", + source_path, + ] + + expected_return_code = 0 + expected_output = "" + expected_error = "" + + # Act + execute_results = scanner.invoke_main(arguments=supplied_arguments) + + # Assert + execute_results.assert_results( + expected_output, expected_error, expected_return_code + ) + + +@pytest.mark.rules +def test_md022_bad_with_pragmas_blanks_around(): + """ + Test to make sure this rule works properly with pragmas. + """ + + # Arrange + scanner = MarkdownScanner() + source_file_contents = """Some text + + + +## Heading 2 + + + +Some more text +""" + with create_temporary_configuration_file( + source_file_contents, file_name_suffix=".md" + ) as source_path: + supplied_configuration = { + "plugins": {"md022": {"lines_below": 2, "lines_above": 2}} + } + with create_temporary_configuration_file( + supplied_configuration + ) as configuration_file: + supplied_arguments = [ + "-c", + configuration_file, + "scan", + source_path, + ] + + expected_return_code = 1 + expected_output = f"""{source_path}:5:1: MD022: Headings should be surrounded by blank lines. [Expected: 2; Actual: 1; Above] (blanks-around-headings,blanks-around-headers) +{source_path}:5:1: MD022: Headings should be surrounded by blank lines. [Expected: 2; Actual: 1; Below] (blanks-around-headings,blanks-around-headers)""" + expected_error = "" + + # Act + execute_results = scanner.invoke_main(arguments=supplied_arguments) + + # Assert + execute_results.assert_results( + expected_output, expected_error, expected_return_code + ) + + +@pytest.mark.rules +def test_md022_good_with_pragmas_blanks_after(): + """ + Test to make sure this rule works properly with pragmas. + """ + + # Arrange + scanner = MarkdownScanner() + source_file_contents = """ + +## Heading 3 +""" + with create_temporary_configuration_file( + source_file_contents, file_name_suffix=".md" + ) as source_path: + supplied_configuration = { + "plugins": {"md022": {"lines_below": 1, "lines_above": 1}} + } + with create_temporary_configuration_file( + supplied_configuration + ) as configuration_file: + supplied_arguments = [ + "-c", + configuration_file, + "scan", + source_path, + ] + + expected_return_code = 0 + expected_output = "" + expected_error = "" + + # Act + execute_results = scanner.invoke_main(arguments=supplied_arguments) + + # Assert + execute_results.assert_results( + expected_output, expected_error, expected_return_code + ) + + +@pytest.mark.rules +def test_md022_bad_with_pragmas_blanks_after(): + """ + Test to make sure this rule works properly with pragmas. + """ + + # Arrange + scanner = MarkdownScanner() + source_file_contents = """ + + +## Heading 3 +""" + with create_temporary_configuration_file( + source_file_contents, file_name_suffix=".md" + ) as source_path: + supplied_configuration = { + "plugins": {"md022": {"lines_below": 2, "lines_above": 2}} + } + with create_temporary_configuration_file( + supplied_configuration + ) as configuration_file: + supplied_arguments = [ + "-c", + configuration_file, + "scan", + source_path, + ] + + expected_return_code = 1 + expected_output = f"""{source_path}:4:1: MD022: Headings should be surrounded by blank lines. [Expected: 2; Actual: 1; Above] (blanks-around-headings,blanks-around-headers) +{source_path}:4:1: MD022: Headings should be surrounded by blank lines. [Expected: 2; Actual: 1; Below] (blanks-around-headings,blanks-around-headers)""" + expected_error = "" + + # Act + execute_results = scanner.invoke_main(arguments=supplied_arguments) + + # Assert + execute_results.assert_results( + expected_output, expected_error, expected_return_code + ) + + def test_md022_query_config(): config_test = pluginQueryConfigTest( "md022",