From b8fd58a0291c2981c7883c60e3e4e6050187d369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 8 Feb 2025 15:04:10 +0000 Subject: [PATCH 1/6] style: Fix repeated-append (FURB113) in build.py Use `cmd.extend(('-i', img))` instead of repeatedly calling `cmd.append()` Ruff rule: https://docs.astral.sh/ruff/rules/repeated-append/ --- build.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build.py b/build.py index d82b94b1..3a482c6a 100755 --- a/build.py +++ b/build.py @@ -1809,8 +1809,7 @@ def cmd_build_docker(options, args): cmd = ['inv', 'build-wxpython'] if options.docker_img != 'all': for img in options.docker_img.split(','): - cmd.append('-i') - cmd.append(img) + cmd.extend(('-i', img)) # Do just the gtk2 builds? if options.gtk2: From 5c06e43ae3b286f8d5f35395859ccada159fe0ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 8 Feb 2025 15:05:43 +0000 Subject: [PATCH 2/6] style: Fix sorted-min-max (FURB192) in build.py Prefer `min` over `sorted()` to compute the minimum value in a sequence Ruff rule: https://docs.astral.sh/ruff/rules/sorted-min-max/ --- build.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.py b/build.py index 3a482c6a..3504d75b 100755 --- a/build.py +++ b/build.py @@ -934,7 +934,7 @@ def do_regenerate_sysconfig(): # grab the file in that folder and copy it into the Python lib p = opj(td, pybd, '*') - datafile = sorted(glob.glob(opj(td, pybd, '*')))[0] + datafile = min(glob.glob(opj(td, pybd, '*'))) cmd = [PYTHON, '-c', 'import sysconfig; print(sysconfig.get_path("stdlib"))'] stdlib = runcmd(cmd, getOutput=True) shutil.copy(datafile, stdlib) @@ -1335,7 +1335,7 @@ def cmd_sip(options, args): # Write out a sip build file (no longer done by sip itself) sip_tmp_out_dir = opj(tmpdir, 'build', base) sip_pwd = pushDir(sip_tmp_out_dir) - header = sorted(glob.glob('*.h'))[0] + header = min(glob.glob('*.h')) sources = sorted(glob.glob('*.cpp')) del sip_pwd with open(sbf, 'w') as f: @@ -1408,7 +1408,7 @@ def cmd_sip(options, args): with tempfile.TemporaryDirectory() as tmpdir: cmd = 'sip-module --sdist --abi-version {} --target-dir {} wx.siplib'.format(cfg.SIP_ABI, tmpdir) runcmd(cmd) - tf_name = sorted(glob.glob(tmpdir + '/*.tar*'))[0] + tf_name = min(glob.glob(tmpdir + '/*.tar*')) tf_dir = os.path.splitext(os.path.splitext(tf_name)[0])[0] with tarfile.open(tf_name) as tf: try: From a50ae3da22cd6ebf7a04c079bb15d4ae147b1e1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 8 Feb 2025 15:11:02 +0000 Subject: [PATCH 3/6] Only import Path from pathlib in build.py --- build.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build.py b/build.py index 3504d75b..638ceb13 100755 --- a/build.py +++ b/build.py @@ -18,7 +18,6 @@ import glob import hashlib import optparse import os -import pathlib import re import shutil import subprocess @@ -29,6 +28,7 @@ import shlex import textwrap import warnings +from pathlib import Path from shutil import which try: @@ -802,7 +802,7 @@ def checkCompiler(quiet=False): # Make sure there is now a cl.exe on the PATH CL = 'NOT FOUND' for d in os.environ['PATH'].split(os.pathsep): - p = pathlib.Path(d, 'cl.exe') + p = Path(d, 'cl.exe') if p.exists(): CL = p break @@ -811,7 +811,7 @@ def checkCompiler(quiet=False): # # Just needed for debugging # for d in info.include.split(os.pathsep): - # p = pathlib.Path(d, 'tchar.h') + # p = Path(d, 'tchar.h') # if p.exists(): # msg(f' tchar.h: {p}') # break @@ -1425,7 +1425,7 @@ def cmd_sip(options, args): def cmd_touch(options, args): cmdTimer = CommandTimer('touch') pwd = pushDir(phoenixDir()) - etg = pathlib.Path('etg') + etg = Path('etg') for item in sorted(etg.glob('*.py')): item.touch() cmd_touch_others(options, args) @@ -1854,7 +1854,7 @@ def cmd_touch_others(options, args): cmdTimer = CommandTimer('touch_others') pwd = pushDir(phoenixDir()) cfg = Config(noWxConfig=True) - pth = pathlib.Path(opj(cfg.PKGDIR, 'svg')) + pth = Path(opj(cfg.PKGDIR, 'svg')) for item in sorted(pth.glob('*.pyx')): item.touch() From 450f106469f9d47167718b1e4fe68a61f8d3e4ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 8 Feb 2025 15:19:53 +0000 Subject: [PATCH 4/6] Use pathlib's read_text()/write_text() and read_bytes()/write_bytes() for simple file IO in build.py --- build.py | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/build.py b/build.py index 638ceb13..e5dee2a7 100755 --- a/build.py +++ b/build.py @@ -577,8 +577,7 @@ def getTool(cmdName, version, MD5, envVar, platformBinary, linuxBits=False): # now check the MD5 if not in dev mode and it's set to None if not (devMode and md5 is None): m = hashlib.md5() - with open(cmd, 'rb') as fid: - m.update(fid.read()) + m.update(Path(cmd).read_bytes()) if m.hexdigest() != md5: _error_msg('MD5 mismatch, got "%s"\n ' 'expected "%s"' % (m.hexdigest(), md5)) @@ -622,8 +621,7 @@ def getTool(cmdName, version, MD5, envVar, platformBinary, linuxBits=False): import bz2 data = bz2.decompress(data) - with open(cmd, 'wb') as f: - f.write(data) + Path(cmd).write_bytes(data) os.chmod(cmd, 0o755) # Recursive call so the MD5 value will be double-checked on what was @@ -672,8 +670,7 @@ def getMSWebView2(): sys.exit(1) # Write the downloaded data to a local file - with open(opj(dest, fname), 'wb') as f: - f.write(data) + Path(dest, fname).write_bytes(data) # Unzip it from zipfile import ZipFile @@ -929,8 +926,7 @@ def do_regenerate_sysconfig(): # On success the new data module will have been written to a subfolder # of the current folder, which is recorded in ./pybuilddir.txt - with open('pybuilddir.txt', 'r') as fp: - pybd = fp.read() + pybd = Path('pybuilddir.txt').read_text() # grab the file in that folder and copy it into the Python lib p = opj(td, pybd, '*') @@ -1323,9 +1319,7 @@ def cmd_sip(options, args): sip_gen_dir=opj(phoenixDir(), 'sip', 'gen'), ) ) - - with open(opj(tmpdir, 'pyproject.toml'), 'w') as f: - f.write(pyproject_toml) + Path(tmpdir, 'pyproject.toml').write_text(pyproject_toml) sip_pwd = pushDir(tmpdir) cmd = 'sip-build --no-compile' @@ -1770,8 +1764,7 @@ def cmd_build_py(options, args): msg('*-'*40) msg('WAF config log "{}":'.format(logfilename)) - with open(logfilename, 'r') as log: - msg(log.read()) + msg(Path(logfilename).read_text()) msg('*-'*40) runcmd(cmd, onError=_onWafError) @@ -2377,9 +2370,7 @@ def cmd_setrev(options, args): else: svnrev = getVcsRev() - with open('REV.txt', 'w') as f: - svnrev = '.dev'+svnrev - f.write(svnrev) + Path('REV.txt').write_text(svnrev) msg('REV.txt set to "%s"' % svnrev) cfg = Config() From 36fbef4c199cf9a9d7433d4873456f2e9901a5ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 8 Feb 2025 16:14:36 +0000 Subject: [PATCH 5/6] Replace textfile_open wrapper with pure calls in build.py textfile_wrapper doesn't wrap much since Python 2 hybridation is removed --- build.py | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/build.py b/build.py index e5dee2a7..3ea08e5c 100755 --- a/build.py +++ b/build.py @@ -39,7 +39,7 @@ except ImportError: from buildtools.config import Config, msg, opj, posixjoin, loadETG, etg2sip, findCmd, \ phoenixDir, wxDir, copyIfNewer, copyFile, \ macSetLoaderNames, \ - getVcsRev, runcmd, textfile_open, getSipFiles, \ + getVcsRev, runcmd, getSipFiles, \ getVisCVersion, getToolsPlatformName, updateLicenseFiles, \ TemporaryDirectory, getMSVCInfo, generateVersionFiles @@ -1061,8 +1061,7 @@ def _removeSidebar(path): """ from bs4 import BeautifulSoup for filename in sorted(glob.glob(opj(path, '*.html'))): - with textfile_open(filename, 'rt') as f: - text = f.read() + text = Path(filename).read_text(encoding="utf-8") text = text.replace('', '') soup = BeautifulSoup(text, 'html.parser') tag = soup.find('div', 'sphinxsidebar') @@ -1072,8 +1071,7 @@ def _removeSidebar(path): if tag: tag.attrs['class'] = ['document-no-sidebar'] text = str(soup) - with textfile_open(filename, 'wt') as f: - f.write(text) + Path(filename).write_text(text, encoding="utf-8") def cmd_docset(options, args): @@ -1339,7 +1337,7 @@ def cmd_sip(options, args): classesNeedingClassInfo = { 'sip_corewxTreeCtrl.cpp' : 'wxTreeCtrl', } def processSrc(src, keepHashLines=False): - with textfile_open(src, 'rt') as f: + with open(src, 'rt', encoding="utf-8") as f: srcTxt = f.read() if keepHashLines: # Either just fix the pathnames in the #line lines... @@ -1375,24 +1373,21 @@ def cmd_sip(options, args): # in cfg.SIPOUT. If so then copy the new one to cfg.SIPOUT, otherwise # ignore it. for src in sorted(glob.glob(sip_tmp_out_dir + '/*')): - dest = opj(cfg.SIPOUT, os.path.basename(src)) - if not os.path.exists(dest): + dest = Path(opj(cfg.SIPOUT, os.path.basename(src))) + if not dest.exists(): msg('%s is a new file, copying...' % os.path.basename(src)) srcTxt = processSrc(src, options.keep_hash_lines) - with textfile_open(dest, 'wt') as f: - f.write(srcTxt) + dest.write_text(srcTxt, encoding="utf-8") continue srcTxt = processSrc(src, options.keep_hash_lines) - with textfile_open(dest, 'rt') as f: - destTxt = f.read() + destTxt = dest.read_text(encoding="utf-8") if srcTxt == destTxt: pass else: msg('%s is changed, copying...' % os.path.basename(src)) - with textfile_open(dest, 'wt') as f: - f.write(srcTxt) + dest.write_text(srcTxt, encoding="utf-8") # Remove tmpdir and its contents shutil.rmtree(tmpdir) From 616f65c7d68871fd1816eff231c6bf3bc8326767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 8 Feb 2025 16:15:32 +0000 Subject: [PATCH 6/6] Use pathlib write_text for more situations in build.py --- build.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/build.py b/build.py index 3ea08e5c..af102d54 100755 --- a/build.py +++ b/build.py @@ -1330,10 +1330,7 @@ def cmd_sip(options, args): header = min(glob.glob('*.h')) sources = sorted(glob.glob('*.cpp')) del sip_pwd - with open(sbf, 'w') as f: - f.write("sources = {}\n".format(' '.join(sources))) - f.write("headers = {}\n".format(header)) - + Path(sbf).write_text(f"sources = {' '.join(sources)}\nheaders = {header}\n") classesNeedingClassInfo = { 'sip_corewxTreeCtrl.cpp' : 'wxTreeCtrl', } def processSrc(src, keepHashLines=False): @@ -2212,8 +2209,7 @@ def cmd_sdist(options, args): shutil.rmtree(opj(PDEST, 'docs'), ignore_errors=True) if options.nodoc: os.makedirs(opj(PDEST, 'docs')) - with open(opj(PDEST, 'docs', 'README.txt'), 'wt') as f: - f.write("The sphinx files and generated docs are not included in this archive.\n") + Path(PDEST, 'docs', 'README.txt').write_text("The sphinx files and generated docs are not included in this archive.\n") else: shutil.copytree('docs', opj(PDEST, 'docs'), ignore=shutil.ignore_patterns('html', 'build', '__pycache__', 'cpp'))