PyPcre 0.6.0__tar.gz → 0.6.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pypcre-0.6.0 → pypcre-0.6.2}/PKG-INFO +89 -30
- {pypcre-0.6.0 → pypcre-0.6.2}/PyPcre.egg-info/PKG-INFO +89 -30
- {pypcre-0.6.0 → pypcre-0.6.2}/PyPcre.egg-info/SOURCES.txt +15 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/README.md +86 -27
- {pypcre-0.6.0 → pypcre-0.6.2}/pcre/__init__.py +1 -7
- pypcre-0.6.2/pcre/_stdlib_re.py +37 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/pcre/cache.py +111 -25
- pypcre-0.6.2/pcre/pcre.py +1935 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/pcre/re_compat.py +154 -8
- pypcre-0.6.2/pcre/threads.py +292 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/pcre_ext/atomic_compat.h +36 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/pcre_ext/cache.c +52 -8
- {pypcre-0.6.0 → pypcre-0.6.2}/pcre_ext/error.c +21 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/pcre_ext/memory.c +14 -20
- {pypcre-0.6.0 → pypcre-0.6.2}/pcre_ext/pattern_cache.c +102 -86
- {pypcre-0.6.0 → pypcre-0.6.2}/pcre_ext/pcre2.c +2387 -264
- {pypcre-0.6.0 → pypcre-0.6.2}/pcre_ext/pcre2_module.h +6 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/pcre_ext/string_helpers.c +192 -3
- {pypcre-0.6.0 → pypcre-0.6.2}/pcre_ext/util.c +13 -8
- {pypcre-0.6.0 → pypcre-0.6.2}/pyproject.toml +4 -4
- {pypcre-0.6.0 → pypcre-0.6.2}/setup.py +7 -1
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_api_parity.py +85 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_c_api_audit.py +91 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_cache.py +82 -23
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_cache_global.py +32 -3
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_cache_global_inproc.py +58 -5
- pypcre-0.6.2/tests/test_cache_scope_safety.py +276 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_clobber.py +4 -1
- pypcre-0.6.2/tests/test_clobber_verify.py +876 -0
- pypcre-0.6.2/tests/test_compile_utf_no_check_safety.py +150 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_core.py +2 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_coverage_gaps.py +18 -4
- pypcre-0.6.2/tests/test_escape_fastpath.py +83 -0
- pypcre-0.6.2/tests/test_expand_fastpath.py +302 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_gil_zero_safety.py +118 -1
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_jit.py +7 -2
- pypcre-0.6.2/tests/test_jit_start_optimize_workaround.py +82 -0
- pypcre-0.6.2/tests/test_lastindex_ovector_fastpath.py +78 -0
- pypcre-0.6.2/tests/test_literal_capture_findall_fastpath.py +123 -0
- pypcre-0.6.2/tests/test_literal_capture_split_fastpath.py +94 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_module.py +5 -0
- pypcre-0.6.2/tests/test_multi_literal_capture_findall_fastpath.py +144 -0
- pypcre-0.6.2/tests/test_multi_literal_capture_split_fastpath.py +114 -0
- pypcre-0.6.2/tests/test_python_coverage_audit.py +826 -0
- pypcre-0.6.2/tests/test_stdlib_flag_fastpath.py +111 -0
- pypcre-0.6.2/tests/test_sub_count_one_fastpath.py +154 -0
- pypcre-0.6.2/tests/test_sub_reference_fastpath.py +140 -0
- pypcre-0.6.2/tests/test_template_dispatch_fastpath.py +74 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_threaded_backend.py +27 -4
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_threads.py +134 -6
- pypcre-0.6.0/pcre/_stdlib_re.py +0 -28
- pypcre-0.6.0/pcre/pcre.py +0 -924
- pypcre-0.6.0/pcre/threads.py +0 -181
- pypcre-0.6.0/tests/test_python_coverage_audit.py +0 -348
- {pypcre-0.6.0 → pypcre-0.6.2}/LICENSE +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/MANIFEST.in +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/PyPcre.egg-info/dependency_links.txt +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/PyPcre.egg-info/top_level.txt +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/pcre/error.py +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/pcre/flags.py +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/pcre_ext/flag.c +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/pcre_ext/jit_support.c +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/pcre_ext/pcre2.h +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/setup.cfg +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/setup_utils.py +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_accuracy.py +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_basic.py +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_bench_string.py +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_benchmark.py +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_bytes.py +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_clobber_thread.py +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_errors.py +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_flags.py +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_jit_anchoring.py +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_lastindex_semantics.py +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_memory.py +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_mmap.py +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_pattern.py +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_re_compat.py +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_setup_utils_multiarch.py +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_simd.py +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_transformers_regex.py +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_utf8.py +0 -0
- {pypcre-0.6.0 → pypcre-0.6.2}/tests/test_version.py +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyPcre
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.2
|
|
4
4
|
Summary: Modern, GIL-friendly, Fast Python bindings for PCRE2 with auto caching and JIT of compiled patterns.
|
|
5
5
|
Author-email: ModelCloud <qubitium@modelcloud.ai>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
7
|
-
Project-URL: Homepage, https://github.com/ModelCloud/
|
|
7
|
+
Project-URL: Homepage, https://github.com/ModelCloud/PyPcre
|
|
8
8
|
Keywords: regex,pcre2,bindings
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
|
10
10
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
@@ -16,7 +16,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
16
16
|
Classifier: Programming Language :: C
|
|
17
17
|
Classifier: Topic :: Software Development :: Libraries
|
|
18
18
|
Classifier: Topic :: Text Processing :: Linguistic
|
|
19
|
-
Requires-Python: >=3.
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
22
|
Dynamic: license-file
|
|
@@ -47,6 +47,7 @@ Fast, free-threaded Python bindings for `PCRE2` with a stable `stdlib.re`-compat
|
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
## Latest News 🚀
|
|
50
|
+
* 08/09–08/10/2026 **API performance and safety update**: common regex workloads and ordered `parallel_map(search)` workloads were benchmarked across Python 3.10 and free-threaded Python 3.14t/GIL=0. Compatibility fallbacks preserve complex patterns, subclasses, buffers, and callables. Unsafe UTF bytes compilation is also blocked, with differential, randomized, concurrency, subprocess, and memory-safety coverage. 🧵⚡🛡️
|
|
50
51
|
* 08/08/2026 **0.6.0**: `findall`, `finditer`, `sub`/`subn`, `split`, and `match`/`search`/`fullmatch` are now up to **46x faster** than `stdlib.re` and **48x faster** than `regex` on `finditer`/`findall` workloads, **13x** on `split`, and **2–9x** on `sub`/`subn` backref workloads, with full `re` semantics. Free-threaded `findall` reaches **13.8x** vs `re` on 8 threads. 🚀⚡
|
|
51
52
|
* 07/27/2026 [0.5.0](https://github.com/ModelCloud/PyPcre/releases/tag/v0.5.0): Zero-copy buffer-protocol subject support (`mmap.mmap`, `bytearray`, `array.array`) with UTF-8 validation and GIL=0-safe memory pinning. 🗂️⚡
|
|
52
53
|
* 07/24/2026 [0.4.0](https://github.com/ModelCloud/PyPcre/releases/tag/v0.4.0): C extension hardening (memory/pointer safety, bounds checks, atomic allocator init), GIL=0 safety verified, vectorized UTF-8 index/offset conversion, GIL-release threshold for small calls, C `findall` implementation, and README competitor benchmarks. 🛡️⚡
|
|
@@ -68,10 +69,10 @@ PyPcre pairs Python's familiar `re`-compatible API with the real `PCRE2` engine.
|
|
|
68
69
|
|
|
69
70
|
- 🧬 **Full power of PCRE2**: PyPcre uses the real `PCRE2` engine, so you get native compile options, semantics, JIT, and upstream tuning.
|
|
70
71
|
- 🔥 **More expressive regex syntax**: `PCRE2` supports constructs beyond stdlib `re`, including atomic groups `(?>...)`, possessive quantifiers `++`, branch-reset groups `(?|...)`, richer lookarounds, and backtracking control verbs like `(*SKIP)(*FAIL)`.
|
|
71
|
-
- 🧵 **Thread-safe into `nogil`**: PyPcre is built for `PYTHON_GIL=0`, with CI coverage
|
|
72
|
+
- 🧵 **Thread-safe into `nogil`**: PyPcre is built for `PYTHON_GIL=0`, with CI coverage and `parallel_map()` for multi-subject fan-out.
|
|
72
73
|
- ⚡ **Fast on real workloads**: `PCRE2` JIT plus cached compiled patterns lets PyPcre match or beat `re` and `regex` on many common scans, especially multiline searches, lookaround-heavy patterns, and free-threaded execution.
|
|
73
74
|
- 🛡️ **Safer operational story**: PyPcre prefers the system `libpcre2-8` shared library so normal OS package updates can bring security and bug-fix benefits without a bundled fork.
|
|
74
|
-
- ✅ **Validated thoroughly**: the project runs API
|
|
75
|
+
- ✅ **Validated thoroughly**: the project runs API, fuzz, concurrency, and memory-safety tests.
|
|
75
76
|
|
|
76
77
|
### Quick Comparison 🥊
|
|
77
78
|
|
|
@@ -88,17 +89,69 @@ PyPcre pairs Python's familiar `re`-compatible API with the real `PCRE2` engine.
|
|
|
88
89
|
|
|
89
90
|
### Benchmark Highlights 🏁
|
|
90
91
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
The tables below summarize representative public workloads. Lower is better.
|
|
93
|
+
|
|
94
|
+
#### Fan-out and API speedups
|
|
95
|
+
|
|
96
|
+
Both interpreter runs used the same scheduler policy. The host reports 12
|
|
97
|
+
performance logical CPUs and 4 efficiency logical CPUs; macOS does not provide
|
|
98
|
+
an unprivileged hard per-process CPU mask, so these measurements record the
|
|
99
|
+
topology rather than claiming hard CPU affinity.
|
|
100
|
+
|
|
101
|
+
| Workload | Python 3.10 | Python 3.14t/GIL=0 |
|
|
102
|
+
| --- | ---: | ---: |
|
|
103
|
+
| `parallel_map(search)`, 16 × 1 MiB subjects, 12 workers | **8.57x** | **7.85x** |
|
|
104
|
+
| `parallel_map(findall)`, 48 × 1 MiB subjects, 12 workers | **11.51x** | **11.25x** |
|
|
105
|
+
| No-op `escape("literal")` | **5.0x** | **3.6x** |
|
|
106
|
+
| No-op `escape(b"literal")` | **6.9x** | **6.5x** |
|
|
107
|
+
| Bound literal `sub(..., count=1)` | **4.7x** | **4.3x** |
|
|
108
|
+
| Bound numeric-reference `sub(..., count=1)` | **4.3x** | **4.1x** |
|
|
109
|
+
| Bound explicit-reference `sub(..., count=1)` | **4.6x** | **4.3x** |
|
|
110
|
+
| Bound named-reference `sub(..., count=1)` | **4.2x** | **4.3x** |
|
|
111
|
+
| Bound numeric-reference `sub(..., count=2)` | **4.6x** | **4.2x** |
|
|
112
|
+
| Bound numeric-reference `sub(..., count=4)` | **6.0x** | **5.1x** |
|
|
113
|
+
| Bound numeric-reference `sub(..., count=8)` | **8.6x** | **6.1x** |
|
|
114
|
+
| Cached compile with `re.I` | **6.7x** | **6.9x** |
|
|
115
|
+
| Cached compile with `re.I|re.M|re.S|re.X` | **6.2x** | **6.4x** |
|
|
116
|
+
| First-read `lastindex` cost, sole capture | **11.8x** | **8.2x** |
|
|
117
|
+
| Deprecated `template()` compatibility call | **6.2x** | **1.1x** |
|
|
118
|
+
| Literal-capture `findall`, 100 matches | **5.0x** | **6.2x** |
|
|
119
|
+
| Literal-capture `findall`, 500 matches | **7.0x** | **8.4x** |
|
|
120
|
+
| Two literal captures `findall`, 100 matches | **7.5x** | **10.8x** |
|
|
121
|
+
| Two literal captures `findall`, 500 matches | **13.5x** | **18.3x** |
|
|
122
|
+
| Eight literal captures `findall`, 500 matches | **24.5x** | **29.4x** |
|
|
123
|
+
| Three literal captures `split`, 500 captures | **4.5x** | **6.5x** |
|
|
124
|
+
| Eight literal captures `split`, 500 captures | **6.6x** | **9.0x** |
|
|
125
|
+
| Literal-capture `split`, 100 captures | **2.6x** | **3.5x** |
|
|
126
|
+
| Literal-capture `split`, 2,000 captures | **3.1x** | **3.8x** |
|
|
127
|
+
| Bound one-character literal `Pattern.split` | **2.1x** | **1.7x** |
|
|
128
|
+
| Bound backreference `sub` hot path | **1.38 μs** | **1.14 μs** |
|
|
129
|
+
| One-match numeric-reference `Pattern.sub` | **0.45 μs** | **0.34 μs** |
|
|
130
|
+
| One-match explicit-reference `Pattern.sub` | **0.45 μs** | **0.31 μs** |
|
|
131
|
+
| One-match named-reference `Pattern.sub` | **0.46 μs** | **0.33 μs** |
|
|
132
|
+
| Repeated call-local `Match.groups()` | **~0.05 μs** | **~0.05 μs** |
|
|
133
|
+
| Call-local `Match.expand(r"[\\1]")` | **0.07 μs** | **0.07 μs** |
|
|
134
|
+
| Call-local `Match.expand(r"[\\g<1>]")` | **0.11 μs** | **0.08 μs** |
|
|
135
|
+
| Call-local `Match.expand(r"[\\g<word>]")` | **0.13 μs** | **0.11 μs** |
|
|
136
|
+
| Call-local two-name `Match.expand` | **0.18 μs** | **0.15 μs** |
|
|
137
|
+
| Call-local three-name `Match.expand` | **0.23 μs** | **0.20 μs** |
|
|
138
|
+
| Call-local eight-name `Match.expand` | **0.44 μs** | **0.39 μs** |
|
|
139
|
+
| Literal-backslash + named `Match.expand` | **0.12 μs** | **0.10 μs** |
|
|
140
|
+
| Named + backslash-suffix `Match.expand` | **0.16 μs** | **0.13 μs** |
|
|
141
|
+
| Repeated default `compile("(x)")` | **0.49 μs** | **0.38 μs** |
|
|
142
|
+
| Repeated integer-flagged `compile("x", CASELESS)` | **1.16 μs** | **0.81 μs** |
|
|
143
|
+
|
|
144
|
+
The parallel figures are serial-to-parallel speedups and preserve input order
|
|
145
|
+
and exception behavior. They were measured with the same scheduler policy for
|
|
146
|
+
both interpreters on the Apple host.
|
|
94
147
|
|
|
95
148
|
#### `findall` — large multiline and lookaround workloads
|
|
96
149
|
|
|
97
150
|
| Workload | PyPcre (ms) | `re` (ms) | `regex` (ms) | PyPcre edge |
|
|
98
151
|
| --- | ---: | ---: | ---: | --- |
|
|
99
|
-
| Extract `WARN` / `ERROR` lines (multiline) | `0.
|
|
100
|
-
| Per-line full-name extraction (multiline) | `0.
|
|
101
|
-
| Lookbehind + negative-lookahead tokens | `1.
|
|
152
|
+
| Extract `WARN` / `ERROR` lines (multiline) | `0.471` | `15.098` | `16.281` | **32.1x** vs `re`, **34.6x** vs `regex` |
|
|
153
|
+
| Per-line full-name extraction (multiline) | `0.588` | `14.305` | `8.000` | **24.3x** vs `re`, **13.6x** vs `regex` |
|
|
154
|
+
| Lookbehind + negative-lookahead tokens | `1.013` | `6.129` | `5.267` | **6.1x** vs `re`, **5.2x** vs `regex` |
|
|
102
155
|
|
|
103
156
|
Patterns used:
|
|
104
157
|
|
|
@@ -113,51 +166,51 @@ Patterns used:
|
|
|
113
166
|
|
|
114
167
|
#### `finditer` — same workloads
|
|
115
168
|
|
|
116
|
-
Measured on
|
|
169
|
+
Measured on Python 3.10.11 arm64 with compiled-pattern reuse and JIT enabled. A reproducible version lives in [`benchmarks/finditer_bench.py`](benchmarks/finditer_bench.py).
|
|
117
170
|
|
|
118
171
|
| Workload | PyPcre (ms) | `re` (ms) | `regex` (ms) | PyPcre edge |
|
|
119
172
|
| --- | ---: | ---: | ---: | --- |
|
|
120
|
-
| Extract `WARN` / `ERROR` lines | `0.
|
|
121
|
-
| Per-line full-name extraction | `0.
|
|
122
|
-
| Lookbehind + negative lookahead | `
|
|
173
|
+
| Extract `WARN` / `ERROR` lines | `0.449` | `17.145` | `16.175` | **38.2x** vs `re`, **36.0x** vs `regex` |
|
|
174
|
+
| Per-line full-name extraction | `0.564` | `16.258` | `7.874` | **28.8x** vs `re`, **14.0x** vs `regex` |
|
|
175
|
+
| Lookbehind + negative lookahead | `1.942` | `8.548` | `6.037` | **4.4x** vs `re`, **3.1x** vs `regex` |
|
|
123
176
|
|
|
124
177
|
#### `sub` / `subn` — high-volume replacement workloads
|
|
125
178
|
|
|
126
|
-
Measured on
|
|
179
|
+
Measured on Python 3.10.11 arm64 with compiled-pattern reuse and JIT enabled. Values are medians of three outer runs; lower is better. The benchmark replaces 100,000 space-separated tokens.
|
|
127
180
|
|
|
128
181
|
A reproducible version lives in [`benchmarks/sub_bench.py`](benchmarks/sub_bench.py).
|
|
129
182
|
|
|
130
183
|
| Workload | PyPcre (ms) | `re` (ms) | `regex` (ms) | PyPcre edge |
|
|
131
184
|
| --- | ---: | ---: | ---: | --- |
|
|
132
|
-
| Literal replacement (`\w+` → `[X]`) | `
|
|
133
|
-
| Single numeric backref (`(w)\d+` → `[\1]`) | `
|
|
134
|
-
| Two numeric backrefs (`(w)(\d+)` → `\2-\1`) | `
|
|
135
|
-
| Named backref (`(?P<g>\w+)` → `<\g<g>>`) | `
|
|
185
|
+
| Literal replacement (`\w+` → `[X]`) | `3.127` | `6.489` | `9.992` | **2.1x** vs `re`, **3.2x** vs `regex` |
|
|
186
|
+
| Single numeric backref (`(w)\d+` → `[\1]`) | `4.003` | `30.098` | `12.481` | **7.5x** vs `re`, **3.1x** vs `regex` |
|
|
187
|
+
| Two numeric backrefs (`(w)(\d+)` → `\2-\1`) | `9.940` | `35.052` | `16.201` | **3.5x** vs `re`, **1.6x** vs `regex` |
|
|
188
|
+
| Named backref (`(?P<g>\w+)` → `<\g<g>>`) | `9.765` | `32.434` | `15.216` | **3.3x** vs `re`, **1.6x** vs `regex` |
|
|
136
189
|
|
|
137
190
|
#### `split` — high-volume delimiter workloads
|
|
138
191
|
|
|
139
|
-
Measured on
|
|
192
|
+
Measured on Python 3.10.11 arm64 with compiled-pattern reuse and JIT enabled. Values are medians of three outer runs; lower is better. The benchmark splits 100,000 space-separated tokens.
|
|
140
193
|
|
|
141
194
|
A reproducible version lives in [`benchmarks/split_bench.py`](benchmarks/split_bench.py).
|
|
142
195
|
|
|
143
196
|
| Workload | PyPcre (ms) | `re` (ms) | `regex` (ms) | PyPcre edge |
|
|
144
197
|
| --- | ---: | ---: | ---: | --- |
|
|
145
|
-
| Delimiter no group (`\s+`) | `
|
|
146
|
-
| Delimiter with group (`(\s+)`) | `
|
|
147
|
-
| Single char (` `) | `
|
|
148
|
-
| Single char with group (`( )`) | `
|
|
149
|
-
| Empty pattern (`''`) | `
|
|
198
|
+
| Delimiter no group (`\s+`) | `3.349` | `8.013` | `9.913` | **2.4x** vs `re`, **3.0x** vs `regex` |
|
|
199
|
+
| Delimiter with group (`(\s+)`) | `5.080` | `9.142` | `12.374` | **1.8x** vs `re`, **2.4x** vs `regex` |
|
|
200
|
+
| Single char (` `) | `1.484` | `1.666` | `6.963` | **1.1x** vs `re`, **4.7x** vs `regex` |
|
|
201
|
+
| Single char with group (`( )`) | `1.772` | `4.203` | `8.875` | **2.4x** vs `re`, **5.0x** vs `regex` |
|
|
202
|
+
| Empty pattern (`''`) | `35.736` | `18.386` | `35.801` | **0.5x** vs `re`, parity vs `regex` |
|
|
150
203
|
|
|
151
204
|
### Free-Threaded Benchmark Highlights 🧵
|
|
152
205
|
|
|
153
|
-
Measured on the same `Python 3.14.
|
|
206
|
+
Measured on the same Apple arm64 `Python 3.14.0rc2` free-threaded build with `8` threads fanning out over split copies of each workload. Values are medians of three outer runs; lower is better.
|
|
154
207
|
|
|
155
208
|
A reproducible version lives in [`benchmarks/free_threaded_bench.py`](benchmarks/free_threaded_bench.py).
|
|
156
209
|
|
|
157
210
|
| Workload | PyPcre (ms) | `re` (ms) | `regex` (ms) | PyPcre edge |
|
|
158
211
|
| --- | ---: | ---: | ---: | --- |
|
|
159
|
-
| Extract `WARN` / `ERROR` lines (`findall`) | `0.
|
|
160
|
-
| Per-line full-name extraction (`findall`) | `0.
|
|
212
|
+
| Extract `WARN` / `ERROR` lines (`findall`) | `0.401` | `2.430` | `2.626` | **6.1x** vs `re`, **6.6x** vs `regex` |
|
|
213
|
+
| Per-line full-name extraction (`findall`) | `0.462` | `2.351` | `1.477` | **5.1x** vs `re`, **3.2x** vs `regex` |
|
|
161
214
|
|
|
162
215
|
PyPcre is the stronger all-around choice when you want more than the baseline: full `PCRE2` features, more expressive syntax, JIT, explicit free-threaded support, and a stable `re`-compatible API surface. It keeps Python ergonomics while giving you a substantially more capable engine. 🚀
|
|
163
216
|
|
|
@@ -303,7 +356,13 @@ the conversion without repeating the flag.
|
|
|
303
356
|
- `pcre.configure(jit=False)` disables JIT globally. `Flag.JIT` and
|
|
304
357
|
`Flag.NO_JIT` let you override that per pattern.
|
|
305
358
|
- `pcre.set_cache_limit()`, `pcre.get_cache_limit()`, and `pcre.clear_cache()`
|
|
306
|
-
control
|
|
359
|
+
control every high-level compile/template helper cache in the active context.
|
|
360
|
+
A zero limit disables them, and `None` uses a 256-entry hard safety ceiling
|
|
361
|
+
rather than permitting unbounded growth. High-level cache entries never cross
|
|
362
|
+
thread scope in the default thread-local strategy; a clear invalidates live
|
|
363
|
+
workers' high-level helper caches on their next cache-backed call. Backend
|
|
364
|
+
scratch buffers remain thread-scoped and are released when that thread exits.
|
|
365
|
+
Oversized patterns and templates are not retained.
|
|
307
366
|
- `pcre.configure_threads()`, `pcre.configure_thread_pool()`,
|
|
308
367
|
`shutdown_thread_pool()`, `Flag.THREADS`, and `Flag.NO_THREADS` are available
|
|
309
368
|
if you want to opt into or restrict threaded execution.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyPcre
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.2
|
|
4
4
|
Summary: Modern, GIL-friendly, Fast Python bindings for PCRE2 with auto caching and JIT of compiled patterns.
|
|
5
5
|
Author-email: ModelCloud <qubitium@modelcloud.ai>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
7
|
-
Project-URL: Homepage, https://github.com/ModelCloud/
|
|
7
|
+
Project-URL: Homepage, https://github.com/ModelCloud/PyPcre
|
|
8
8
|
Keywords: regex,pcre2,bindings
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
|
10
10
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
@@ -16,7 +16,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
16
16
|
Classifier: Programming Language :: C
|
|
17
17
|
Classifier: Topic :: Software Development :: Libraries
|
|
18
18
|
Classifier: Topic :: Text Processing :: Linguistic
|
|
19
|
-
Requires-Python: >=3.
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
22
|
Dynamic: license-file
|
|
@@ -47,6 +47,7 @@ Fast, free-threaded Python bindings for `PCRE2` with a stable `stdlib.re`-compat
|
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
## Latest News 🚀
|
|
50
|
+
* 08/09–08/10/2026 **API performance and safety update**: common regex workloads and ordered `parallel_map(search)` workloads were benchmarked across Python 3.10 and free-threaded Python 3.14t/GIL=0. Compatibility fallbacks preserve complex patterns, subclasses, buffers, and callables. Unsafe UTF bytes compilation is also blocked, with differential, randomized, concurrency, subprocess, and memory-safety coverage. 🧵⚡🛡️
|
|
50
51
|
* 08/08/2026 **0.6.0**: `findall`, `finditer`, `sub`/`subn`, `split`, and `match`/`search`/`fullmatch` are now up to **46x faster** than `stdlib.re` and **48x faster** than `regex` on `finditer`/`findall` workloads, **13x** on `split`, and **2–9x** on `sub`/`subn` backref workloads, with full `re` semantics. Free-threaded `findall` reaches **13.8x** vs `re` on 8 threads. 🚀⚡
|
|
51
52
|
* 07/27/2026 [0.5.0](https://github.com/ModelCloud/PyPcre/releases/tag/v0.5.0): Zero-copy buffer-protocol subject support (`mmap.mmap`, `bytearray`, `array.array`) with UTF-8 validation and GIL=0-safe memory pinning. 🗂️⚡
|
|
52
53
|
* 07/24/2026 [0.4.0](https://github.com/ModelCloud/PyPcre/releases/tag/v0.4.0): C extension hardening (memory/pointer safety, bounds checks, atomic allocator init), GIL=0 safety verified, vectorized UTF-8 index/offset conversion, GIL-release threshold for small calls, C `findall` implementation, and README competitor benchmarks. 🛡️⚡
|
|
@@ -68,10 +69,10 @@ PyPcre pairs Python's familiar `re`-compatible API with the real `PCRE2` engine.
|
|
|
68
69
|
|
|
69
70
|
- 🧬 **Full power of PCRE2**: PyPcre uses the real `PCRE2` engine, so you get native compile options, semantics, JIT, and upstream tuning.
|
|
70
71
|
- 🔥 **More expressive regex syntax**: `PCRE2` supports constructs beyond stdlib `re`, including atomic groups `(?>...)`, possessive quantifiers `++`, branch-reset groups `(?|...)`, richer lookarounds, and backtracking control verbs like `(*SKIP)(*FAIL)`.
|
|
71
|
-
- 🧵 **Thread-safe into `nogil`**: PyPcre is built for `PYTHON_GIL=0`, with CI coverage
|
|
72
|
+
- 🧵 **Thread-safe into `nogil`**: PyPcre is built for `PYTHON_GIL=0`, with CI coverage and `parallel_map()` for multi-subject fan-out.
|
|
72
73
|
- ⚡ **Fast on real workloads**: `PCRE2` JIT plus cached compiled patterns lets PyPcre match or beat `re` and `regex` on many common scans, especially multiline searches, lookaround-heavy patterns, and free-threaded execution.
|
|
73
74
|
- 🛡️ **Safer operational story**: PyPcre prefers the system `libpcre2-8` shared library so normal OS package updates can bring security and bug-fix benefits without a bundled fork.
|
|
74
|
-
- ✅ **Validated thoroughly**: the project runs API
|
|
75
|
+
- ✅ **Validated thoroughly**: the project runs API, fuzz, concurrency, and memory-safety tests.
|
|
75
76
|
|
|
76
77
|
### Quick Comparison 🥊
|
|
77
78
|
|
|
@@ -88,17 +89,69 @@ PyPcre pairs Python's familiar `re`-compatible API with the real `PCRE2` engine.
|
|
|
88
89
|
|
|
89
90
|
### Benchmark Highlights 🏁
|
|
90
91
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
The tables below summarize representative public workloads. Lower is better.
|
|
93
|
+
|
|
94
|
+
#### Fan-out and API speedups
|
|
95
|
+
|
|
96
|
+
Both interpreter runs used the same scheduler policy. The host reports 12
|
|
97
|
+
performance logical CPUs and 4 efficiency logical CPUs; macOS does not provide
|
|
98
|
+
an unprivileged hard per-process CPU mask, so these measurements record the
|
|
99
|
+
topology rather than claiming hard CPU affinity.
|
|
100
|
+
|
|
101
|
+
| Workload | Python 3.10 | Python 3.14t/GIL=0 |
|
|
102
|
+
| --- | ---: | ---: |
|
|
103
|
+
| `parallel_map(search)`, 16 × 1 MiB subjects, 12 workers | **8.57x** | **7.85x** |
|
|
104
|
+
| `parallel_map(findall)`, 48 × 1 MiB subjects, 12 workers | **11.51x** | **11.25x** |
|
|
105
|
+
| No-op `escape("literal")` | **5.0x** | **3.6x** |
|
|
106
|
+
| No-op `escape(b"literal")` | **6.9x** | **6.5x** |
|
|
107
|
+
| Bound literal `sub(..., count=1)` | **4.7x** | **4.3x** |
|
|
108
|
+
| Bound numeric-reference `sub(..., count=1)` | **4.3x** | **4.1x** |
|
|
109
|
+
| Bound explicit-reference `sub(..., count=1)` | **4.6x** | **4.3x** |
|
|
110
|
+
| Bound named-reference `sub(..., count=1)` | **4.2x** | **4.3x** |
|
|
111
|
+
| Bound numeric-reference `sub(..., count=2)` | **4.6x** | **4.2x** |
|
|
112
|
+
| Bound numeric-reference `sub(..., count=4)` | **6.0x** | **5.1x** |
|
|
113
|
+
| Bound numeric-reference `sub(..., count=8)` | **8.6x** | **6.1x** |
|
|
114
|
+
| Cached compile with `re.I` | **6.7x** | **6.9x** |
|
|
115
|
+
| Cached compile with `re.I|re.M|re.S|re.X` | **6.2x** | **6.4x** |
|
|
116
|
+
| First-read `lastindex` cost, sole capture | **11.8x** | **8.2x** |
|
|
117
|
+
| Deprecated `template()` compatibility call | **6.2x** | **1.1x** |
|
|
118
|
+
| Literal-capture `findall`, 100 matches | **5.0x** | **6.2x** |
|
|
119
|
+
| Literal-capture `findall`, 500 matches | **7.0x** | **8.4x** |
|
|
120
|
+
| Two literal captures `findall`, 100 matches | **7.5x** | **10.8x** |
|
|
121
|
+
| Two literal captures `findall`, 500 matches | **13.5x** | **18.3x** |
|
|
122
|
+
| Eight literal captures `findall`, 500 matches | **24.5x** | **29.4x** |
|
|
123
|
+
| Three literal captures `split`, 500 captures | **4.5x** | **6.5x** |
|
|
124
|
+
| Eight literal captures `split`, 500 captures | **6.6x** | **9.0x** |
|
|
125
|
+
| Literal-capture `split`, 100 captures | **2.6x** | **3.5x** |
|
|
126
|
+
| Literal-capture `split`, 2,000 captures | **3.1x** | **3.8x** |
|
|
127
|
+
| Bound one-character literal `Pattern.split` | **2.1x** | **1.7x** |
|
|
128
|
+
| Bound backreference `sub` hot path | **1.38 μs** | **1.14 μs** |
|
|
129
|
+
| One-match numeric-reference `Pattern.sub` | **0.45 μs** | **0.34 μs** |
|
|
130
|
+
| One-match explicit-reference `Pattern.sub` | **0.45 μs** | **0.31 μs** |
|
|
131
|
+
| One-match named-reference `Pattern.sub` | **0.46 μs** | **0.33 μs** |
|
|
132
|
+
| Repeated call-local `Match.groups()` | **~0.05 μs** | **~0.05 μs** |
|
|
133
|
+
| Call-local `Match.expand(r"[\\1]")` | **0.07 μs** | **0.07 μs** |
|
|
134
|
+
| Call-local `Match.expand(r"[\\g<1>]")` | **0.11 μs** | **0.08 μs** |
|
|
135
|
+
| Call-local `Match.expand(r"[\\g<word>]")` | **0.13 μs** | **0.11 μs** |
|
|
136
|
+
| Call-local two-name `Match.expand` | **0.18 μs** | **0.15 μs** |
|
|
137
|
+
| Call-local three-name `Match.expand` | **0.23 μs** | **0.20 μs** |
|
|
138
|
+
| Call-local eight-name `Match.expand` | **0.44 μs** | **0.39 μs** |
|
|
139
|
+
| Literal-backslash + named `Match.expand` | **0.12 μs** | **0.10 μs** |
|
|
140
|
+
| Named + backslash-suffix `Match.expand` | **0.16 μs** | **0.13 μs** |
|
|
141
|
+
| Repeated default `compile("(x)")` | **0.49 μs** | **0.38 μs** |
|
|
142
|
+
| Repeated integer-flagged `compile("x", CASELESS)` | **1.16 μs** | **0.81 μs** |
|
|
143
|
+
|
|
144
|
+
The parallel figures are serial-to-parallel speedups and preserve input order
|
|
145
|
+
and exception behavior. They were measured with the same scheduler policy for
|
|
146
|
+
both interpreters on the Apple host.
|
|
94
147
|
|
|
95
148
|
#### `findall` — large multiline and lookaround workloads
|
|
96
149
|
|
|
97
150
|
| Workload | PyPcre (ms) | `re` (ms) | `regex` (ms) | PyPcre edge |
|
|
98
151
|
| --- | ---: | ---: | ---: | --- |
|
|
99
|
-
| Extract `WARN` / `ERROR` lines (multiline) | `0.
|
|
100
|
-
| Per-line full-name extraction (multiline) | `0.
|
|
101
|
-
| Lookbehind + negative-lookahead tokens | `1.
|
|
152
|
+
| Extract `WARN` / `ERROR` lines (multiline) | `0.471` | `15.098` | `16.281` | **32.1x** vs `re`, **34.6x** vs `regex` |
|
|
153
|
+
| Per-line full-name extraction (multiline) | `0.588` | `14.305` | `8.000` | **24.3x** vs `re`, **13.6x** vs `regex` |
|
|
154
|
+
| Lookbehind + negative-lookahead tokens | `1.013` | `6.129` | `5.267` | **6.1x** vs `re`, **5.2x** vs `regex` |
|
|
102
155
|
|
|
103
156
|
Patterns used:
|
|
104
157
|
|
|
@@ -113,51 +166,51 @@ Patterns used:
|
|
|
113
166
|
|
|
114
167
|
#### `finditer` — same workloads
|
|
115
168
|
|
|
116
|
-
Measured on
|
|
169
|
+
Measured on Python 3.10.11 arm64 with compiled-pattern reuse and JIT enabled. A reproducible version lives in [`benchmarks/finditer_bench.py`](benchmarks/finditer_bench.py).
|
|
117
170
|
|
|
118
171
|
| Workload | PyPcre (ms) | `re` (ms) | `regex` (ms) | PyPcre edge |
|
|
119
172
|
| --- | ---: | ---: | ---: | --- |
|
|
120
|
-
| Extract `WARN` / `ERROR` lines | `0.
|
|
121
|
-
| Per-line full-name extraction | `0.
|
|
122
|
-
| Lookbehind + negative lookahead | `
|
|
173
|
+
| Extract `WARN` / `ERROR` lines | `0.449` | `17.145` | `16.175` | **38.2x** vs `re`, **36.0x** vs `regex` |
|
|
174
|
+
| Per-line full-name extraction | `0.564` | `16.258` | `7.874` | **28.8x** vs `re`, **14.0x** vs `regex` |
|
|
175
|
+
| Lookbehind + negative lookahead | `1.942` | `8.548` | `6.037` | **4.4x** vs `re`, **3.1x** vs `regex` |
|
|
123
176
|
|
|
124
177
|
#### `sub` / `subn` — high-volume replacement workloads
|
|
125
178
|
|
|
126
|
-
Measured on
|
|
179
|
+
Measured on Python 3.10.11 arm64 with compiled-pattern reuse and JIT enabled. Values are medians of three outer runs; lower is better. The benchmark replaces 100,000 space-separated tokens.
|
|
127
180
|
|
|
128
181
|
A reproducible version lives in [`benchmarks/sub_bench.py`](benchmarks/sub_bench.py).
|
|
129
182
|
|
|
130
183
|
| Workload | PyPcre (ms) | `re` (ms) | `regex` (ms) | PyPcre edge |
|
|
131
184
|
| --- | ---: | ---: | ---: | --- |
|
|
132
|
-
| Literal replacement (`\w+` → `[X]`) | `
|
|
133
|
-
| Single numeric backref (`(w)\d+` → `[\1]`) | `
|
|
134
|
-
| Two numeric backrefs (`(w)(\d+)` → `\2-\1`) | `
|
|
135
|
-
| Named backref (`(?P<g>\w+)` → `<\g<g>>`) | `
|
|
185
|
+
| Literal replacement (`\w+` → `[X]`) | `3.127` | `6.489` | `9.992` | **2.1x** vs `re`, **3.2x** vs `regex` |
|
|
186
|
+
| Single numeric backref (`(w)\d+` → `[\1]`) | `4.003` | `30.098` | `12.481` | **7.5x** vs `re`, **3.1x** vs `regex` |
|
|
187
|
+
| Two numeric backrefs (`(w)(\d+)` → `\2-\1`) | `9.940` | `35.052` | `16.201` | **3.5x** vs `re`, **1.6x** vs `regex` |
|
|
188
|
+
| Named backref (`(?P<g>\w+)` → `<\g<g>>`) | `9.765` | `32.434` | `15.216` | **3.3x** vs `re`, **1.6x** vs `regex` |
|
|
136
189
|
|
|
137
190
|
#### `split` — high-volume delimiter workloads
|
|
138
191
|
|
|
139
|
-
Measured on
|
|
192
|
+
Measured on Python 3.10.11 arm64 with compiled-pattern reuse and JIT enabled. Values are medians of three outer runs; lower is better. The benchmark splits 100,000 space-separated tokens.
|
|
140
193
|
|
|
141
194
|
A reproducible version lives in [`benchmarks/split_bench.py`](benchmarks/split_bench.py).
|
|
142
195
|
|
|
143
196
|
| Workload | PyPcre (ms) | `re` (ms) | `regex` (ms) | PyPcre edge |
|
|
144
197
|
| --- | ---: | ---: | ---: | --- |
|
|
145
|
-
| Delimiter no group (`\s+`) | `
|
|
146
|
-
| Delimiter with group (`(\s+)`) | `
|
|
147
|
-
| Single char (` `) | `
|
|
148
|
-
| Single char with group (`( )`) | `
|
|
149
|
-
| Empty pattern (`''`) | `
|
|
198
|
+
| Delimiter no group (`\s+`) | `3.349` | `8.013` | `9.913` | **2.4x** vs `re`, **3.0x** vs `regex` |
|
|
199
|
+
| Delimiter with group (`(\s+)`) | `5.080` | `9.142` | `12.374` | **1.8x** vs `re`, **2.4x** vs `regex` |
|
|
200
|
+
| Single char (` `) | `1.484` | `1.666` | `6.963` | **1.1x** vs `re`, **4.7x** vs `regex` |
|
|
201
|
+
| Single char with group (`( )`) | `1.772` | `4.203` | `8.875` | **2.4x** vs `re`, **5.0x** vs `regex` |
|
|
202
|
+
| Empty pattern (`''`) | `35.736` | `18.386` | `35.801` | **0.5x** vs `re`, parity vs `regex` |
|
|
150
203
|
|
|
151
204
|
### Free-Threaded Benchmark Highlights 🧵
|
|
152
205
|
|
|
153
|
-
Measured on the same `Python 3.14.
|
|
206
|
+
Measured on the same Apple arm64 `Python 3.14.0rc2` free-threaded build with `8` threads fanning out over split copies of each workload. Values are medians of three outer runs; lower is better.
|
|
154
207
|
|
|
155
208
|
A reproducible version lives in [`benchmarks/free_threaded_bench.py`](benchmarks/free_threaded_bench.py).
|
|
156
209
|
|
|
157
210
|
| Workload | PyPcre (ms) | `re` (ms) | `regex` (ms) | PyPcre edge |
|
|
158
211
|
| --- | ---: | ---: | ---: | --- |
|
|
159
|
-
| Extract `WARN` / `ERROR` lines (`findall`) | `0.
|
|
160
|
-
| Per-line full-name extraction (`findall`) | `0.
|
|
212
|
+
| Extract `WARN` / `ERROR` lines (`findall`) | `0.401` | `2.430` | `2.626` | **6.1x** vs `re`, **6.6x** vs `regex` |
|
|
213
|
+
| Per-line full-name extraction (`findall`) | `0.462` | `2.351` | `1.477` | **5.1x** vs `re`, **3.2x** vs `regex` |
|
|
161
214
|
|
|
162
215
|
PyPcre is the stronger all-around choice when you want more than the baseline: full `PCRE2` features, more expressive syntax, JIT, explicit free-threaded support, and a stable `re`-compatible API surface. It keeps Python ergonomics while giving you a substantially more capable engine. 🚀
|
|
163
216
|
|
|
@@ -303,7 +356,13 @@ the conversion without repeating the flag.
|
|
|
303
356
|
- `pcre.configure(jit=False)` disables JIT globally. `Flag.JIT` and
|
|
304
357
|
`Flag.NO_JIT` let you override that per pattern.
|
|
305
358
|
- `pcre.set_cache_limit()`, `pcre.get_cache_limit()`, and `pcre.clear_cache()`
|
|
306
|
-
control
|
|
359
|
+
control every high-level compile/template helper cache in the active context.
|
|
360
|
+
A zero limit disables them, and `None` uses a 256-entry hard safety ceiling
|
|
361
|
+
rather than permitting unbounded growth. High-level cache entries never cross
|
|
362
|
+
thread scope in the default thread-local strategy; a clear invalidates live
|
|
363
|
+
workers' high-level helper caches on their next cache-backed call. Backend
|
|
364
|
+
scratch buffers remain thread-scoped and are released when that thread exits.
|
|
365
|
+
Oversized patterns and templates are not retained.
|
|
307
366
|
- `pcre.configure_threads()`, `pcre.configure_thread_pool()`,
|
|
308
367
|
`shutdown_thread_pool()`, `Flag.THREADS`, and `Flag.NO_THREADS` are available
|
|
309
368
|
if you want to opt into or restrict threaded execution.
|
|
@@ -38,24 +38,39 @@ tests/test_c_api_audit.py
|
|
|
38
38
|
tests/test_cache.py
|
|
39
39
|
tests/test_cache_global.py
|
|
40
40
|
tests/test_cache_global_inproc.py
|
|
41
|
+
tests/test_cache_scope_safety.py
|
|
41
42
|
tests/test_clobber.py
|
|
42
43
|
tests/test_clobber_thread.py
|
|
44
|
+
tests/test_clobber_verify.py
|
|
45
|
+
tests/test_compile_utf_no_check_safety.py
|
|
43
46
|
tests/test_core.py
|
|
44
47
|
tests/test_coverage_gaps.py
|
|
45
48
|
tests/test_errors.py
|
|
49
|
+
tests/test_escape_fastpath.py
|
|
50
|
+
tests/test_expand_fastpath.py
|
|
46
51
|
tests/test_flags.py
|
|
47
52
|
tests/test_gil_zero_safety.py
|
|
48
53
|
tests/test_jit.py
|
|
49
54
|
tests/test_jit_anchoring.py
|
|
55
|
+
tests/test_jit_start_optimize_workaround.py
|
|
56
|
+
tests/test_lastindex_ovector_fastpath.py
|
|
50
57
|
tests/test_lastindex_semantics.py
|
|
58
|
+
tests/test_literal_capture_findall_fastpath.py
|
|
59
|
+
tests/test_literal_capture_split_fastpath.py
|
|
51
60
|
tests/test_memory.py
|
|
52
61
|
tests/test_mmap.py
|
|
53
62
|
tests/test_module.py
|
|
63
|
+
tests/test_multi_literal_capture_findall_fastpath.py
|
|
64
|
+
tests/test_multi_literal_capture_split_fastpath.py
|
|
54
65
|
tests/test_pattern.py
|
|
55
66
|
tests/test_python_coverage_audit.py
|
|
56
67
|
tests/test_re_compat.py
|
|
57
68
|
tests/test_setup_utils_multiarch.py
|
|
58
69
|
tests/test_simd.py
|
|
70
|
+
tests/test_stdlib_flag_fastpath.py
|
|
71
|
+
tests/test_sub_count_one_fastpath.py
|
|
72
|
+
tests/test_sub_reference_fastpath.py
|
|
73
|
+
tests/test_template_dispatch_fastpath.py
|
|
59
74
|
tests/test_threaded_backend.py
|
|
60
75
|
tests/test_threads.py
|
|
61
76
|
tests/test_transformers_regex.py
|