From 4de4e654e592c4b3b1a073140b97ff7f373c7553 Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Sun, 14 Jan 2024 23:06:04 +0000 Subject: [PATCH 1/2] Replace `pathlib._abc.PathModuleBase.splitroot()` with `splitdrive()` (#114065) This allows users of the `pathlib-abc` PyPI package to use `posixpath` or `ntpath` as a path module in versions of Python lacking `os.path.splitroot()` (3.11 and before). --- Lib/pathlib/_abc.py | 18 ++++++++---------- Lib/test/test_pathlib/test_pathlib_abc.py | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Lib/pathlib/_abc.py b/Lib/pathlib/_abc.py index 1fdca004d6b31f..48a6c218309385 100644 --- a/Lib/pathlib/_abc.py +++ b/Lib/pathlib/_abc.py @@ -165,12 +165,11 @@ def split(self, path): """ self._unsupported('split()') - def splitroot(self, path): - """Split the pathname path into a 3-item tuple (drive, root, tail), - where *drive* is a device name or mount point, *root* is a string of - separators after the drive, and *tail* is everything after the root. - Any part may be empty.""" - self._unsupported('splitroot()') + def splitdrive(self, path): + """Split the path into a 2-item tuple (drive, tail), where *drive* is + a device name or mount point, and *tail* is everything after the + drive. Either part may be empty.""" + self._unsupported('splitdrive()') def normcase(self, path): """Normalize the case of the path.""" @@ -227,18 +226,17 @@ def as_posix(self): @property def drive(self): """The drive prefix (letter or UNC path), if any.""" - return self.pathmod.splitroot(self._raw_path)[0] + return self.pathmod.splitdrive(self.anchor)[0] @property def root(self): """The root of the path, if any.""" - return self.pathmod.splitroot(self._raw_path)[1] + return self.pathmod.splitdrive(self.anchor)[1] @property def anchor(self): """The concatenation of the drive and root, or ''.""" - drive, root, _ = self.pathmod.splitroot(self._raw_path) - return drive + root + return self._stack[0] @property def name(self): diff --git a/Lib/test/test_pathlib/test_pathlib_abc.py b/Lib/test/test_pathlib/test_pathlib_abc.py index c3c568c296e25c..f877c98b7678f4 100644 --- a/Lib/test/test_pathlib/test_pathlib_abc.py +++ b/Lib/test/test_pathlib/test_pathlib_abc.py @@ -27,7 +27,7 @@ def test_unsupported_operation(self): m.sep self.assertRaises(e, m.join, 'foo') self.assertRaises(e, m.split, 'foo') - self.assertRaises(e, m.splitroot, 'foo') + self.assertRaises(e, m.splitdrive, 'foo') self.assertRaises(e, m.normcase, 'foo') self.assertRaises(e, m.isabs, 'foo') From 1709020e8ebaf9bf1bc9ee14d56173c860613931 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 15 Jan 2024 00:09:26 +0100 Subject: [PATCH 2/2] gh-113317: Move FormatCounterFormatter into libclinic (#114066) --- Tools/clinic/clinic.py | 21 +-------------------- Tools/clinic/libclinic/__init__.py | 6 ++++-- Tools/clinic/libclinic/utils.py | 29 ++++++++++++++++++++++++++--- 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index d45159f47a0989..c247bd075321cd 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -23,7 +23,6 @@ import pprint import re import shlex -import string import sys import textwrap @@ -270,24 +269,6 @@ def __init__(self) -> None: self.unlock: list[str] = [] -class FormatCounterFormatter(string.Formatter): - """ - This counts how many instances of each formatter - "replacement string" appear in the format string. - - e.g. after evaluating "string {a}, {b}, {c}, {a}" - the counts dict would now look like - {'a': 2, 'b': 1, 'c': 1} - """ - def __init__(self) -> None: - self.counts = collections.Counter[str]() - - def get_value( - self, key: str, args: object, kwargs: object # type: ignore[override] - ) -> Literal['']: - self.counts[key] += 1 - return '' - class Language(metaclass=abc.ABCMeta): start_line = "" @@ -341,7 +322,7 @@ def assert_only_one( fields = ['dsl_name'] fields.extend(additional_fields) line: str = getattr(self, attr) - fcf = FormatCounterFormatter() + fcf = libclinic.FormatCounterFormatter() fcf.format(line) def local_fail(should_be_there_but_isnt: bool) -> None: if should_be_there_but_isnt: diff --git a/Tools/clinic/libclinic/__init__.py b/Tools/clinic/libclinic/__init__.py index f26bf3ef6d55fe..1b300b55acc21e 100644 --- a/Tools/clinic/libclinic/__init__.py +++ b/Tools/clinic/libclinic/__init__.py @@ -16,8 +16,9 @@ wrapped_c_string_literal, ) from .utils import ( - create_regex, + FormatCounterFormatter, compute_checksum, + create_regex, write_file, ) @@ -39,8 +40,9 @@ "wrapped_c_string_literal", # Utility functions - "create_regex", + "FormatCounterFormatter", "compute_checksum", + "create_regex", "write_file", ] diff --git a/Tools/clinic/libclinic/utils.py b/Tools/clinic/libclinic/utils.py index 1514558cb5665c..d2d09387a73d1e 100644 --- a/Tools/clinic/libclinic/utils.py +++ b/Tools/clinic/libclinic/utils.py @@ -1,6 +1,9 @@ +import collections import hashlib -import re import os +import re +import string +from typing import Literal def write_file(filename: str, new_contents: str) -> None: @@ -39,7 +42,27 @@ def create_regex( group_re = r"\w+" if word else ".+" before = re.escape(before) after = re.escape(after) - pattern = fr"{before}({group_re}){after}" + pattern = rf"{before}({group_re}){after}" if whole_line: - pattern = fr"^{pattern}$" + pattern = rf"^{pattern}$" return re.compile(pattern) + + +class FormatCounterFormatter(string.Formatter): + """ + This counts how many instances of each formatter + "replacement string" appear in the format string. + + e.g. after evaluating "string {a}, {b}, {c}, {a}" + the counts dict would now look like + {'a': 2, 'b': 1, 'c': 1} + """ + + def __init__(self) -> None: + self.counts = collections.Counter[str]() + + def get_value( + self, key: str, args: object, kwargs: object # type: ignore[override] + ) -> Literal[""]: + self.counts[key] += 1 + return ""