From 1e0f2e1fe72731cf94eb4a47ea06394e365208c8 Mon Sep 17 00:00:00 2001 From: Dave Hall Date: Sat, 20 Jan 2024 17:31:03 +0000 Subject: [PATCH 01/13] wip --- logot/_match.py | 14 ++++- poetry.lock | 122 ++++++++++++++++++++++---------------------- tests/test_match.py | 3 +- 3 files changed, 75 insertions(+), 64 deletions(-) diff --git a/logot/_match.py b/logot/_match.py index 63f1193d..e9227331 100644 --- a/logot/_match.py +++ b/logot/_match.py @@ -1,6 +1,11 @@ from __future__ import annotations import re +from collections.abc import Callable +from functools import partial + +# A compiled matcher callable. +Matcher = Callable[[str], bool] # Regex matching a simplified conversion specifier. _RE_CONVERSION = re.compile(r"%(.|$)") @@ -41,10 +46,15 @@ def _compile_replace(match: re.Match[str]) -> str: raise ValueError(f"Unsupported format character {match.group(1)!r} at index {match.start(1)}") from None -def compile(pattern: str) -> re.Pattern[str]: +def _regex_matcher(pattern: re.Pattern[str], value: str) -> bool: + return pattern.fullmatch(value) is not None + + +def compile(pattern: str) -> Matcher: # Escape the pattern. This leaves simplified conversion specifiers intact. pattern = re.escape(pattern) # Substitute simplified conversion specifiers with regex matchers. pattern = _RE_CONVERSION.sub(_compile_replace, pattern) # Compile to regex. - return re.compile(pattern, re.DOTALL) + pattern = re.compile(pattern, re.DOTALL) + return partial(_regex_matcher, pattern) diff --git a/poetry.lock b/poetry.lock index b28f1c06..f73e96e5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -394,71 +394,71 @@ tornado = {version = "*", markers = "python_version > \"2.7\""} [[package]] name = "markupsafe" -version = "2.1.3" +version = "2.1.4" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, - {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de8153a7aae3835484ac168a9a9bdaa0c5eee4e0bc595503c95d53b942879c84"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e888ff76ceb39601c59e219f281466c6d7e66bd375b4ec1ce83bcdc68306796b"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b838c37ba596fcbfca71651a104a611543077156cb0a26fe0c475e1f152ee8"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac1ebf6983148b45b5fa48593950f90ed6d1d26300604f321c74a9ca1609f8e"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fbad3d346df8f9d72622ac71b69565e621ada2ce6572f37c2eae8dacd60385d"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5291d98cd3ad9a562883468c690a2a238c4a6388ab3bd155b0c75dd55ece858"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a7cc49ef48a3c7a0005a949f3c04f8baa5409d3f663a1b36f0eba9bfe2a0396e"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b83041cda633871572f0d3c41dddd5582ad7d22f65a72eacd8d3d6d00291df26"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-win32.whl", hash = "sha256:0c26f67b3fe27302d3a412b85ef696792c4a2386293c53ba683a89562f9399b0"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-win_amd64.whl", hash = "sha256:a76055d5cb1c23485d7ddae533229039b850db711c554a12ea64a0fd8a0129e2"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9e9e3c4020aa2dc62d5dd6743a69e399ce3de58320522948af6140ac959ab863"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0042d6a9880b38e1dd9ff83146cc3c9c18a059b9360ceae207805567aacccc69"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55d03fea4c4e9fd0ad75dc2e7e2b6757b80c152c032ea1d1de487461d8140efc"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ab3a886a237f6e9c9f4f7d272067e712cdb4efa774bef494dccad08f39d8ae6"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf5ebbec056817057bfafc0445916bb688a255a5146f900445d081db08cbabb"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e1a0d1924a5013d4f294087e00024ad25668234569289650929ab871231668e7"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e7902211afd0af05fbadcc9a312e4cf10f27b779cf1323e78d52377ae4b72bea"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c669391319973e49a7c6230c218a1e3044710bc1ce4c8e6eb71f7e6d43a2c131"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-win32.whl", hash = "sha256:31f57d64c336b8ccb1966d156932f3daa4fee74176b0fdc48ef580be774aae74"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-win_amd64.whl", hash = "sha256:54a7e1380dfece8847c71bf7e33da5d084e9b889c75eca19100ef98027bd9f56"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a76cd37d229fc385738bd1ce4cba2a121cf26b53864c1772694ad0ad348e509e"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:987d13fe1d23e12a66ca2073b8d2e2a75cec2ecb8eab43ff5624ba0ad42764bc"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5244324676254697fe5c181fc762284e2c5fceeb1c4e3e7f6aca2b6f107e60dc"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78bc995e004681246e85e28e068111a4c3f35f34e6c62da1471e844ee1446250"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4d176cfdfde84f732c4a53109b293d05883e952bbba68b857ae446fa3119b4f"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f9917691f410a2e0897d1ef99619fd3f7dd503647c8ff2475bf90c3cf222ad74"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:f06e5a9e99b7df44640767842f414ed5d7bedaaa78cd817ce04bbd6fd86e2dd6"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396549cea79e8ca4ba65525470d534e8a41070e6b3500ce2414921099cb73e8d"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-win32.whl", hash = "sha256:f6be2d708a9d0e9b0054856f07ac7070fbe1754be40ca8525d5adccdbda8f475"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-win_amd64.whl", hash = "sha256:5045e892cfdaecc5b4c01822f353cf2c8feb88a6ec1c0adef2a2e705eef0f656"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7a07f40ef8f0fbc5ef1000d0c78771f4d5ca03b4953fc162749772916b298fc4"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d18b66fe626ac412d96c2ab536306c736c66cf2a31c243a45025156cc190dc8a"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:698e84142f3f884114ea8cf83e7a67ca8f4ace8454e78fe960646c6c91c63bfa"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a3b78a5af63ec10d8604180380c13dcd870aba7928c1fe04e881d5c792dc4e"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:15866d7f2dc60cfdde12ebb4e75e41be862348b4728300c36cdf405e258415ec"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6aa5e2e7fc9bc042ae82d8b79d795b9a62bd8f15ba1e7594e3db243f158b5565"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:54635102ba3cf5da26eb6f96c4b8c53af8a9c0d97b64bdcb592596a6255d8518"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-win32.whl", hash = "sha256:3583a3a3ab7958e354dc1d25be74aee6228938312ee875a22330c4dc2e41beb0"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-win_amd64.whl", hash = "sha256:d6e427c7378c7f1b2bef6a344c925b8b63623d3321c09a237b7cc0e77dd98ceb"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:bf1196dcc239e608605b716e7b166eb5faf4bc192f8a44b81e85251e62584bd2"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4df98d4a9cd6a88d6a585852f56f2155c9cdb6aec78361a19f938810aa020954"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b835aba863195269ea358cecc21b400276747cc977492319fd7682b8cd2c253d"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23984d1bdae01bee794267424af55eef4dfc038dc5d1272860669b2aa025c9e3"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c98c33ffe20e9a489145d97070a435ea0679fddaabcafe19982fe9c971987d5"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9896fca4a8eb246defc8b2a7ac77ef7553b638e04fbf170bff78a40fa8a91474"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b0fe73bac2fed83839dbdbe6da84ae2a31c11cfc1c777a40dbd8ac8a6ed1560f"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c7556bafeaa0a50e2fe7dc86e0382dea349ebcad8f010d5a7dc6ba568eaaa789"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-win32.whl", hash = "sha256:fc1a75aa8f11b87910ffd98de62b29d6520b6d6e8a3de69a70ca34dea85d2a8a"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-win_amd64.whl", hash = "sha256:3a66c36a3864df95e4f62f9167c734b3b1192cb0851b43d7cc08040c074c6279"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:765f036a3d00395a326df2835d8f86b637dbaf9832f90f5d196c3b8a7a5080cb"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:21e7af8091007bf4bebf4521184f4880a6acab8df0df52ef9e513d8e5db23411"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5c31fe855c77cad679b302aabc42d724ed87c043b1432d457f4976add1c2c3e"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7653fa39578957bc42e5ebc15cf4361d9e0ee4b702d7d5ec96cdac860953c5b4"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47bb5f0142b8b64ed1399b6b60f700a580335c8e1c57f2f15587bd072012decc"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fe8512ed897d5daf089e5bd010c3dc03bb1bdae00b35588c49b98268d4a01e00"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:36d7626a8cca4d34216875aee5a1d3d654bb3dac201c1c003d182283e3205949"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b6f14a9cd50c3cb100eb94b3273131c80d102e19bb20253ac7bd7336118a673a"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-win32.whl", hash = "sha256:c8f253a84dbd2c63c19590fa86a032ef3d8cc18923b8049d91bcdeeb2581fbf6"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-win_amd64.whl", hash = "sha256:8b570a1537367b52396e53325769608f2a687ec9a4363647af1cded8928af959"}, + {file = "MarkupSafe-2.1.4.tar.gz", hash = "sha256:3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f"}, ] [[package]] diff --git a/tests/test_match.py b/tests/test_match.py index dc76bbbd..dcf43dfb 100644 --- a/tests/test_match.py +++ b/tests/test_match.py @@ -13,7 +13,8 @@ def assert_matches(pattern: str, *values: Any) -> None: # Use Python printf-style formatting to make a string that *definitely* should match. expected = pattern % values # Assert the matcher matches the expected string. - assert compile(pattern).fullmatch(expected) is not None, f"{pattern} does not match {expected}" + matcher = compile(pattern) + assert matcher(expected) is not None, f"{pattern} does not match {expected}" @given(st.integers()) From a93f0af818ec005bf87cdfa43879a184a6c0146a Mon Sep 17 00:00:00 2001 From: Dave Hall Date: Sat, 20 Jan 2024 20:10:13 +0000 Subject: [PATCH 02/13] wip --- logot/_match.py | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/logot/_match.py b/logot/_match.py index e9227331..192ed664 100644 --- a/logot/_match.py +++ b/logot/_match.py @@ -46,15 +46,28 @@ def _compile_replace(match: re.Match[str]) -> str: raise ValueError(f"Unsupported format character {match.group(1)!r} at index {match.start(1)}") from None -def _regex_matcher(pattern: re.Pattern[str], value: str) -> bool: +def _match_regex(pattern: re.Pattern[str], value: str) -> bool: return pattern.fullmatch(value) is not None def compile(pattern: str) -> Matcher: - # Escape the pattern. This leaves simplified conversion specifiers intact. - pattern = re.escape(pattern) - # Substitute simplified conversion specifiers with regex matchers. - pattern = _RE_CONVERSION.sub(_compile_replace, pattern) - # Compile to regex. - pattern = re.compile(pattern, re.DOTALL) - return partial(_regex_matcher, pattern) + parts: list[str] = _RE_CONVERSION.split(pattern) + parts_len = len(parts) + is_regex = False + # Replace conversion types with regex matchers. + for n in range(1, parts_len, 2): + part = parts[n] + try: + parts[n] = _CONVERSION_MAP[part] + except KeyError: + raise ValueError(f"Unsupported format character {part!r}") from None + # Possibly mark matcher as regex. + is_regex |= part != "%" + # Create regex matcher. + if is_regex: + # Escape all non-regex parts. + parts[::2] = map(re.escape, parts[::2]) + # Compile to regex. + return partial(_match_regex, re.compile("".join(parts), re.DOTALL)) + # Create simple matcher. + return "".join(parts).__eq__ From b4b4d33b3e3275e866457b7e3efc448d5b504cf7 Mon Sep 17 00:00:00 2001 From: Dave Hall Date: Sat, 20 Jan 2024 20:10:24 +0000 Subject: [PATCH 03/13] wip --- logot/_match.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/logot/_match.py b/logot/_match.py index 192ed664..55067913 100644 --- a/logot/_match.py +++ b/logot/_match.py @@ -39,13 +39,6 @@ } -def _compile_replace(match: re.Match[str]) -> str: - try: - return _CONVERSION_MAP[match.group(1)] - except KeyError: - raise ValueError(f"Unsupported format character {match.group(1)!r} at index {match.start(1)}") from None - - def _match_regex(pattern: re.Pattern[str], value: str) -> bool: return pattern.fullmatch(value) is not None From a507c2fe683144f9e595ea940a638a6ceda5b973 Mon Sep 17 00:00:00 2001 From: Dave Hall Date: Sat, 20 Jan 2024 20:10:36 +0000 Subject: [PATCH 04/13] wip --- logot/_match.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logot/_match.py b/logot/_match.py index 55067913..bf30e053 100644 --- a/logot/_match.py +++ b/logot/_match.py @@ -4,7 +4,7 @@ from collections.abc import Callable from functools import partial -# A compiled matcher callable. +# Compiled matcher callable. Matcher = Callable[[str], bool] # Regex matching a simplified conversion specifier. From 5fc0b2da2464316f6783768df5908d67b57ac370 Mon Sep 17 00:00:00 2001 From: Dave Hall Date: Sat, 20 Jan 2024 20:12:15 +0000 Subject: [PATCH 05/13] wip --- tests/test_match.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_match.py b/tests/test_match.py index dcf43dfb..c317c70a 100644 --- a/tests/test_match.py +++ b/tests/test_match.py @@ -56,10 +56,10 @@ def test_percent_matches() -> None: def test_unsupported_format() -> None: with pytest.raises(ValueError) as ex: compile("%b") - assert str(ex.value) == "Unsupported format character 'b' at index 1" + assert str(ex.value) == "Unsupported format character 'b'" def test_truncated_format() -> None: with pytest.raises(ValueError) as ex: compile("%") - assert str(ex.value) == "Unsupported format character '' at index 1" + assert str(ex.value) == "Unsupported format character ''" From 6b9d319104157df8eac75a4ded51489034ea2dba Mon Sep 17 00:00:00 2001 From: Dave Hall Date: Sat, 20 Jan 2024 20:16:08 +0000 Subject: [PATCH 06/13] wip --- logot/_match.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/logot/_match.py b/logot/_match.py index bf30e053..37ee8f79 100644 --- a/logot/_match.py +++ b/logot/_match.py @@ -45,10 +45,9 @@ def _match_regex(pattern: re.Pattern[str], value: str) -> bool: def compile(pattern: str) -> Matcher: parts: list[str] = _RE_CONVERSION.split(pattern) - parts_len = len(parts) is_regex = False # Replace conversion types with regex matchers. - for n in range(1, parts_len, 2): + for n in range(1, len(parts), 2): part = parts[n] try: parts[n] = _CONVERSION_MAP[part] From d6378e40d6df303fc3e2c1e345525019fd5e3e8c Mon Sep 17 00:00:00 2001 From: Dave Hall Date: Sat, 20 Jan 2024 20:16:37 +0000 Subject: [PATCH 07/13] wip --- logot/_match.py | 2 +- tests/test_match.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/logot/_match.py b/logot/_match.py index 37ee8f79..74980336 100644 --- a/logot/_match.py +++ b/logot/_match.py @@ -43,7 +43,7 @@ def _match_regex(pattern: re.Pattern[str], value: str) -> bool: return pattern.fullmatch(value) is not None -def compile(pattern: str) -> Matcher: +def compile_matcher(pattern: str) -> Matcher: parts: list[str] = _RE_CONVERSION.split(pattern) is_regex = False # Replace conversion types with regex matchers. diff --git a/tests/test_match.py b/tests/test_match.py index c317c70a..b59f370d 100644 --- a/tests/test_match.py +++ b/tests/test_match.py @@ -6,14 +6,14 @@ from hypothesis import given from hypothesis import strategies as st -from logot._match import compile +from logot._match import compile_matcher def assert_matches(pattern: str, *values: Any) -> None: # Use Python printf-style formatting to make a string that *definitely* should match. expected = pattern % values # Assert the matcher matches the expected string. - matcher = compile(pattern) + matcher = compile_matcher(pattern) assert matcher(expected) is not None, f"{pattern} does not match {expected}" @@ -55,11 +55,11 @@ def test_percent_matches() -> None: def test_unsupported_format() -> None: with pytest.raises(ValueError) as ex: - compile("%b") + compile_matcher("%b") assert str(ex.value) == "Unsupported format character 'b'" def test_truncated_format() -> None: with pytest.raises(ValueError) as ex: - compile("%") + compile_matcher("%") assert str(ex.value) == "Unsupported format character ''" From 3b38728e6e2e1439a5247dcfda30aa5d5a9603d7 Mon Sep 17 00:00:00 2001 From: Dave Hall Date: Sat, 20 Jan 2024 20:57:48 +0000 Subject: [PATCH 08/13] wip --- logot/_match.py | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/logot/_match.py b/logot/_match.py index 74980336..ed6640a2 100644 --- a/logot/_match.py +++ b/logot/_match.py @@ -45,21 +45,23 @@ def _match_regex(pattern: re.Pattern[str], value: str) -> bool: def compile_matcher(pattern: str) -> Matcher: parts: list[str] = _RE_CONVERSION.split(pattern) - is_regex = False - # Replace conversion types with regex matchers. - for n in range(1, len(parts), 2): - part = parts[n] - try: - parts[n] = _CONVERSION_MAP[part] - except KeyError: - raise ValueError(f"Unsupported format character {part!r}") from None - # Possibly mark matcher as regex. - is_regex |= part != "%" - # Create regex matcher. - if is_regex: - # Escape all non-regex parts. - parts[::2] = map(re.escape, parts[::2]) - # Compile to regex. - return partial(_match_regex, re.compile("".join(parts), re.DOTALL)) + # If there is at least one matching conversion specifier, this might require a regex matcher. + if parts: + is_regex = False + # Replace conversion types with regex matchers. + for n in range(1, len(parts), 2): + part = parts[n] + try: + parts[n] = _CONVERSION_MAP[part] + except KeyError: + raise ValueError(f"Unsupported format character {part!r}") from None + # Possibly mark matcher as regex. + is_regex |= part != "%" + # Create regex matcher. + if is_regex: + # Escape all non-regex parts. + parts[::2] = map(re.escape, parts[::2]) + # Compile to regex. + return partial(_match_regex, re.compile("".join(parts), re.DOTALL)) # Create simple matcher. return "".join(parts).__eq__ From 4a96f9d8755a508d615a10d8e47b90b13f8f1d49 Mon Sep 17 00:00:00 2001 From: Dave Hall Date: Sat, 20 Jan 2024 21:03:48 +0000 Subject: [PATCH 09/13] wip --- logot/_match.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/logot/_match.py b/logot/_match.py index ed6640a2..db711599 100644 --- a/logot/_match.py +++ b/logot/_match.py @@ -45,23 +45,24 @@ def _match_regex(pattern: re.Pattern[str], value: str) -> bool: def compile_matcher(pattern: str) -> Matcher: parts: list[str] = _RE_CONVERSION.split(pattern) - # If there is at least one matching conversion specifier, this might require a regex matcher. - if parts: + parts_len = len(parts) + # If there is more than one part, at least one conversion specifier was found and we might need a regex matcher. + if parts_len > 1: is_regex = False # Replace conversion types with regex matchers. - for n in range(1, len(parts), 2): + for n in range(1, parts_len, 2): part = parts[n] try: parts[n] = _CONVERSION_MAP[part] except KeyError: raise ValueError(f"Unsupported format character {part!r}") from None - # Possibly mark matcher as regex. + # A "%" is used as an escape sequence, and doesn't require a regex matcher. Anything else does. is_regex |= part != "%" # Create regex matcher. if is_regex: - # Escape all non-regex parts. parts[::2] = map(re.escape, parts[::2]) - # Compile to regex. return partial(_match_regex, re.compile("".join(parts), re.DOTALL)) + # Recreate the pattern with all escape sequences replaced. + pattern = "".join(parts) # Create simple matcher. - return "".join(parts).__eq__ + return pattern.__eq__ From c4a9a4b6594304131ba250d17e7e2890d7cef19a Mon Sep 17 00:00:00 2001 From: Dave Hall Date: Sat, 20 Jan 2024 21:07:21 +0000 Subject: [PATCH 10/13] wip --- logot/_match.py | 3 ++- tests/test_match.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/logot/_match.py b/logot/_match.py index db711599..781e88a6 100644 --- a/logot/_match.py +++ b/logot/_match.py @@ -55,7 +55,8 @@ def compile_matcher(pattern: str) -> Matcher: try: parts[n] = _CONVERSION_MAP[part] except KeyError: - raise ValueError(f"Unsupported format character {part!r}") from None + part_index = sum(map(len, parts[:n:2])) + ((n - 1) * 2) + 1 + raise ValueError(f"Unsupported format character {part!r} at index {part_index}") from None # A "%" is used as an escape sequence, and doesn't require a regex matcher. Anything else does. is_regex |= part != "%" # Create regex matcher. diff --git a/tests/test_match.py b/tests/test_match.py index b59f370d..81e0dbe2 100644 --- a/tests/test_match.py +++ b/tests/test_match.py @@ -56,10 +56,10 @@ def test_percent_matches() -> None: def test_unsupported_format() -> None: with pytest.raises(ValueError) as ex: compile_matcher("%b") - assert str(ex.value) == "Unsupported format character 'b'" + assert str(ex.value) == "Unsupported format character 'b' at index 1" def test_truncated_format() -> None: with pytest.raises(ValueError) as ex: compile_matcher("%") - assert str(ex.value) == "Unsupported format character ''" + assert str(ex.value) == "Unsupported format character '' at index 1" From 611649d10bff2caef0390429462c7d45861923e5 Mon Sep 17 00:00:00 2001 From: Dave Hall Date: Sat, 20 Jan 2024 21:07:46 +0000 Subject: [PATCH 11/13] wip --- tests/test_match.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_match.py b/tests/test_match.py index 81e0dbe2..91cf2366 100644 --- a/tests/test_match.py +++ b/tests/test_match.py @@ -55,11 +55,11 @@ def test_percent_matches() -> None: def test_unsupported_format() -> None: with pytest.raises(ValueError) as ex: - compile_matcher("%b") - assert str(ex.value) == "Unsupported format character 'b' at index 1" + compile_matcher("foo %b bar") + assert str(ex.value) == "Unsupported format character 'b' at index 5" def test_truncated_format() -> None: with pytest.raises(ValueError) as ex: - compile_matcher("%") - assert str(ex.value) == "Unsupported format character '' at index 1" + compile_matcher("foo %") + assert str(ex.value) == "Unsupported format character '' at index 5" From 312ce58e9309fe23d7646f656fd3bbbfe5a2cc2e Mon Sep 17 00:00:00 2001 From: Dave Hall Date: Sat, 20 Jan 2024 21:12:02 +0000 Subject: [PATCH 12/13] wip --- logot/_match.py | 2 +- tests/test_match.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/logot/_match.py b/logot/_match.py index 781e88a6..9fee9c81 100644 --- a/logot/_match.py +++ b/logot/_match.py @@ -55,7 +55,7 @@ def compile_matcher(pattern: str) -> Matcher: try: parts[n] = _CONVERSION_MAP[part] except KeyError: - part_index = sum(map(len, parts[:n:2])) + ((n - 1) * 2) + 1 + part_index = sum(map(len, parts[:n:2])) + ((n // 2) * 2) + 1 raise ValueError(f"Unsupported format character {part!r} at index {part_index}") from None # A "%" is used as an escape sequence, and doesn't require a regex matcher. Anything else does. is_regex |= part != "%" diff --git a/tests/test_match.py b/tests/test_match.py index 91cf2366..fc061705 100644 --- a/tests/test_match.py +++ b/tests/test_match.py @@ -55,11 +55,11 @@ def test_percent_matches() -> None: def test_unsupported_format() -> None: with pytest.raises(ValueError) as ex: - compile_matcher("foo %b bar") - assert str(ex.value) == "Unsupported format character 'b' at index 5" + compile_matcher("foo %s %b") + assert str(ex.value) == "Unsupported format character 'b' at index 8" def test_truncated_format() -> None: with pytest.raises(ValueError) as ex: - compile_matcher("foo %") - assert str(ex.value) == "Unsupported format character '' at index 5" + compile_matcher("foo %s %") + assert str(ex.value) == "Unsupported format character '' at index 8" From dfa899efe2a82719b34b5de623c3b5a6cdc8d4af Mon Sep 17 00:00:00 2001 From: Dave Hall Date: Sat, 20 Jan 2024 21:13:43 +0000 Subject: [PATCH 13/13] wip --- logot/_match.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logot/_match.py b/logot/_match.py index 9fee9c81..2416947c 100644 --- a/logot/_match.py +++ b/logot/_match.py @@ -1,8 +1,8 @@ from __future__ import annotations import re -from collections.abc import Callable from functools import partial +from typing import Callable # Compiled matcher callable. Matcher = Callable[[str], bool]