diff --git a/.github/workflows/download-arm64-libs.py b/.github/workflows/download-arm64-libs.py index 63e48971a..21b23cc79 100644 --- a/.github/workflows/download-arm64-libs.py +++ b/.github/workflows/download-arm64-libs.py @@ -21,11 +21,11 @@ VERSION = "{}.{}.{}".format(*sys.version_info[:3]) if sys.version_info.releaselevel == "alpha": - VERSION += "-a{}".format(sys.version_info.serial) + VERSION += f"-a{sys.version_info.serial}" if sys.version_info.releaselevel == "beta": - VERSION += "-b{}".format(sys.version_info.serial) + VERSION += f"-b{sys.version_info.serial}" if sys.version_info.releaselevel == "candidate": - VERSION += "-rc{}".format(sys.version_info.serial) + VERSION += f"-rc{sys.version_info.serial}" URL = f"https://www.nuget.org/api/v2/package/pythonarm64/{VERSION}" PATH = dest / f"pythonarm64.{VERSION}.zip" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 260d16047..fe4a75f6a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -99,7 +99,11 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - run: pip install isort pycln + - run: pip install pyupgrade pycln isort + # Ignore adodbapi until this has been manually ran and merged in adodbapi code + # _dbgscript.py is non-UTF8 on purpose, which is not supported + # TODO: Remove the --keep-percent-format flag and fix all printf-style string formatting + - run: pyupgrade --keep-percent-format --py37-plus $(git ls-files '**.py*' ':!:adodbapi/*' ':!:Pythonwin/pywin/test/_dbgscript.py') - run: pycln . --config=pycln.toml --check - run: isort . --diff --check-only - uses: psf/black@stable diff --git a/AutoDuck/Dump2HHC.py b/AutoDuck/Dump2HHC.py index d6071d31b..30c49fbd7 100644 --- a/AutoDuck/Dump2HHC.py +++ b/AutoDuck/Dump2HHC.py @@ -465,7 +465,7 @@ def main(): cats = parseCategories() for cat in cats: file = os.path.join(gen_dir, cat.dump_file) - input = open(file, "r") + input = open(file) parseTopics(cat, input) input.close() diff --git a/AutoDuck/InsertExternalOverviews.py b/AutoDuck/InsertExternalOverviews.py index c94ddef44..22d228310 100644 --- a/AutoDuck/InsertExternalOverviews.py +++ b/AutoDuck/InsertExternalOverviews.py @@ -51,7 +51,7 @@ def main(): print("Invalid args") sys.exit(1) file = sys.argv[1] - input = open(file, "r") + input = open(file) out = open(file + ".2", "w") doc = document_object.GetDocument() linksHTML = genLinksHTML(doc.links) diff --git a/AutoDuck/TOCToHHK.py b/AutoDuck/TOCToHHK.py index 235b78677..a91ec7547 100644 --- a/AutoDuck/TOCToHHK.py +++ b/AutoDuck/TOCToHHK.py @@ -11,7 +11,7 @@ def main(): file = sys.argv[1] output = sys.argv[2] - input = open(file, "r") + input = open(file) out = open(output, "w") line = input.readline() out.write( diff --git a/Pythonwin/Scintilla/src/LexGen.py b/Pythonwin/Scintilla/src/LexGen.py index 7c1d9eb0b..08a0e7854 100644 --- a/Pythonwin/Scintilla/src/LexGen.py +++ b/Pythonwin/Scintilla/src/LexGen.py @@ -135,7 +135,7 @@ def Generate(inpath, outpath, commentPrefix, eolType, *lists): # print "generate '%s' -> '%s' (comment prefix: %r, eols: %r)"\ # % (inpath, outpath, commentPrefix, eolType) try: - infile = open(inpath, "r") + infile = open(inpath) except OSError: print("Can not open", inpath) return diff --git a/Pythonwin/pywin/framework/mdi_pychecker.py b/Pythonwin/pywin/framework/mdi_pychecker.py index 06fbcc82b..2b841befc 100644 --- a/Pythonwin/pywin/framework/mdi_pychecker.py +++ b/Pythonwin/pywin/framework/mdi_pychecker.py @@ -210,7 +210,7 @@ def OnOpenDocument(self, fnm): # and starting a new grep can communicate the default parameters to the # new grep. try: - params = open(fnm, "r").read() + params = open(fnm).read() except: params = None self.setInitParams(params) @@ -386,7 +386,7 @@ def _inactive_idleHandler(self, handler, count): if self.verbose: self.GetFirstView().Append("# .." + f + "\n") win32ui.SetStatusText("Searching " + f, 0) - lines = open(f, "r").readlines() + lines = open(f).readlines() for i in range(len(lines)): line = lines[i] if self.pat.search(line) is not None: diff --git a/Pythonwin/pywin/framework/scriptutils.py b/Pythonwin/pywin/framework/scriptutils.py index c6e8e3244..97b784a56 100644 --- a/Pythonwin/pywin/framework/scriptutils.py +++ b/Pythonwin/pywin/framework/scriptutils.py @@ -101,8 +101,8 @@ def IsOnPythonPath(path): def GetPackageModuleName(fileName): """Given a filename, return (module name, new path). - eg - given "c:\a\b\c\my.py", return ("b.c.my",None) if "c:\a" is on sys.path. - If no package found, will return ("my", "c:\a\b\c") + eg - given "c:\a\b\\c\\my.py", return ("b.c.my",None) if "c:\a" is on sys.path. + If no package found, will return ("my", "c:\a\b\\c") """ path, fname = os.path.split(fileName) path = origPath = win32ui.FullPath(path) diff --git a/Pythonwin/pywin/framework/sgrepmdi.py b/Pythonwin/pywin/framework/sgrepmdi.py index 16bff7fa8..5a9260145 100644 --- a/Pythonwin/pywin/framework/sgrepmdi.py +++ b/Pythonwin/pywin/framework/sgrepmdi.py @@ -191,7 +191,7 @@ def OnOpenDocument(self, fnm): # and starting a new grep can communicate the default parameters to the # new grep. try: - params = open(fnm, "r").read() + params = open(fnm).read() except: params = None self.setInitParams(params) @@ -299,7 +299,7 @@ def SearchFile(self, handler, count): # while grep is running if os.path.isfile(f): win32ui.SetStatusText("Searching " + f, 0) - lines = open(f, "r").readlines() + lines = open(f).readlines() for i in range(len(lines)): line = lines[i] if self.pat.search(line) is not None: diff --git a/Pythonwin/pywin/tools/__init__.py b/Pythonwin/pywin/tools/__init__.py index 8b1378917..e69de29bb 100644 --- a/Pythonwin/pywin/tools/__init__.py +++ b/Pythonwin/pywin/tools/__init__.py @@ -1 +0,0 @@ - diff --git a/com/win32com/client/genpy.py b/com/win32com/client/genpy.py index 96997d3a2..f1aef3575 100644 --- a/com/win32com/client/genpy.py +++ b/com/win32com/client/genpy.py @@ -1036,7 +1036,7 @@ def open_writer(self, filename, encoding="mbcs"): # don't step on each others' toes. # Could be a classmethod one day... temp_filename = self.get_temp_filename(filename) - return open(temp_filename, "wt", encoding=encoding) + return open(temp_filename, "w", encoding=encoding) def finish_writer(self, filename, f, worked): f.close() diff --git a/com/win32com/client/makepy.py b/com/win32com/client/makepy.py index bb1bf4e07..f041062eb 100644 --- a/com/win32com/client/makepy.py +++ b/com/win32com/client/makepy.py @@ -425,7 +425,7 @@ def main(): path = os.path.dirname(outputName) if path != "" and not os.path.exists(path): os.makedirs(path) - f = open(outputName, "wt", encoding="mbcs") + f = open(outputName, "w", encoding="mbcs") else: f = None diff --git a/com/win32com/demos/iebutton.py b/com/win32com/demos/iebutton.py index 6ded24c9f..d870c21cd 100644 --- a/com/win32com/demos/iebutton.py +++ b/com/win32com/demos/iebutton.py @@ -1,5 +1,3 @@ -# -*- coding: latin-1 -*- - # PyWin32 Internet Explorer Button # # written by Leonard Ritter (paniq@gmx.net) diff --git a/com/win32com/demos/ietoolbar.py b/com/win32com/demos/ietoolbar.py index b520dcdad..22b69011b 100644 --- a/com/win32com/demos/ietoolbar.py +++ b/com/win32com/demos/ietoolbar.py @@ -1,5 +1,3 @@ -# -*- coding: latin-1 -*- - # PyWin32 Internet Explorer Toolbar # # written by Leonard Ritter (paniq@gmx.net) diff --git a/com/win32com/test/testIterators.py b/com/win32com/test/testIterators.py index 8eba364a7..bc310ce83 100644 --- a/com/win32com/test/testIterators.py +++ b/com/win32com/test/testIterators.py @@ -132,7 +132,7 @@ def suite(): and issubclass(item, unittest.TestCase) and item != _BaseTestCase ): - suite.addTest(unittest.makeSuite(item)) + suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(item)) return suite diff --git a/com/win32com/test/testall.py b/com/win32com/test/testall.py index 6ca312e34..abebaecea 100644 --- a/com/win32com/test/testall.py +++ b/com/win32com/test/testall.py @@ -218,7 +218,7 @@ def make_test_suite(test_level=1): for mod_name in unittest_modules[i]: mod, func = get_test_mod_and_func(mod_name, import_failures) if mod is None: - raise Exception("no such module '{}'".format(mod_name)) + raise Exception(f"no such module '{mod_name}'") if func is not None: test = CapturingFunctionTestCase(func, description=mod_name) else: diff --git a/com/win32com/test/util.py b/com/win32com/test/util.py index 1704f6326..3a7cdd706 100644 --- a/com/win32com/test/util.py +++ b/com/win32com/test/util.py @@ -104,7 +104,7 @@ def ExecuteShellCommand( output_name = tempfile.mktemp("win32com_test") cmd = cmd + ' > "%s" 2>&1' % output_name rc = os.system(cmd) - output = open(output_name, "r").read().strip() + output = open(output_name).read().strip() os.remove(output_name) class Failed(Exception): diff --git a/com/win32comext/authorization/demos/EditServiceSecurity.py b/com/win32comext/authorization/demos/EditServiceSecurity.py index 009f4245c..7f6233e31 100644 --- a/com/win32comext/authorization/demos/EditServiceSecurity.py +++ b/com/win32comext/authorization/demos/EditServiceSecurity.py @@ -1,7 +1,7 @@ """ Implements a permissions editor for services. Service can be specified as plain name for local machine, -or as a remote service of the form \\machinename\service +or as a remote service of the form \\machinename\\service """ import os diff --git a/com/win32comext/axdebug/Test/host.py b/com/win32comext/axdebug/Test/host.py index da99b1b2f..73ed6f31c 100644 --- a/com/win32comext/axdebug/Test/host.py +++ b/com/win32comext/axdebug/Test/host.py @@ -57,7 +57,7 @@ def _query_interface_(self, iid): def _GetCodeContainer(self): if self.codeContainer is None: try: - codeText = open(self.module.__file__, "rt").read() + codeText = open(self.module.__file__).read() except OSError as details: codeText = "# Exception opening file\n# %s" % (details) diff --git a/com/win32comext/axdebug/codecontainer.py b/com/win32comext/axdebug/codecontainer.py index be20a2d39..ac99fe9e4 100644 --- a/com/win32comext/axdebug/codecontainer.py +++ b/com/win32comext/axdebug/codecontainer.py @@ -224,7 +224,7 @@ def GetText(self): fname = self.GetFileName() if fname: try: - self.text = open(fname, "r").read() + self.text = open(fname).read() except OSError as details: self.text = "# Exception opening file\n# %s" % (repr(details)) else: diff --git a/format_all.bat b/format_all.bat index 10b8aeddb..e8b440d06 100644 --- a/format_all.bat +++ b/format_all.bat @@ -1,3 +1,11 @@ +@echo off +@REM Ignore adodbapi until this has been manually ran and merged in adodbapi code +@REM _dbgscript.py is non-UTF8 on purpose, which is not supported +for /f "delims=" %%F in ('git ls-files **.py* :!:adodbapi/* :!:Pythonwin/pywin/test/_dbgscript.py') do ( + @REM TODO: Remove the --keep-percent-format flag and fix all printf-style string formatting + pyupgrade --keep-percent-format --py37-plus %%F +) +@echo on pycln . --config=pycln.toml isort . black . diff --git a/pywin32_postinstall.py b/pywin32_postinstall.py index 1c0b396ad..101c99f43 100644 --- a/pywin32_postinstall.py +++ b/pywin32_postinstall.py @@ -692,7 +692,7 @@ def uninstall(lib_dir): def verify_destination(location): if not os.path.isdir(location): - raise argparse.ArgumentTypeError('Path "{}" does not exist!'.format(location)) + raise argparse.ArgumentTypeError(f'Path "{location}" does not exist!') return location @@ -756,7 +756,7 @@ def main(): args = parser.parse_args() if not args.quiet: - print("Parsed arguments are: {}".format(args)) + print(f"Parsed arguments are: {args}") if not args.install ^ args.remove: parser.error("You need to either choose to -install or -remove!") diff --git a/setup.py b/setup.py index 7309fc119..9e6bb37da 100644 --- a/setup.py +++ b/setup.py @@ -543,7 +543,7 @@ def _check_vc(self): # so find and add them if vcbase and not atlmfc_found: atls_lib = glob.glob( - vcbase + r"ATLMFC\lib\{}\atls.lib".format(self.plat_dir) + vcbase + fr"ATLMFC\lib\{self.plat_dir}\atls.lib" ) if atls_lib: self.library_dirs.append(os.path.dirname(atls_lib[0])) diff --git a/win32/Demos/EvtFormatMessage.py b/win32/Demos/EvtFormatMessage.py index 125438692..ecd5075a7 100644 --- a/win32/Demos/EvtFormatMessage.py +++ b/win32/Demos/EvtFormatMessage.py @@ -21,7 +21,7 @@ def main(): event, win32evtlog.EvtRenderEventValues, Context=context ) - print("Event {}".format(i)) + print(f"Event {i}") level_value, level_variant = result[win32evtlog.EvtSystemLevel] if level_variant != win32evtlog.EvtVarTypeNull: @@ -42,17 +42,17 @@ def main(): win32evtlog.EvtSystemTimeCreated ] if time_created_variant != win32evtlog.EvtVarTypeNull: - print(" Timestamp: {}".format(time_created_value.isoformat())) + print(f" Timestamp: {time_created_value.isoformat()}") computer_value, computer_variant = result[win32evtlog.EvtSystemComputer] if computer_variant != win32evtlog.EvtVarTypeNull: - print(" FQDN: {}".format(computer_value)) + print(f" FQDN: {computer_value}") provider_name_value, provider_name_variant = result[ win32evtlog.EvtSystemProviderName ] if provider_name_variant != win32evtlog.EvtVarTypeNull: - print(" Provider: {}".format(provider_name_value)) + print(f" Provider: {provider_name_value}") try: metadata = win32evtlog.EvtOpenPublisherMetadata(provider_name_value) @@ -69,7 +69,7 @@ def main(): pass else: try: - print(" Message: {}".format(message)) + print(f" Message: {message}") except UnicodeEncodeError: # Obscure error when run under subprocess.Popen(), presumably due to # not knowing the correct encoding for the console. diff --git a/win32/Lib/win32rcparser.py b/win32/Lib/win32rcparser.py index 627cea1ba..92a19e710 100644 --- a/win32/Lib/win32rcparser.py +++ b/win32/Lib/win32rcparser.py @@ -584,21 +584,21 @@ def ParseStreams(rc_file, h_file): def Parse(rc_name, h_name=None): if h_name: - h_file = open(h_name, "r") + h_file = open(h_name) else: # See if same basename as the .rc h_name = rc_name[:-2] + "h" try: - h_file = open(h_name, "r") + h_file = open(h_name) except OSError: # See if MSVC default of 'resource.h' in the same dir. h_name = os.path.join(os.path.dirname(rc_name), "resource.h") try: - h_file = open(h_name, "r") + h_file = open(h_name) except OSError: # .h files are optional anyway h_file = None - rc_file = open(rc_name, "r") + rc_file = open(rc_name) try: return ParseStreams(rc_file, h_file) finally: @@ -617,7 +617,7 @@ def GenerateFrozenResource(rc_name, output_name, h_name=None): rcp = Parse(rc_name, h_name) in_stat = os.stat(rc_name) - out = open(output_name, "wt") + out = open(output_name, "w") out.write("#%s\n" % output_name) out.write("#This is a generated file. Please edit %s instead.\n" % rc_name) out.write("__version__=%r\n" % __version__) diff --git a/win32/Lib/win32timezone.py b/win32/Lib/win32timezone.py index 442cb1f6d..ee9cfecca 100644 --- a/win32/Lib/win32timezone.py +++ b/win32/Lib/win32timezone.py @@ -1,5 +1,3 @@ -# -*- coding: UTF-8 -*- - """ win32timezone: Module for handling datetime.tzinfo time zones using the windows diff --git a/win32/scripts/VersionStamp/bulkstamp.py b/win32/scripts/VersionStamp/bulkstamp.py index 44f2a63e0..297f4adca 100644 --- a/win32/scripts/VersionStamp/bulkstamp.py +++ b/win32/scripts/VersionStamp/bulkstamp.py @@ -85,7 +85,7 @@ def load_descriptions(fname, vars): retvars = {} descriptions = {} - lines = open(fname, "r").readlines() + lines = open(fname).readlines() for i in range(len(lines)): line = lines[i].strip() diff --git a/win32/scripts/VersionStamp/vssutil.py b/win32/scripts/VersionStamp/vssutil.py index 6679ebc93..1e970d817 100644 --- a/win32/scripts/VersionStamp/vssutil.py +++ b/win32/scripts/VersionStamp/vssutil.py @@ -56,7 +56,7 @@ def SubstituteInString(inString, evalEnv): def SubstituteInFile(inName, outName, evalEnv): - inFile = open(inName, "r") + inFile = open(inName) try: outFile = open(outName, "w") try: diff --git a/win32/scripts/regsetup.py b/win32/scripts/regsetup.py index 20a4f8471..1c17736f2 100644 --- a/win32/scripts/regsetup.py +++ b/win32/scripts/regsetup.py @@ -506,9 +506,9 @@ def RegisterShellInfo(searchPaths): as well as the 2 wierd spots to locate the core Python files (eg, Python.exe, pythonXX.dll, the standard library and Win32 Extensions. -"regsetup -a myappname . .\subdir" +"regsetup -a myappname . .\\subdir" Registers a new Pythonpath entry named myappname, with "C:\\I\\AM\\HERE" and -"C:\\I\\AM\\HERE\subdir" added to the path (ie, all args are converted to +"C:\\I\\AM\\HERE\\subdir" added to the path (ie, all args are converted to absolute paths) "regsetup -c c:\\my\\python\\files" diff --git a/win32/test/test_odbc.py b/win32/test/test_odbc.py index 8cba6310f..1d2a9f1b2 100644 --- a/win32/test/test_odbc.py +++ b/win32/test/test_odbc.py @@ -206,7 +206,7 @@ def testLongBinary(self): def testRaw(self): ## Test binary data - self._test_val("rawfield", memoryview(b"\1\2\3\4\0\5\6\7\8")) + self._test_val("rawfield", memoryview(b"\1\2\3\4\0\5\6\7\\8")) def test_widechar(self): """Test a unicode character that would be mangled if bound as plain character. diff --git a/win32/test/testall.py b/win32/test/testall.py index 85adf736e..373dd212b 100644 --- a/win32/test/testall.py +++ b/win32/test/testall.py @@ -85,7 +85,7 @@ def find_exception_in_output(data): class TestRunner: def __init__(self, argv): self.argv = argv - self.__name__ = "Test Runner for cmdline {}".format(argv) + self.__name__ = f"Test Runner for cmdline {argv}" def __call__(self): import subprocess