From 552cf86b83e8aafebcfe9abbc77101bdbfda14c8 Mon Sep 17 00:00:00 2001 From: Fangyi Zhou Date: Sun, 31 Aug 2025 16:50:23 +0100 Subject: [PATCH 1/3] gh-138295: Fix a grammar issue in the descriptor HOWTO (GH-138296) "an str" -> "a str" --- Doc/howto/descriptor.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index f6c3e473f1c36d..9d5a9ac8b718cb 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -420,7 +420,7 @@ Here are three practical data validation utilities: def validate(self, value): if not isinstance(value, str): - raise TypeError(f'Expected {value!r} to be an str') + raise TypeError(f'Expected {value!r} to be a str') if self.minsize is not None and len(value) < self.minsize: raise ValueError( f'Expected {value!r} to be no smaller than {self.minsize!r}' From 15e37ea6b7f7070c112aa3118ba46325c4cfde2c Mon Sep 17 00:00:00 2001 From: Cody Maloney Date: Sun, 31 Aug 2025 12:14:19 -0700 Subject: [PATCH 2/3] gh-138013: Make ``test.test_io`` into a package (#138153) --- Lib/test/test_io/__init__.py | 5 +++++ Lib/test/test_io/__main__.py | 4 ++++ Lib/test/{test_io.py => test_io/test_general.py} | 2 +- Makefile.pre.in | 1 + 4 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 Lib/test/test_io/__init__.py create mode 100644 Lib/test/test_io/__main__.py rename Lib/test/{test_io.py => test_io/test_general.py} (99%) diff --git a/Lib/test/test_io/__init__.py b/Lib/test/test_io/__init__.py new file mode 100644 index 00000000000000..4b16ecc31156a5 --- /dev/null +++ b/Lib/test/test_io/__init__.py @@ -0,0 +1,5 @@ +import os +from test.support import load_package_tests + +def load_tests(*args): + return load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_io/__main__.py b/Lib/test/test_io/__main__.py new file mode 100644 index 00000000000000..40a23a297ec2b4 --- /dev/null +++ b/Lib/test/test_io/__main__.py @@ -0,0 +1,4 @@ +from . import load_tests +import unittest + +unittest.main() diff --git a/Lib/test/test_io.py b/Lib/test/test_io/test_general.py similarity index 99% rename from Lib/test/test_io.py rename to Lib/test/test_io/test_general.py index 92be2763e5ed1e..a56a2c0157f764 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io/test_general.py @@ -5,7 +5,7 @@ # * test_memoryio - tests BytesIO and StringIO # * test_fileio - tests FileIO # * test_file - tests the file interface -# * test_io - tests everything else in the io module +# * test_io.test_general - tests everything else in the io module # * test_univnewlines - tests universal newline support # * test_largefile - tests operations on a file greater than 2**32 bytes # (only enabled with -ulargefile) diff --git a/Makefile.pre.in b/Makefile.pre.in index 9ce6ec65f142d8..eb07f66f14ffc5 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2670,6 +2670,7 @@ TESTSUBDIRS= idlelib/idle_test \ test/test_importlib/source \ test/test_inspect \ test/test_interpreters \ + test/test_io \ test/test_json \ test/test_module \ test/test_multiprocessing_fork \ From 78acd8e95e78bc410b8207cd60e1323ece01b3d5 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com> Date: Sun, 31 Aug 2025 21:29:02 +0100 Subject: [PATCH 3/3] gh-138286: Run ``ruff`` on ``Tools/i18n`` (#138287) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Tomas R. --- .pre-commit-config.yaml | 4 ++++ Tools/i18n/.ruff.toml | 10 ++++++++++ Tools/i18n/makelocalealias.py | 14 +++++++------- Tools/i18n/msgfmt.py | 22 +++++++++++----------- Tools/i18n/pygettext.py | 4 ++-- 5 files changed, 34 insertions(+), 20 deletions(-) create mode 100644 Tools/i18n/.ruff.toml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d101f5c37e60b1..61db8c456c2e64 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,6 +14,10 @@ repos: name: Run Ruff (lint) on Tools/build/ args: [--exit-non-zero-on-fix, --config=Tools/build/.ruff.toml] files: ^Tools/build/ + - id: ruff + name: Run Ruff (lint) on Tools/i18n/ + args: [--exit-non-zero-on-fix, --config=Tools/i18n/.ruff.toml] + files: ^Tools/i18n/ - id: ruff name: Run Ruff (lint) on Argument Clinic args: [--exit-non-zero-on-fix, --config=Tools/clinic/.ruff.toml] diff --git a/Tools/i18n/.ruff.toml b/Tools/i18n/.ruff.toml new file mode 100644 index 00000000000000..a8f4f2f5a96d7b --- /dev/null +++ b/Tools/i18n/.ruff.toml @@ -0,0 +1,10 @@ +extend = "../../.ruff.toml" # Inherit the project-wide settings + +target-version = "py313" + +[lint] +select = [ + "F", # pyflakes + "I", # isort + "UP", # pyupgrade +] diff --git a/Tools/i18n/makelocalealias.py b/Tools/i18n/makelocalealias.py index 7f001abc09745d..f825862ffdf350 100755 --- a/Tools/i18n/makelocalealias.py +++ b/Tools/i18n/makelocalealias.py @@ -8,6 +8,7 @@ """ import locale import sys + _locale = locale # Location of the X11 alias file. @@ -100,16 +101,15 @@ def parse_glibc_supported(filename): def pprint(data): items = sorted(data.items()) for k, v in items: - print(' %-40s%a,' % ('%a:' % k, v)) + print(f" {k!a:<40}{v!a},") def print_differences(data, olddata): items = sorted(olddata.items()) for k, v in items: if k not in data: - print('# removed %a' % k) + print(f'# removed {k!a}') elif olddata[k] != data[k]: - print('# updated %a -> %a to %a' % \ - (k, olddata[k], data[k])) + print(f'# updated {k!a} -> {olddata[k]!a} to {data[k]!a}') # Additions are not mentioned def optimize(data): @@ -132,7 +132,7 @@ def check(data): errors = 0 for k, v in data.items(): if locale.normalize(k) != v: - print('ERROR: %a -> %a != %a' % (k, locale.normalize(k), v), + print(f'ERROR: {k!a} -> {locale.normalize(k)!a} != {v!a}', file=sys.stderr) errors += 1 return errors @@ -142,10 +142,10 @@ def check(data): parser = argparse.ArgumentParser() parser.add_argument('--locale-alias', default=LOCALE_ALIAS, help='location of the X11 alias file ' - '(default: %a)' % LOCALE_ALIAS) + f'(default: {LOCALE_ALIAS})') parser.add_argument('--glibc-supported', default=SUPPORTED, help='location of the glibc SUPPORTED locales file ' - '(default: %a)' % SUPPORTED) + f'(default: {SUPPORTED})') args = parser.parse_args() data = locale.locale_alias.copy() diff --git a/Tools/i18n/msgfmt.py b/Tools/i18n/msgfmt.py index 65254a7c375456..3351511bbc8f2b 100755 --- a/Tools/i18n/msgfmt.py +++ b/Tools/i18n/msgfmt.py @@ -24,14 +24,14 @@ Display version information and exit. """ -import os -import sys +import array import ast +import codecs import getopt +import os import struct -import array +import sys from email.parser import HeaderParser -import codecs __version__ = "1.2" @@ -113,7 +113,7 @@ def make(filename, outfile): try: with open(infile, 'rb') as f: lines = f.readlines() - except IOError as msg: + except OSError as msg: print(msg, file=sys.stderr) sys.exit(1) @@ -126,6 +126,7 @@ def make(filename, outfile): sys.exit(1) section = msgctxt = None + msgid = msgstr = b'' fuzzy = 0 # Start off assuming Latin-1, so everything decodes without failure, @@ -177,7 +178,7 @@ def make(filename, outfile): # This is a message with plural forms elif l.startswith('msgid_plural'): if section != ID: - print('msgid_plural not preceded by msgid on %s:%d' % (infile, lno), + print(f'msgid_plural not preceded by msgid on {infile}:{lno}', file=sys.stderr) sys.exit(1) l = l[12:] @@ -188,7 +189,7 @@ def make(filename, outfile): section = STR if l.startswith('msgstr['): if not is_plural: - print('plural without msgid_plural on %s:%d' % (infile, lno), + print(f'plural without msgid_plural on {infile}:{lno}', file=sys.stderr) sys.exit(1) l = l.split(']', 1)[1] @@ -196,7 +197,7 @@ def make(filename, outfile): msgstr += b'\0' # Separator of the various plural forms else: if is_plural: - print('indexed msgstr required for plural on %s:%d' % (infile, lno), + print(f'indexed msgstr required for plural on {infile}:{lno}', file=sys.stderr) sys.exit(1) l = l[6:] @@ -212,8 +213,7 @@ def make(filename, outfile): elif section == STR: msgstr += l.encode(encoding) else: - print('Syntax error on %s:%d' % (infile, lno), \ - 'before:', file=sys.stderr) + print(f'Syntax error on {infile}:{lno} before:', file=sys.stderr) print(l, file=sys.stderr) sys.exit(1) # Add last entry @@ -226,7 +226,7 @@ def make(filename, outfile): try: with open(outfile,"wb") as f: f.write(output) - except IOError as msg: + except OSError as msg: print(msg, file=sys.stderr) diff --git a/Tools/i18n/pygettext.py b/Tools/i18n/pygettext.py index f46b05067d7fde..ddf4474d2bce55 100755 --- a/Tools/i18n/pygettext.py +++ b/Tools/i18n/pygettext.py @@ -193,7 +193,7 @@ def make_escapes(pass_nonascii): escape = escape_ascii else: escape = escape_nonascii - escapes = [r"\%03o" % i for i in range(256)] + escapes = [fr"\{i:03o}" for i in range(256)] for i in range(32, 127): escapes[i] = chr(i) escapes[ord('\\')] = r'\\' @@ -796,7 +796,7 @@ class Options: try: with open(options.excludefilename) as fp: options.toexclude = fp.readlines() - except IOError: + except OSError: print(f"Can't read --exclude-file: {options.excludefilename}", file=sys.stderr) sys.exit(1)