diff --git a/.editorconfig b/.editorconfig
index 0f4d99d0f..e55d13f9d 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/.git-blame-ignore-revs b/.git-blame-ignore-revs
index 4816d046a..9309054aa 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -13,3 +13,6 @@
# 2024-05-28 formatted c++ source with clang-format
637448f8252ab142eedd539ddf9b08259b73eecc
+
+# 2024-10-14 formatted Python source with Ruff format
+2b5191d8fc6f1d1fbde01481b49278c1957ef8f1
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 6356b0e36..2275d01cc 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -110,25 +110,24 @@ 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==18.* 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' ':!:com/win32comext/mapi/src/MAPIStubLibrary/')
if ($LastExitCode -ne 0) { exit $LastExitCode }
clang-format --Werror --dry-run $(git ls-files '*.h' ':!:Pythonwin/Scintilla/' ':!:com/win32comext/mapi/src/MAPIStubLibrary/')
if ($LastExitCode -ne 0) { exit $LastExitCode }
- shell: powershell
mypy:
runs-on: windows-2019
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index aa634c7f2..a2f2eff96 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.8
hooks:
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):
-""".format(
- **locals()
- )
+""".format(**locals())
)
for cat in cats:
@@ -355,9 +351,7 @@ def genTOC(cats, output, title, target):
- """.format(
- **locals()
- )
+ """.format(**locals())
)
# Next write the overviews for this category
output.write(
@@ -368,9 +362,7 @@ def genTOC(cats, output, title, target):
- """.format(
- **locals()
- )
+ """.format(**locals())
)
_genItemsFromDict(cat.overviewTopics, cat, output, target)
_genItemsFromDict(cat.extOverviewTopics, cat, output, target)
@@ -387,9 +379,7 @@ def genTOC(cats, output, title, target):
-""".format(
- **locals()
- )
+""".format(**locals())
)
_genItemsFromDict(cat.modules, cat, output, target)
output.write(
@@ -404,9 +394,7 @@ def genTOC(cats, output, title, target):
- """.format(
- **locals()
- )
+ """.format(**locals())
)
# Don't show 'children' for objects - params etc don't need their own child nodes!
_genItemsFromDict(cat.objects, cat, output, target, do_children=0)
@@ -423,9 +411,7 @@ def genTOC(cats, output, title, target):
-""".format(
- **locals()
- )
+""".format(**locals())
)
_genItemsFromDict(cat.constants, cat, output, target)
output.write(
diff --git a/CHANGES.txt b/CHANGES.txt
index d8978afd5..82cf59213 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -15,7 +15,8 @@ Coming in build 309, as yet unreleased
--------------------------------------
* Dropped support for Python 3.7 (#2207, @Avasam)
-* Implement record pointers as [in, out] method parameters of a Dispatch Interface (#2310)
+* Implement the creation of SAFEARRAY(VT_RECORD) from a sequence of COM Records (#2317, @geppi)
+* Implement record pointers as [in, out] method parameters of a Dispatch Interface (#2304, #2310, @geppi)
* Fix memory leak converting to PyObject from some SAFEARRAY elements (#2316)
* Fix bug where makepy support was unnecessarily generated (#2354, #2353, @geppi)
* Fail sooner on invalid `win32timezone.TimeZoneInfo` creation (#2338, @Avasam)
diff --git a/Pythonwin/pywin/dialogs/list.py b/Pythonwin/pywin/dialogs/list.py
index 4e1877955..377a7cade 100644
--- a/Pythonwin/pywin/dialogs/list.py
+++ b/Pythonwin/pywin/dialogs/list.py
@@ -44,14 +44,17 @@ def OnListClick(self, id, code):
return 1
def OnListItemChange(self, std, extra):
- (hwndFrom, idFrom, code), (
- itemNotify,
- sub,
- newState,
- oldState,
- change,
- point,
- lparam,
+ (
+ (hwndFrom, idFrom, code),
+ (
+ itemNotify,
+ sub,
+ newState,
+ oldState,
+ change,
+ point,
+ lparam,
+ ),
) = (std, extra)
oldSel = (oldState & commctrl.LVIS_SELECTED) != 0
newSel = (newState & commctrl.LVIS_SELECTED) != 0
diff --git a/Pythonwin/pywin/framework/app.py b/Pythonwin/pywin/framework/app.py
index 4e0f09b94..9899e62fa 100644
--- a/Pythonwin/pywin/framework/app.py
+++ b/Pythonwin/pywin/framework/app.py
@@ -2,7 +2,8 @@
# The application is responsible for managing the main frame window.
#
# We also grab the FileOpen command, to invoke our Python editor
-" The PythonWin application code. Manages most aspects of MDI, etc "
+"The PythonWin application code. Manages most aspects of MDI, etc"
+
from __future__ import annotations
import os
diff --git a/Pythonwin/pywin/framework/scriptutils.py b/Pythonwin/pywin/framework/scriptutils.py
index fe57113dd..32811190b 100644
--- a/Pythonwin/pywin/framework/scriptutils.py
+++ b/Pythonwin/pywin/framework/scriptutils.py
@@ -27,9 +27,7 @@
debugging_options = """No debugging
Step-through in the debugger
Run in the debugger
-Post-Mortem of unhandled exceptions""".split(
- "\n"
-)
+Post-Mortem of unhandled exceptions""".split("\n")
byte_cr = b"\r"
byte_lf = b"\n"
diff --git a/Pythonwin/pywin/framework/stdin.py b/Pythonwin/pywin/framework/stdin.py
index 1614fbe91..b7d71dc19 100644
--- a/Pythonwin/pywin/framework/stdin.py
+++ b/Pythonwin/pywin/framework/stdin.py
@@ -16,6 +16,7 @@
import sys
sys.stdin = sys.stdin.real_file
"""
+
import sys
get_input_line = input
diff --git a/Pythonwin/pywin/mfc/activex.py b/Pythonwin/pywin/mfc/activex.py
index f3d9939a4..3d0207aca 100644
--- a/Pythonwin/pywin/mfc/activex.py
+++ b/Pythonwin/pywin/mfc/activex.py
@@ -1,5 +1,4 @@
-"""Support for ActiveX control hosting in Pythonwin.
-"""
+"""Support for ActiveX control hosting in Pythonwin."""
import win32ui
import win32uiole
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/examples/db_print.py b/adodbapi/examples/db_print.py
index c0eb83ee4..fc86a8b3c 100644
--- a/adodbapi/examples/db_print.py
+++ b/adodbapi/examples/db_print.py
@@ -1,4 +1,4 @@
-""" db_print.py -- a simple demo for ADO database reads."""
+"""db_print.py -- a simple demo for ADO database reads."""
import sys
diff --git a/adodbapi/examples/db_table_names.py b/adodbapi/examples/db_table_names.py
index 907bdb85e..17ff58349 100644
--- a/adodbapi/examples/db_table_names.py
+++ b/adodbapi/examples/db_table_names.py
@@ -1,4 +1,4 @@
-""" db_table_names.py -- a simple demo for ADO database table listing."""
+"""db_table_names.py -- a simple demo for ADO database table listing."""
import sys
diff --git a/adodbapi/process_connect_string.py b/adodbapi/process_connect_string.py
index d8b29f280..b1d4e4e93 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/adodbapi/test/adodbapitest.py b/adodbapi/test/adodbapitest.py
index 1b50e595f..dd8e9196d 100644
--- a/adodbapi/test/adodbapitest.py
+++ b/adodbapi/test/adodbapitest.py
@@ -1,4 +1,4 @@
-""" Unit tests version 2.6.1.0 for adodbapi"""
+"""Unit tests version 2.6.1.0 for adodbapi"""
"""
adodbapi - A python DB API 2.0 interface to Microsoft ADO
@@ -325,15 +325,16 @@ def helpTestDataType(
rs = crsr.fetchone()
if allowedReturnValues:
allowedTypes = tuple([type(aRV) for aRV in allowedReturnValues])
- assert isinstance(
- rs[0], allowedTypes
- ), 'result type "%s" must be one of %s' % (type(rs[0]), allowedTypes)
+ assert isinstance(rs[0], allowedTypes), (
+ 'result type "%s" must be one of %s' % (type(rs[0]), allowedTypes)
+ )
else:
- assert isinstance(
- rs[0], type(pyData)
- ), 'result type "%s" must be instance of %s' % (
- type(rs[0]),
- type(pyData),
+ assert isinstance(rs[0], type(pyData)), (
+ 'result type "%s" must be instance of %s'
+ % (
+ type(rs[0]),
+ type(pyData),
+ )
)
if compareAlmostEqual and DBAPIDataTypeString == "DATETIME":
@@ -343,9 +344,9 @@ def helpTestDataType(
elif compareAlmostEqual:
s = float(pyData)
v = float(rs[0])
- assert (
- abs(v - s) / s < 0.00001
- ), "Values not almost equal recvd=%s, expected=%f" % (rs[0], s)
+ assert abs(v - s) / s < 0.00001, (
+ "Values not almost equal recvd=%s, expected=%f" % (rs[0], s)
+ )
else:
if allowedReturnValues:
ok = False
@@ -487,7 +488,7 @@ def testDataTypeDate(self):
)
def testDataTypeBinary(self):
- binfld = b"\x07\x00\xE2\x40*"
+ binfld = b"\x07\x00\xe2\x40*"
arv = [binfld, adodbapi.Binary(binfld), bytes(binfld)]
if self.getEngine() == "PostgreSQL":
self.helpTestDataType(
@@ -692,9 +693,9 @@ def testRowIterator(self):
rec = crsr.fetchone()
# check that stepping through an emulated row works
for j in range(len(inParam)):
- assert (
- rec[j] == inParam[j]
- ), 'returned value:"%s" != test value:"%s"' % (rec[j], inParam[j])
+ assert rec[j] == inParam[j], (
+ 'returned value:"%s" != test value:"%s"' % (rec[j], inParam[j])
+ )
# check that we can get a complete tuple from a row
assert (
tuple(rec) == inParam
diff --git a/adodbapi/test/dbapi20.py b/adodbapi/test/dbapi20.py
index 5639e4c3c..373b984d6 100644
--- a/adodbapi/test/dbapi20.py
+++ b/adodbapi/test/dbapi20.py
@@ -1,14 +1,14 @@
#!/usr/bin/env python
-""" Python DB API 2.0 driver compliance unit test suite.
+"""Python DB API 2.0 driver compliance unit test suite.
- This software is Public Domain and may be used without restrictions.
+ This software is Public Domain and may be used without restrictions.
- "Now we have booze and barflies entering the discussion, plus rumours of
- DBAs on drugs... and I won't tell you what flashes through my mind each
- time I read the subject line with 'Anal Compliance' in it. All around
- this is turning out to be a thoroughly unwholesome unit test."
+"Now we have booze and barflies entering the discussion, plus rumours of
+ DBAs on drugs... and I won't tell you what flashes through my mind each
+ time I read the subject line with 'Anal Compliance' in it. All around
+ this is turning out to be a thoroughly unwholesome unit test."
- -- Ian Bicking
+ -- Ian Bicking
"""
__version__ = "$Revision: 1.15.0 $"[11:-2]
diff --git a/adodbapi/test/setuptestframework.py b/adodbapi/test/setuptestframework.py
index 65b99e990..e09549421 100644
--- a/adodbapi/test/setuptestframework.py
+++ b/adodbapi/test/setuptestframework.py
@@ -1,6 +1,7 @@
#!/usr/bin/python2
# Configure this in order to run the testcases.
"setuptestframework.py v 2.6.0.8"
+
import os
import shutil
import tempfile
diff --git a/com/TestSources/PyCOMTest/PyCOMImpl.cpp b/com/TestSources/PyCOMTest/PyCOMImpl.cpp
index d58c00f99..6ba0af0c4 100644
--- a/com/TestSources/PyCOMTest/PyCOMImpl.cpp
+++ b/com/TestSources/PyCOMTest/PyCOMImpl.cpp
@@ -626,6 +626,27 @@ HRESULT CPyCOMTest::ModifyStruct(TestStruct1 *prec)
return S_OK;
}
+HRESULT CPyCOMTest::VerifyArrayOfStructs(TestStruct2 *prec, VARIANT_BOOL *is_ok)
+{
+ long i;
+ TestStruct1 *pdata = NULL;
+ HRESULT hr;
+
+ hr = SafeArrayAccessData(prec->array_of_records, reinterpret_cast(&pdata));
+ if (FAILED(hr)) {
+ return E_FAIL;
+ }
+ *is_ok = VARIANT_TRUE;
+ for (i = 0; i < prec->rec_count; i++)
+ {
+ if (_wcsicmp(pdata[i].str_value, L"This is record number") != 0 || pdata[i].int_value != i + 1) {
+ *is_ok = VARIANT_FALSE;
+ break;
+ }
+ }
+ return S_OK;
+}
+
HRESULT CPyCOMTest::DoubleString(BSTR in, BSTR *out)
{
*out = SysAllocStringLen(NULL, SysStringLen(in) * 2);
diff --git a/com/TestSources/PyCOMTest/PyCOMImpl.h b/com/TestSources/PyCOMTest/PyCOMImpl.h
index 50eb8dd0d..7b1f83c2b 100644
--- a/com/TestSources/PyCOMTest/PyCOMImpl.h
+++ b/com/TestSources/PyCOMTest/PyCOMImpl.h
@@ -120,6 +120,7 @@ class CPyCOMTest : public IDispatchImplowner);
else if (V_VT(&vret) == (VT_BYREF | VT_ARRAY | VT_RECORD)) {
SAFEARRAY *psa = *V_ARRAYREF(&vret);
- int d = SafeArrayGetDim(psa);
- if (sub_data == NULL)
- return PyErr_Format(PyExc_RuntimeError, "Did not get a buffer for the array!");
if (SafeArrayGetDim(psa) != 1)
return PyErr_Format(PyExc_TypeError, "Only support single dimensional arrays of records");
IRecordInfo *sub = NULL;
@@ -526,7 +523,13 @@ PyObject *PyRecord::getattro(PyObject *self, PyObject *obname)
ret_tuple = PyTuple_New(nelems);
if (ret_tuple == NULL)
goto array_end;
- this_data = (BYTE *)sub_data;
+ // We're dealing here with a Record field that is a SAFEARRAY of Records.
+ // Therefore the VARIANT that was returned by the call to 'pyrec->pri->GetFieldNoCopy'
+ // does contain a reference to the SAFEARRAY of Records, i.e. the actual data of the
+ // Record elements of this SAFEARRAY is referenced by the 'pvData' field of the SAFEARRAY.
+ // In this particular case the implementation of 'GetFieldNoCopy' returns a NULL pointer
+ // in the last parameter, i.e. 'sub_data == NULL'.
+ this_data = (BYTE *)psa->pvData;
for (i = 0; i < nelems; i++) {
PyTuple_SET_ITEM(ret_tuple, i, new PyRecord(sub, this_data, pyrec->owner));
this_data += element_size;
diff --git a/com/win32com/src/oleargs.cpp b/com/win32com/src/oleargs.cpp
index 0dac5453b..f9441e6fd 100644
--- a/com/win32com/src/oleargs.cpp
+++ b/com/win32com/src/oleargs.cpp
@@ -4,6 +4,7 @@
#include "stdafx.h"
#include "PythonCOM.h"
+#include "PyRecord.h"
extern PyObject *PyObject_FromRecordInfo(IRecordInfo *, void *, ULONG);
extern PyObject *PyObject_FromSAFEARRAYRecordInfo(SAFEARRAY *psa);
@@ -278,9 +279,23 @@ BOOL PyCom_VariantFromPyObject(PyObject *obj, VARIANT *var)
// So make sure this check is after anything else which qualifies.
else if (PySequence_Check(obj)) {
V_ARRAY(var) = NULL; // not a valid, existing array.
- if (!PyCom_SAFEARRAYFromPyObject(obj, &V_ARRAY(var)))
- return FALSE;
- V_VT(var) = VT_ARRAY | VT_VARIANT;
+ BOOL is_record_item = false;
+ if (PyObject_Length(obj) > 0) {
+ PyObject *obItemCheck = PySequence_GetItem(obj, 0);
+ is_record_item = PyRecord_Check(obItemCheck);
+ }
+ // If the sequence elements are PyRecord objects we do NOT package
+ // them as VARIANT elements but put them directly into the SAFEARRAY.
+ if (is_record_item) {
+ if (!PyCom_SAFEARRAYFromPyObject(obj, &V_ARRAY(var), VT_RECORD))
+ return FALSE;
+ V_VT(var) = VT_ARRAY | VT_RECORD;
+ }
+ else {
+ if (!PyCom_SAFEARRAYFromPyObject(obj, &V_ARRAY(var)))
+ return FALSE;
+ V_VT(var) = VT_ARRAY | VT_VARIANT;
+ }
}
else if (PyRecord_Check(obj)) {
if (!PyObject_AsVARIANTRecordInfo(obj, var))
@@ -554,6 +569,9 @@ static BOOL PyCom_SAFEARRAYFromPyObjectBuildDimension(PyObject *obj, SAFEARRAY *
helper.m_reqdType = vt;
ok = helper.MakeObjToVariant(item, &element);
switch (vt) {
+ case VT_RECORD:
+ pvData = V_RECORD(&element);
+ break;
case VT_DISPATCH:
pvData = V_DISPATCH(&element);
break;
@@ -759,7 +777,14 @@ static BOOL PyCom_SAFEARRAYFromPyObjectEx(PyObject *obj, SAFEARRAY **ppSA, bool
if (bAllocNewArray) {
// OK - Finally can create the array...
- *ppSA = SafeArrayCreate(vt, cDims, pBounds);
+ if (vt == VT_RECORD) {
+ // SAFEARRAYS of UDTs need a special treatment.
+ obItemCheck = PySequence_GetItem(obj, 0);
+ PyRecord *pyrec = (PyRecord *)obItemCheck;
+ *ppSA = SafeArrayCreateEx(vt, cDims, pBounds, pyrec->pri);
+ }
+ else
+ *ppSA = SafeArrayCreate(vt, cDims, pBounds);
if (*ppSA == NULL) {
delete[] pBounds;
PyErr_SetString(PyExc_MemoryError, "CreatingSafeArray");
diff --git a/com/win32com/test/errorSemantics.py b/com/win32com/test/errorSemantics.py
index 843395c41..fe5045cc8 100644
--- a/com/win32com/test/errorSemantics.py
+++ b/com/win32com/test/errorSemantics.py
@@ -158,7 +158,7 @@ def test():
"The source in the exception tuple did not yield the correct string",
str(com_exc),
)
- assert exc[2] == "\U0001F600", (
+ assert exc[2] == "\U0001f600", (
"The description in the exception tuple did not yield the correct string",
str(com_exc),
)
@@ -213,7 +213,7 @@ def testLogger():
except pythoncom.error as exc:
# `excepinfo` is a tuple with elt 2 being the traceback we captured.
message = exc.excepinfo[2]
- assert message.endswith("Exception: \U0001F600\n")
+ assert message.endswith("Exception: \U0001f600\n")
assert handler.num_emits == 1, handler.num_emits
assert handler.last_record.startswith(
"pythoncom error: Unexpected exception in gateway method 'Commit'"
@@ -228,7 +228,7 @@ def testLogger():
except pythoncom.error as exc:
# `excepinfo` is a tuple with elt 2 being the traceback we captured.
message = exc.excepinfo[2]
- assert message.endswith("Exception: \U0001F600\n")
+ assert message.endswith("Exception: \U0001f600\n")
assert handler.num_emits == 1, handler.num_emits
handler.reset()
diff --git a/com/win32com/test/testExchange.py b/com/win32com/test/testExchange.py
index 119c16a17..f54422bb6 100644
--- a/com/win32com/test/testExchange.py
+++ b/com/win32com/test/testExchange.py
@@ -91,7 +91,6 @@ def TestUser(session):
def test():
-
oldcwd = os.getcwd()
try:
session = gencache.EnsureDispatch("MAPI.Session")
diff --git a/com/win32com/test/testPyComTest.py b/com/win32com/test/testPyComTest.py
index dbe933669..50330e356 100644
--- a/com/win32com/test/testPyComTest.py
+++ b/com/win32com/test/testPyComTest.py
@@ -411,6 +411,7 @@ def TestDynamic():
def TestGenerated():
# Create an instance of the server.
+ from win32com.client import Record
from win32com.client.gencache import EnsureDispatch
o = EnsureDispatch("PyCOMTest.PyCOMTest")
@@ -433,6 +434,19 @@ def TestGenerated():
coclass = GetClass("{B88DD310-BAE8-11D0-AE86-76F2C1000000}")()
TestCounter(coclass, True)
+ # Test records with SAFEARRAY(VT_RECORD) fields.
+ progress("Testing records with SAFEARRAY(VT_RECORD) fields.")
+ l = []
+ for i in range(3):
+ rec = Record("TestStruct1", o)
+ rec.str_value = "This is record number"
+ rec.int_value = i + 1
+ l.append(rec)
+ test_rec = Record("TestStruct2", o)
+ test_rec.array_of_records = l
+ test_rec.rec_count = i + 1
+ assert o.VerifyArrayOfStructs(test_rec)
+
# XXX - this is failing in dynamic tests, but should work fine.
i1, i2 = o.GetMultipleInterfaces()
# Yay - is now an instance returned!
diff --git a/com/win32com/test/testvb.py b/com/win32com/test/testvb.py
index ca5ab7689..65426559d 100644
--- a/com/win32com/test/testvb.py
+++ b/com/win32com/test/testvb.py
@@ -95,10 +95,13 @@ def TestVB(vbtest, bUseGenerated):
vbtest.VariantProperty == "Hello from Python"
), "Could not set the variant string property correctly."
vbtest.VariantProperty = (1.0, 2.0, 3.0)
- assert vbtest.VariantProperty == (
- 1.0,
- 2.0,
- 3.0,
+ assert (
+ vbtest.VariantProperty
+ == (
+ 1.0,
+ 2.0,
+ 3.0,
+ )
), f"Could not set the variant property to an array of floats correctly - '{vbtest.VariantProperty}'."
TestArrays(vbtest, bUseGenerated)
@@ -195,8 +198,8 @@ def _getcount(ob):
check = []
for item in i:
check.append(item)
- assert check == list(
- expected
+ assert (
+ check == list(expected)
), f"Collection iterator {col_name} didn't have {expected!r} 2nd time around (had {check!r})"
# but an iterator is not restartable
check = []
diff --git a/com/win32com/util.py b/com/win32com/util.py
index 0a5748f1e..2fa8931af 100644
--- a/com/win32com/util.py
+++ b/com/win32com/util.py
@@ -1,6 +1,6 @@
"""General utility functions common to client and server.
- This module contains a collection of general purpose utility functions.
+This module contains a collection of general purpose utility functions.
"""
import pythoncom
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/com/win32comext/axdebug/adb.py b/com/win32comext/axdebug/adb.py
index 191041809..ee6b620c5 100644
--- a/com/win32comext/axdebug/adb.py
+++ b/com/win32comext/axdebug/adb.py
@@ -1,5 +1,4 @@
-"""The glue between the Python debugger interface and the Active Debugger interface
-"""
+"""The glue between the Python debugger interface and the Active Debugger interface"""
import _thread
import bdb
diff --git a/com/win32comext/axdebug/contexts.py b/com/win32comext/axdebug/contexts.py
index df6e97760..d732fbae1 100644
--- a/com/win32comext/axdebug/contexts.py
+++ b/com/win32comext/axdebug/contexts.py
@@ -1,6 +1,4 @@
-""" A module for managing the AXDebug I*Contexts
-
-"""
+"""A module for managing the AXDebug I*Contexts"""
from . import adb, axdebug, gateways
diff --git a/com/win32comext/axdebug/documents.py b/com/win32comext/axdebug/documents.py
index 560901fb4..eb45517e7 100644
--- a/com/win32comext/axdebug/documents.py
+++ b/com/win32comext/axdebug/documents.py
@@ -1,5 +1,4 @@
-""" Management of documents for AXDebugging.
-"""
+"""Management of documents for AXDebugging."""
import pythoncom
import win32api
diff --git a/com/win32comext/axdebug/dump.py b/com/win32comext/axdebug/dump.py
index 61a1cfc7a..6500167c0 100644
--- a/com/win32comext/axdebug/dump.py
+++ b/com/win32comext/axdebug/dump.py
@@ -46,9 +46,7 @@ def dumpall():
e = Enumerator(dm.EnumApplications())
for app in e:
print(f"Application: {app.GetName()}")
- node = (
- app.GetRootNode()
- ) # of type PyIDebugApplicationNode->PyIDebugDocumentProvider->PyIDebugDocumentInfo
+ node = app.GetRootNode() # of type PyIDebugApplicationNode->PyIDebugDocumentProvider->PyIDebugDocumentInfo
DumpDebugApplicationNode(node)
diff --git a/com/win32comext/axscript/client/error.py b/com/win32comext/axscript/client/error.py
index 5aadbf9bc..f02e66603 100644
--- a/com/win32comext/axscript/client/error.py
+++ b/com/win32comext/axscript/client/error.py
@@ -1,7 +1,7 @@
"""Exception and error handling.
- This contains the core exceptions that the implementations should raise
- as well as the IActiveScriptError interface code.
+This contains the core exceptions that the implementations should raise
+as well as the IActiveScriptError interface code.
"""
from __future__ import annotations
diff --git a/com/win32comext/axscript/client/framework.py b/com/win32comext/axscript/client/framework.py
index b9f0fd605..c4a04329f 100644
--- a/com/win32comext/axscript/client/framework.py
+++ b/com/win32comext/axscript/client/framework.py
@@ -1,10 +1,10 @@
"""AXScript Client Framework
- This module provides a core framework for an ActiveX Scripting client.
- Derived classes actually implement the AX Client itself, including the
- scoping rules, etc.
+This module provides a core framework for an ActiveX Scripting client.
+Derived classes actually implement the AX Client itself, including the
+scoping rules, etc.
- There are classes defined for the engine itself, and for ScriptItems
+There are classes defined for the engine itself, and for ScriptItems
"""
from __future__ import annotations
diff --git a/com/win32comext/axscript/client/scriptdispatch.py b/com/win32comext/axscript/client/scriptdispatch.py
index ca696fe84..6bd29adcb 100644
--- a/com/win32comext/axscript/client/scriptdispatch.py
+++ b/com/win32comext/axscript/client/scriptdispatch.py
@@ -1,8 +1,8 @@
"""dynamic dispatch objects for AX Script.
- This is an IDispatch object that a scripting host may use to
- query and invoke methods on the main script. Not may hosts use
- this yet, so it is not well tested!
+This is an IDispatch object that a scripting host may use to
+query and invoke methods on the main script. Not may hosts use
+this yet, so it is not well tested!
"""
from __future__ import annotations
diff --git a/isapi/samples/redirector_with_filter.py b/isapi/samples/redirector_with_filter.py
index 6d9914c04..393e89d05 100644
--- a/isapi/samples/redirector_with_filter.py
+++ b/isapi/samples/redirector_with_filter.py
@@ -84,6 +84,7 @@ def Dispatch(self, ecb):
# The ISAPI filter.
class Filter(SimpleFilter):
"Sample Python Redirector"
+
filter_flags = isapicon.SF_NOTIFY_PREPROC_HEADERS | isapicon.SF_NOTIFY_ORDER_DEFAULT
def HttpFilterProc(self, fc):
diff --git a/isapi/simple.py b/isapi/simple.py
index d5fcb04d7..177e8935c 100644
--- a/isapi/simple.py
+++ b/isapi/simple.py
@@ -40,6 +40,7 @@ def TerminateExtension(self, status):
class SimpleFilter:
"Base class for a a simple ISAPI filter"
+
filter_flags: int | None = None
def __init__(self):
diff --git a/isapi/threaded_extension.py b/isapi/threaded_extension.py
index 044b90987..b6a161a23 100644
--- a/isapi/threaded_extension.py
+++ b/isapi/threaded_extension.py
@@ -60,6 +60,7 @@ def call_handler(self, cblock):
# fully asynch extension.
class ThreadPoolExtension(isapi.simple.SimpleExtension):
"Base class for an ISAPI extension based around a thread-pool"
+
max_workers = 20
worker_shutdown_wait = 15000 # 15 seconds for workers to quit...
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/setup.py b/setup.py
index e25465fd7..e72edf0ad 100644
--- a/setup.py
+++ b/setup.py
@@ -1341,9 +1341,7 @@ def finalize_options(self):
{win32com}/extensions/PyICancelMethodCalls.cpp {win32com}/extensions/PyIContext.cpp
{win32com}/extensions/PyIEnumContextProps.cpp {win32com}/extensions/PyIClientSecurity.cpp
{win32com}/extensions/PyIServerSecurity.cpp
- """.format(
- **dirs
- )
+ """.format(**dirs)
).split(),
depends=(
"""
@@ -1370,9 +1368,7 @@ def finalize_options(self):
{win32com}/include\\PyICancelMethodCalls.h {win32com}/include\\PyIContext.h
{win32com}/include\\PyIEnumContextProps.h {win32com}/include\\PyIClientSecurity.h
{win32com}/include\\PyIServerSecurity.h
- """.format(
- **dirs
- )
+ """.format(**dirs)
).split(),
libraries="oleaut32 ole32 user32 urlmon",
export_symbol_file="com/win32com/src/PythonCOM.def",
@@ -1400,9 +1396,7 @@ def finalize_options(self):
{adsi}/adsilib.i
{adsi}/PyADSIUtil.cpp {adsi}/PyDSOPObjects.cpp
{adsi}/PyIADs.cpp
- """.format(
- **dirs
- )
+ """.format(**dirs)
).split(),
),
WinExt_win32com(
@@ -1420,9 +1414,7 @@ def finalize_options(self):
{axcontrol}/PyIOleClientSite.cpp {axcontrol}/PyIOleInPlaceSite.cpp
{axcontrol}/PyIOleObject.cpp {axcontrol}/PyIViewObject2.cpp
{axcontrol}/PyIOleCommandTarget.cpp
- """.format(
- **dirs
- )
+ """.format(**dirs)
).split(),
),
WinExt_win32com(
@@ -1437,9 +1429,7 @@ def finalize_options(self):
{axscript}/PyIActiveScriptParse.cpp {axscript}/PyIActiveScriptParseProcedure.cpp
{axscript}/PyIActiveScriptSite.cpp {axscript}/PyIMultiInfos.cpp
{axscript}/PyIObjectSafety.cpp {axscript}/stdafx.cpp
- """.format(
- **dirs
- )
+ """.format(**dirs)
).split(),
depends=(
"""
@@ -1448,9 +1438,7 @@ def finalize_options(self):
{axscript}/PyIActiveScriptError.h {axscript}/PyIObjectSafety.h
{axscript}/PyIProvideMultipleClassInfo.h
{axscript}/stdafx.h
- """.format(
- **dirs
- )
+ """.format(**dirs)
).split(),
extra_compile_args=["-DPY_BUILD_AXSCRIPT"],
implib_name="axscript",
@@ -1506,9 +1494,7 @@ def finalize_options(self):
{axdebug}/PyIRemoteDebugApplicationEvents.cpp
{axdebug}/PyIRemoteDebugApplicationThread.cpp
{axdebug}/stdafx.cpp
- """.format(
- **dirs
- )
+ """.format(**dirs)
).split(),
),
WinExt_win32com(
@@ -1521,9 +1507,7 @@ def finalize_options(self):
{internet}/PyIInternetPriority.cpp {internet}/PyIInternetProtocol.cpp
{internet}/PyIInternetProtocolInfo.cpp {internet}/PyIInternetProtocolRoot.cpp
{internet}/PyIInternetProtocolSink.cpp {internet}/PyIInternetSecurityManager.cpp
- """.format(
- **dirs
- )
+ """.format(**dirs)
).split(),
depends=["{internet}/internet_pch.h".format(**dirs)],
),
@@ -1559,9 +1543,7 @@ def finalize_options(self):
{mapi}/mapiguids.cpp
{mapi}/MAPIStubLibrary/library/mapiStubLibrary.cpp
{mapi}/MAPIStubLibrary/library/stubutils.cpp
- """.format(
- **dirs
- )
+ """.format(**dirs)
).split(),
),
WinExt_win32com_mapi(
@@ -1577,9 +1559,7 @@ def finalize_options(self):
{mapi}/exchangeguids.cpp
{mapi}/MAPIStubLibrary/library/mapiStubLibrary.cpp
{mapi}/MAPIStubLibrary/library/stubutils.cpp
- """.format(
- **dirs
- )
+ """.format(**dirs)
).split(),
),
WinExt_win32com(
@@ -1661,9 +1641,7 @@ def finalize_options(self):
{shell}/PyIUniformResourceLocator.cpp
{shell}/shell.cpp
- """.format(
- **dirs
- )
+ """.format(**dirs)
).split(),
),
WinExt_win32com(
@@ -1691,9 +1669,7 @@ def finalize_options(self):
{propsys}/PyIObjectWithPropertyKey.cpp
{propsys}/PyIPropertyChange.cpp
{propsys}/PyIPropertyChangeArray.cpp
- """.format(
- **dirs
- )
+ """.format(**dirs)
).split(),
implib_name="pypropsys",
),
@@ -1709,9 +1685,7 @@ def finalize_options(self):
{taskscheduler}/PyITaskScheduler.cpp
{taskscheduler}/PyITaskTrigger.cpp
- """.format(
- **dirs
- )
+ """.format(**dirs)
).split(),
),
WinExt_win32com(
@@ -1732,9 +1706,7 @@ def finalize_options(self):
{bits}/PyIEnumBackgroundCopyJobs.cpp
{bits}/PyIEnumBackgroundCopyFiles.cpp
- """.format(
- **dirs
- )
+ """.format(**dirs)
).split(),
),
WinExt_win32com(
@@ -1755,18 +1727,14 @@ def finalize_options(self):
{directsound}/PyIDirectSoundBuffer.cpp {directsound}/PyIDirectSoundCapture.cpp
{directsound}/PyIDirectSoundCaptureBuffer.cpp
{directsound}/PyIDirectSoundNotify.cpp
- """.format(
- **dirs
- )
+ """.format(**dirs)
).split(),
depends=(
"""
{directsound}/directsound_pch.h {directsound}/PyIDirectSound.h
{directsound}/PyIDirectSoundBuffer.h {directsound}/PyIDirectSoundCapture.h
{directsound}/PyIDirectSoundCaptureBuffer.h {directsound}/PyIDirectSoundNotify.h
- """.format(
- **dirs
- )
+ """.format(**dirs)
).split(),
optional_headers=["dsound.h"],
libraries="user32 dsound dxguid",
@@ -1778,9 +1746,7 @@ def finalize_options(self):
"""
{authorization}/authorization.cpp
{authorization}/PyGSecurityInformation.cpp
- """.format(
- **dirs
- )
+ """.format(**dirs)
).split(),
),
]
diff --git a/win32/Demos/security/GetTokenInformation.py b/win32/Demos/security/GetTokenInformation.py
index 192c549e1..745e0e78e 100644
--- a/win32/Demos/security/GetTokenInformation.py
+++ b/win32/Demos/security/GetTokenInformation.py
@@ -1,5 +1,5 @@
-""" Lists various types of information about current user's access token,
- including UAC status on Vista
+"""Lists various types of information about current user's access token,
+including UAC status on Vista
"""
import pywintypes
diff --git a/win32/Demos/win32ts_logoff_disconnected.py b/win32/Demos/win32ts_logoff_disconnected.py
index 2a8bcc940..3b7f882e0 100644
--- a/win32/Demos/win32ts_logoff_disconnected.py
+++ b/win32/Demos/win32ts_logoff_disconnected.py
@@ -1,4 +1,4 @@
-""" Finds any disconnected terminal service sessions and logs them off"""
+"""Finds any disconnected terminal service sessions and logs them off"""
import pywintypes
import win32ts
diff --git a/win32/Lib/win32evtlogutil.py b/win32/Lib/win32evtlogutil.py
index 05cabe2b8..58d3326ef 100644
--- a/win32/Lib/win32evtlogutil.py
+++ b/win32/Lib/win32evtlogutil.py
@@ -1,5 +1,4 @@
-"""Event Log Utilities - helper for win32evtlog.pyd
-"""
+"""Event Log Utilities - helper for win32evtlog.pyd"""
import win32api
import win32con
diff --git a/win32/Lib/win32gui_struct.py b/win32/Lib/win32gui_struct.py
index 41ef815fd..5651c7bc8 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
@@ -808,9 +808,7 @@ def EmptyLVCOLUMN(mask=None, text_buf_size=512):
text_addr, _ = text_buffer.buffer_info()
else:
text_addr = text_buf_size = 0
- buf = struct.pack(
- _lvcolumn_fmt, mask, 0, 0, text_addr, text_buf_size, 0, 0, 0 # text
- )
+ buf = struct.pack(_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/Lib/win32rcparser.py b/win32/Lib/win32rcparser.py
index b87bd96fe..183f075b1 100644
--- a/win32/Lib/win32rcparser.py
+++ b/win32/Lib/win32rcparser.py
@@ -7,6 +7,7 @@
This is a parser for Windows .rc files, which are text files which define
dialogs and other Windows UI resources.
"""
+
from __future__ import annotations
import os
diff --git a/win32/scripts/regsetup.py b/win32/scripts/regsetup.py
index da2f870e1..fb33e11dd 100644
--- a/win32/scripts/regsetup.py
+++ b/win32/scripts/regsetup.py
@@ -447,8 +447,7 @@ def RegisterShellInfo(searchPaths):
# FindRegisterApp("win32", ["win32con.pyc", "win32api%s.pyd" % suffix], searchPaths)
-usage = (
- """\
+usage = """\
regsetup.py - Setup/maintain the registry for Python apps.
Run without options, (but possibly search paths) to repair a totally broken
@@ -475,9 +474,7 @@ def RegisterShellInfo(searchPaths):
--description -- Print a description of the usage.
--examples -- Print examples of usage.
-"""
- % sys.argv[0]
-)
+""" % sys.argv[0]
description = """\
If no options are processed, the program attempts to validate and set
diff --git a/win32/test/test_win32clipboard.py b/win32/test/test_win32clipboard.py
index f5d5c28d1..ccfc32e53 100644
--- a/win32/test/test_win32clipboard.py
+++ b/win32/test/test_win32clipboard.py
@@ -5,7 +5,6 @@
class TestGetSetClipboardData(unittest.TestCase):
-
def copyData(self, data, format_):
win32clipboard.OpenClipboard()
ret = None
@@ -30,13 +29,13 @@ def test_data(self):
test_data = {
"Dummy str": win32clipboard.CF_UNICODETEXT,
b"Dummy bytes text": win32clipboard.CF_TEXT,
- b"Dummy\x00\xFF bytes": win32clipboard.CF_DIB,
+ b"Dummy\x00\xff bytes": win32clipboard.CF_DIB,
}
for data, fmt in test_data.items():
self.assertEqual(data, self.copyData(data, fmt))
test_data = {
"Dummy str": (win32clipboard.CF_TEXT, win32clipboard.CF_DIB),
- b"Dummy\x00\xFF bytes": (win32clipboard.CF_UNICODETEXT,),
+ b"Dummy\x00\xff bytes": (win32clipboard.CF_UNICODETEXT,),
}
for data, formats in test_data.items():
for fmt in formats:
diff --git a/win32/test/test_win32cred.py b/win32/test/test_win32cred.py
index c44fe18b8..4b9fe08d7 100644
--- a/win32/test/test_win32cred.py
+++ b/win32/test/test_win32cred.py
@@ -5,7 +5,6 @@
class TestCredFunctions(unittest.TestCase):
-
def setUp(self):
self.flags = 0
self.dummy_cred = {
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)