From b9256ff26bb64a85a11defe9c817bdde08ab0560 Mon Sep 17 00:00:00 2001 From: Avasam Date: Thu, 10 Oct 2024 21:17:21 -0400 Subject: [PATCH 1/3] Update configs to use Ruff format instead of Black --- .editorconfig | 2 +- .github/workflows/main.yml | 13 +- .pre-commit-config.yaml | 6 +- adodbapi/adodbapi.py | 19 +- adodbapi/process_connect_string.py | 272 ++++++++++++++--------------- com/win32comext/adsi/demos/scp.py | 2 +- ruff.toml | 3 +- win32/Lib/win32gui_struct.py | 6 +- win32/Lib/win32pdhquery.py | 5 +- win32/test/test_win32file.py | 11 +- 10 files changed, 167 insertions(+), 172 deletions(-) diff --git a/.editorconfig b/.editorconfig index 51baf1204..6874683d6 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,7 +9,7 @@ indent_size = 4 max_line_length = 120 # Same as .clang-format [*.py] -max_line_length = 88 # Same as Black +max_line_length = 88 # Same as Ruff's default [*.md] trim_trailing_whitespace = false diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2af0d70a0..db40b4254 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -110,23 +110,22 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: - # This job only needs to target the oldest version supported by our checkers - # (black>=24.10.0 supports Python >=3.9) - python-version: "3.9" + # This job only needs to target the oldest supported version + python-version: "3.8" cache: pip cache-dependency-path: .github/workflows/main.yml - run: pip install clang-format pycln - run: pycln . --config=pycln.toml --check - uses: astral-sh/ruff-action@v1 with: - version: "0.4.5" - - uses: psf/black@stable + version: "0.4.9" + - uses: astral-sh/ruff-action@v1 with: - options: "--fast --check --diff --verbose" + version: "0.4.9" + args: "format --check" - run: | # Too many files to fit in a single command, also exclude vendored Scintilla and MAPIStubLibrary clang-format --Werror --dry-run $(git ls-files '*.cpp') clang-format --Werror --dry-run $(git ls-files '*.h' ':!:Pythonwin/Scintilla/' ':!:com/win32comext/mapi/src/MAPIStubLibrary/') - shell: powershell mypy: runs-on: windows-2019 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a89a958b7..566983fae 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -29,11 +29,7 @@ repos: hooks: - id: ruff # Run the linter. args: [--fix] - - repo: https://github.com/psf/black-pre-commit-mirror - rev: 24.4.2 - hooks: - - id: black - verbose: true + - id: ruff-format - repo: https://github.com/pre-commit/mirrors-clang-format rev: v18.1.5 hooks: diff --git a/adodbapi/adodbapi.py b/adodbapi/adodbapi.py index 4e85bc525..b63b829d8 100644 --- a/adodbapi/adodbapi.py +++ b/adodbapi/adodbapi.py @@ -395,9 +395,7 @@ def _rollback(self): # If attributes has adXactAbortRetaining it performs retaining aborts that is, # calling RollbackTrans automatically starts a new transaction. Not all providers support this. # If not, we will have to start a new transaction by this command: - if ( - not self.transaction_level - ): # if self.transaction_level == 0 or self.transaction_level is None: + if not self.transaction_level: self.transaction_level = self.connector.BeginTrans() except Exception as e: self._raiseConnectionError(api.ProgrammingError, e) @@ -634,9 +632,8 @@ def _makeDescriptionFromRS(self): if self.rs.EOF or self.rs.BOF: display_size = None else: - display_size = ( - f.ActualSize - ) # TODO: Is this the correct defintion according to the DB API 2 Spec ? + # TODO: Is this the correct defintion according to the DB API 2 Spec ? + display_size = f.ActualSize null_ok = bool(f.Attributes & adc.adFldMayBeNull) # v2.1 Cole desc.append( ( @@ -774,9 +771,8 @@ def get_returned_parameters(self): after the last recordset has been read. In that case, you must coll nextset() until it returns None, then call this method to get your returned information.""" - retLst = ( - [] - ) # store procedures may return altered parameters, including an added "return value" item + # store procedures may return altered parameters, including an added "return value" item + retLst = [] for p in tuple(self.cmd.Parameters): if verbose > 2: print( @@ -907,9 +903,8 @@ def _buildADOparameterList(self, parameters, sproc=False): ) i += 1 else: # -- build own parameter list - if ( - self._parameter_names - ): # we expect a dictionary of parameters, this is the list of expected names + # we expect a dictionary of parameters, this is the list of expected names + if self._parameter_names: for parm_name in self._parameter_names: elem = parameters[parm_name] adotype = api.pyTypeToADOType(elem) diff --git a/adodbapi/process_connect_string.py b/adodbapi/process_connect_string.py index d8b29f280..a134ad656 100644 --- a/adodbapi/process_connect_string.py +++ b/adodbapi/process_connect_string.py @@ -1,137 +1,135 @@ -""" a clumsy attempt at a macro language to let the programmer execute code on the server (ex: determine 64bit)""" - -from . import is64bit - - -def macro_call(macro_name, args, kwargs): - """allow the programmer to perform limited processing on the server by passing macro names and args - - :new_key - the key name the macro will create - :args[0] - macro name - :args[1:] - any arguments - :code - the value of the keyword item - :kwargs - the connection keyword dictionary. ??key has been removed - --> the value to put in for kwargs['name'] = value - """ - if isinstance(args, (str, str)): - args = [ - args - ] # the user forgot to pass a sequence, so make a string into args[0] - new_key = args[0] - try: - if macro_name == "is64bit": - if is64bit.Python(): # if on 64 bit Python - return new_key, args[1] # return first argument - else: - try: - return new_key, args[2] # else return second argument (if defined) - except IndexError: - return new_key, "" # else return blank - - elif ( - macro_name == "getuser" - ): # get the name of the user the server is logged in under - if not new_key in kwargs: - import getpass - - return new_key, getpass.getuser() - - elif macro_name == "getnode": # get the name of the computer running the server - import platform - - try: - return new_key, args[1] % platform.node() - except IndexError: - return new_key, platform.node() - - elif macro_name == "getenv": # expand the server's environment variable args[1] - try: - dflt = args[2] # if not found, default from args[2] - except IndexError: # or blank - dflt = "" - return new_key, os.environ.get(args[1], dflt) - - elif macro_name == "auto_security": - if ( - not "user" in kwargs or not kwargs["user"] - ): # missing, blank, or Null username - return new_key, "Integrated Security=SSPI" - return new_key, "User ID=%(user)s; Password=%(password)s" % kwargs - - elif ( - macro_name == "find_temp_test_path" - ): # helper function for testing ado operation -- undocumented - import os - import tempfile - - return new_key, os.path.join( - tempfile.gettempdir(), "adodbapi_test", args[1] - ) - - raise ValueError(f"Unknown connect string macro={macro_name}") - except: - raise ValueError(f"Error in macro processing {macro_name} {args!r}") - - -def process( - args, kwargs, expand_macros=False -): # --> connection string with keyword arguments processed. - """attempts to inject arguments into a connection string using Python "%" operator for strings - - co: adodbapi connection object - args: positional parameters from the .connect() call - kvargs: keyword arguments from the .connect() call - """ - try: - dsn = args[0] - except IndexError: - dsn = None - if isinstance( - dsn, dict - ): # as a convenience the first argument may be django settings - kwargs.update(dsn) - elif ( - dsn - ): # the connection string is passed to the connection as part of the keyword dictionary - kwargs["connection_string"] = dsn - try: - a1 = args[1] - except IndexError: - a1 = None - # historically, the second positional argument might be a timeout value - if isinstance(a1, int): - kwargs["timeout"] = a1 - # if the second positional argument is a string, then it is user - elif isinstance(a1, str): - kwargs["user"] = a1 - # if the second positional argument is a dictionary, use it as keyword arguments, too - elif isinstance(a1, dict): - kwargs.update(a1) - try: - kwargs["password"] = args[2] # the third positional argument is password - kwargs["host"] = args[3] # the fourth positional argument is host name - kwargs["database"] = args[4] # the fifth positional argument is database name - except IndexError: - pass - - # make sure connection string is defined somehow - if not "connection_string" in kwargs: - try: # perhaps 'dsn' was defined - kwargs["connection_string"] = kwargs["dsn"] - except KeyError: - try: # as a last effort, use the "host" keyword - kwargs["connection_string"] = kwargs["host"] - except KeyError: - raise TypeError("Must define 'connection_string' for ado connections") - if expand_macros: - for kwarg in list(kwargs.keys()): - if kwarg.startswith("macro_"): # If a key defines a macro - macro_name = kwarg[6:] # name without the "macro_" - macro_code = kwargs.pop( - kwarg - ) # we remove the macro_key and get the code to execute - new_key, rslt = macro_call( - macro_name, macro_code, kwargs - ) # run the code in the local context - kwargs[new_key] = rslt # put the result back in the keywords dict - return kwargs +""" a clumsy attempt at a macro language to let the programmer execute code on the server (ex: determine 64bit)""" + +from . import is64bit + + +def macro_call(macro_name, args, kwargs): + """allow the programmer to perform limited processing on the server by passing macro names and args + + :new_key - the key name the macro will create + :args[0] - macro name + :args[1:] - any arguments + :code - the value of the keyword item + :kwargs - the connection keyword dictionary. ??key has been removed + --> the value to put in for kwargs['name'] = value + """ + if isinstance(args, (str, str)): + args = [ + args + ] # the user forgot to pass a sequence, so make a string into args[0] + new_key = args[0] + try: + if macro_name == "is64bit": + if is64bit.Python(): # if on 64 bit Python + return new_key, args[1] # return first argument + else: + try: + return new_key, args[2] # else return second argument (if defined) + except IndexError: + return new_key, "" # else return blank + + elif ( + macro_name == "getuser" + ): # get the name of the user the server is logged in under + if not new_key in kwargs: + import getpass + + return new_key, getpass.getuser() + + elif macro_name == "getnode": # get the name of the computer running the server + import platform + + try: + return new_key, args[1] % platform.node() + except IndexError: + return new_key, platform.node() + + elif macro_name == "getenv": # expand the server's environment variable args[1] + try: + dflt = args[2] # if not found, default from args[2] + except IndexError: # or blank + dflt = "" + return new_key, os.environ.get(args[1], dflt) + + elif macro_name == "auto_security": + if ( + not "user" in kwargs or not kwargs["user"] + ): # missing, blank, or Null username + return new_key, "Integrated Security=SSPI" + return new_key, "User ID=%(user)s; Password=%(password)s" % kwargs + + elif ( + macro_name == "find_temp_test_path" + ): # helper function for testing ado operation -- undocumented + import os + import tempfile + + return new_key, os.path.join( + tempfile.gettempdir(), "adodbapi_test", args[1] + ) + + raise ValueError(f"Unknown connect string macro={macro_name}") + except: + raise ValueError(f"Error in macro processing {macro_name} {args!r}") + + +def process( + args, kwargs, expand_macros=False +): # --> connection string with keyword arguments processed. + """attempts to inject arguments into a connection string using Python "%" operator for strings + + co: adodbapi connection object + args: positional parameters from the .connect() call + kvargs: keyword arguments from the .connect() call + """ + try: + dsn = args[0] + except IndexError: + dsn = None + # as a convenience the first argument may be django settings + if isinstance(dsn, dict): + kwargs.update(dsn) + # the connection string is passed to the connection as part of the keyword dictionary + elif dsn: + kwargs["connection_string"] = dsn + try: + a1 = args[1] + except IndexError: + a1 = None + # historically, the second positional argument might be a timeout value + if isinstance(a1, int): + kwargs["timeout"] = a1 + # if the second positional argument is a string, then it is user + elif isinstance(a1, str): + kwargs["user"] = a1 + # if the second positional argument is a dictionary, use it as keyword arguments, too + elif isinstance(a1, dict): + kwargs.update(a1) + try: + kwargs["password"] = args[2] # the third positional argument is password + kwargs["host"] = args[3] # the fourth positional argument is host name + kwargs["database"] = args[4] # the fifth positional argument is database name + except IndexError: + pass + + # make sure connection string is defined somehow + if not "connection_string" in kwargs: + try: # perhaps 'dsn' was defined + kwargs["connection_string"] = kwargs["dsn"] + except KeyError: + try: # as a last effort, use the "host" keyword + kwargs["connection_string"] = kwargs["host"] + except KeyError: + raise TypeError("Must define 'connection_string' for ado connections") + if expand_macros: + for kwarg in list(kwargs.keys()): + if kwarg.startswith("macro_"): # If a key defines a macro + macro_name = kwarg[6:] # name without the "macro_" + macro_code = kwargs.pop( + kwarg + ) # we remove the macro_key and get the code to execute + new_key, rslt = macro_call( + macro_name, macro_code, kwargs + ) # run the code in the local context + kwargs[new_key] = rslt # put the result back in the keywords dict + return kwargs diff --git a/com/win32comext/adsi/demos/scp.py b/com/win32comext/adsi/demos/scp.py index b2ff016ec..dc5f831e8 100644 --- a/com/win32comext/adsi/demos/scp.py +++ b/com/win32comext/adsi/demos/scp.py @@ -419,7 +419,7 @@ def main(): "--test", action="store_true", help="Execute a mini-test suite, providing defaults for most options and args", - ), + ) parser.add_option( "", diff --git a/ruff.toml b/ruff.toml index eab7fcce1..6d75257db 100644 --- a/ruff.toml +++ b/ruff.toml @@ -1,4 +1,6 @@ target-version = "py38" # Target the oldest supported version in editors and default CLI +# This file is not UTF-8 +extend-exclude = ["Pythonwin/pywin/test/_dbgscript.py"] [lint] select = [ @@ -15,7 +17,6 @@ select = [ "FLY", # static-join-to-f-string "G", # flake8-logging-format # Note, we still want to allow multiline ISC - "ISC001", # single-line-implicit-string-concatenation "UP025", # Remove unicode literals from strings "UP030", # Use implicit references for positional format fields # TODO: Still lots of manual fixes needed diff --git a/win32/Lib/win32gui_struct.py b/win32/Lib/win32gui_struct.py index 41ef815fd..a4b7a4f4c 100644 --- a/win32/Lib/win32gui_struct.py +++ b/win32/Lib/win32gui_struct.py @@ -463,7 +463,7 @@ def EmptyTVITEM(hitem, mask=None, text_buf_size=512): else: text_addr = text_buf_size = 0 buf = struct.pack( - _tvitem_fmt, mask, hitem, 0, 0, text_addr, text_buf_size, 0, 0, 0, 0 # text + _tvitem_fmt, mask, hitem, 0, 0, text_addr, text_buf_size, 0, 0, 0, 0 ) return array.array("b", buf), extra @@ -758,7 +758,7 @@ def PackLVCOLUMN(fmt=None, cx=None, text=None, subItem=None, image=None, order=N text_addr, _ = text_buffer.buffer_info() text_len = len(text) buf = struct.pack( - _lvcolumn_fmt, mask, fmt, cx, text_addr, text_len, subItem, image, order # text + _lvcolumn_fmt, mask, fmt, cx, text_addr, text_len, subItem, image, order ) return array.array("b", buf), extra @@ -809,7 +809,7 @@ def EmptyLVCOLUMN(mask=None, text_buf_size=512): else: text_addr = text_buf_size = 0 buf = struct.pack( - _lvcolumn_fmt, mask, 0, 0, text_addr, text_buf_size, 0, 0, 0 # text + _lvcolumn_fmt, mask, 0, 0, text_addr, text_buf_size, 0, 0, 0 ) return array.array("b", buf), extra diff --git a/win32/Lib/win32pdhquery.py b/win32/Lib/win32pdhquery.py index 3f458e0a8..3e51b77b9 100644 --- a/win32/Lib/win32pdhquery.py +++ b/win32/Lib/win32pdhquery.py @@ -331,9 +331,8 @@ def collectdataslave(self, format=win32pdh.PDH_FMT_LONG): if not ok: temp.append(-1) # a better way to signal failure??? return temp - except ( - win32api.error - ): # will happen if, for instance, no counters are part of the query and we attempt to collect data for it. + # will happen if, for instance, no counters are part of the query and we attempt to collect data for it. + except win32api.error: return [-1] * len(self.counters) # pickle functions diff --git a/win32/test/test_win32file.py b/win32/test/test_win32file.py index 4763f9289..12ba8c31d 100644 --- a/win32/test/test_win32file.py +++ b/win32/test/test_win32file.py @@ -641,7 +641,10 @@ def _watcherThread(self, dn, dh, changes): try: print("waiting", dh) changes = win32file.ReadDirectoryChangesW( - dh, 8192, False, flags # sub-tree + dh, + 8192, + False, # sub-tree + flags, ) print("got", changes) except: @@ -655,7 +658,11 @@ def _watcherThreadOverlapped(self, dn, dh, changes): overlapped.hEvent = win32event.CreateEvent(None, 0, 0, None) while 1: win32file.ReadDirectoryChangesW( - dh, buf, False, flags, overlapped # sub-tree + dh, + buf, + False, # sub-tree + flags, + overlapped, ) # Wait for our event, or for 5 seconds. rc = win32event.WaitForSingleObject(overlapped.hEvent, 5000) From b74bfdca97238735adbd1b20d7245cca7070900f Mon Sep 17 00:00:00 2001 From: Avasam Date: Mon, 14 Oct 2024 13:18:52 -0400 Subject: [PATCH 2/3] Run ruff format --- AutoDuck/Dump2HHC.py | 28 ++--- Pythonwin/pywin/dialogs/list.py | 19 ++-- Pythonwin/pywin/framework/app.py | 3 +- Pythonwin/pywin/framework/scriptutils.py | 4 +- Pythonwin/pywin/framework/stdin.py | 1 + Pythonwin/pywin/mfc/activex.py | 3 +- adodbapi/examples/db_print.py | 2 +- adodbapi/examples/db_table_names.py | 2 +- adodbapi/process_connect_string.py | 2 +- adodbapi/test/adodbapitest.py | 33 +++--- adodbapi/test/dbapi20.py | 14 +-- adodbapi/test/setuptestframework.py | 1 + com/win32com/client/combrowse.py | 27 +++-- com/win32com/client/dynamic.py | 7 +- com/win32com/client/genpy.py | 4 +- com/win32com/client/makepy.py | 7 +- com/win32com/client/selecttlb.py | 3 +- com/win32com/makegw/makegw.py | 102 ++++++++---------- com/win32com/makegw/makegwenum.py | 8 +- com/win32com/makegw/makegwparse.py | 14 +-- com/win32com/olectl.py | 2 +- com/win32com/server/connect.py | 2 +- com/win32com/server/exception.py | 14 +-- com/win32com/servers/interp.py | 14 +-- com/win32com/test/errorSemantics.py | 6 +- com/win32com/test/testExchange.py | 1 - com/win32com/test/testvb.py | 15 +-- com/win32com/util.py | 2 +- com/win32comext/axdebug/adb.py | 3 +- com/win32comext/axdebug/contexts.py | 4 +- com/win32comext/axdebug/documents.py | 3 +- com/win32comext/axdebug/dump.py | 4 +- com/win32comext/axscript/client/error.py | 4 +- com/win32comext/axscript/client/framework.py | 8 +- .../axscript/client/scriptdispatch.py | 6 +- isapi/samples/redirector_with_filter.py | 1 + isapi/simple.py | 1 + isapi/threaded_extension.py | 1 + setup.py | 68 +++--------- win32/Demos/security/GetTokenInformation.py | 4 +- win32/Demos/win32ts_logoff_disconnected.py | 2 +- win32/Lib/win32evtlogutil.py | 3 +- win32/Lib/win32gui_struct.py | 4 +- win32/Lib/win32rcparser.py | 1 + win32/scripts/regsetup.py | 7 +- win32/test/test_win32clipboard.py | 5 +- win32/test/test_win32cred.py | 1 - 47 files changed, 202 insertions(+), 268 deletions(-) diff --git a/AutoDuck/Dump2HHC.py b/AutoDuck/Dump2HHC.py index 343bdbca1..32c728c9d 100644 --- a/AutoDuck/Dump2HHC.py +++ b/AutoDuck/Dump2HHC.py @@ -293,9 +293,7 @@ def _genItemsFromDict(dict, cat, output, target, do_children=1): - """.format( - **locals() - ) + """.format(**locals()) ) if not do_children: continue @@ -339,9 +337,7 @@ def genTOC(cats, output, title, target):