closes #159717
glob.translate() kept only the parts list from fnmatch._translate() and dropped the star indices, so every * in a segment became a plain backtracking [^/]*. A failing match then took exponential time, which made PurePath.match, PurePath.full_match and Path.glob hang on short patterns such as '*a' * 8 + '*b'.
This change builds each segment from both the parts and the star indices and wraps every interior STAR fixed pair in an atomic group (?>[^/]*?fixed), the same rewrite fnmatch._join_translated_parts() uses. A pair is left as it was when its fixed part can match a separator. That happens only with a character class such as [!x] or [+-0], and there the atomic group could change the result: today *[!x]*x matches a/x because the class matches the /, and this change keeps that.
Tests:
test_glob.test_translate_slow and the pathlib test_full_match_slow and test_glob_slow are counterparts of test_slow_fnmatch that use the pattern from the issue against a 100 character name. Before this change none of them finished within a 30 second timeout; with it they take a few milliseconds.
test_translate_negated_class_matches_sep pins the current result for *[!x]*x.
- The expected strings in the existing
test_translate* tests are updated for the *.* segment, which now translates to (?>[^/]*?\.)[^/]*.
I also compared the old and new translation on 20,000 random patterns built from stars, literals, separators and character classes, with every combination of recursive, include_hidden and seps, against 30 random names each, and every result was the same.