Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,17 +152,15 @@ jobs:
python-version: "3.8"
cache: pip
cache-dependency-path: .github/workflows/main.yml
- run: pip install clang-format==18.1.* pycln
- run: pip install clang-format==18.1.*
# !cancelled(): Show issues even if the previous steps failed. But still fail the job
- run: pycln . --config=pycln.toml --check
- name: Run Ruff linter
uses: astral-sh/ruff-action@v3
with:
version: "0.11.0"
version: "0.14.4"
if: ${{ !cancelled() }}
- name: Run Ruff formatter
run: ruff format --check
if: ${{ !cancelled() }}
# Too many files to fit in a single command, also exclude vendored Scintilla and MAPIStubLibrary
- run: |
clang-format --Werror --dry-run $(git ls-files '*.cpp' ':!:com/win32comext/mapi/src/MAPIStubLibrary/')
Expand Down
8 changes: 1 addition & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,8 @@ repos:
args: [--autofix, --indent, "2", --offset, "2", --preserve-quotes]
- id: pretty-format-ini
args: [--autofix]
- repo: https://github.com/hadialqattan/pycln
rev: v2.4.0
hooks:
- id: pycln
args: [--config=pycln.toml]
verbose: true
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.0
rev: v0.14.4
hooks:
- id: ruff # Run the linter.
args: [--fix]
Expand Down
2 changes: 1 addition & 1 deletion Pythonwin/pywin/framework/editor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,6 @@ def SetEditorFontOption(option, newValue):
SetEditorOption(option, str(newValue))


from pywin.framework.editor.color.coloreditor import ( # nopycln: import
from pywin.framework.editor.color.coloreditor import (
editorTemplate as editorTemplate, # Adds doc template & Re-export
)
2 changes: 1 addition & 1 deletion Pythonwin/pywin/framework/interact.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import pywin.framework.app
import pywin.scintilla.control
import pywin.scintilla.formatter
import pywin.scintilla.IDLEenvironment # nopycln: import # Injects fast_readline into the IDLE auto-indent extension
import pywin.scintilla.IDLEenvironment # Injects fast_readline into the IDLE auto-indent extension
import win32api
import win32clipboard
import win32con
Expand Down
2 changes: 1 addition & 1 deletion Pythonwin/pywin/framework/intpydde.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import traceback

import win32ui
from dde import ( # nopycln: import # Re-exported for intpyapp.py
from dde import ( # PLC0414: Re-exported for intpyapp.py
CBF_FAIL_SELFCONNECTIONS as CBF_FAIL_SELFCONNECTIONS, # noqa: PLC0414
CreateConversation as CreateConversation, # noqa: PLC0414
CreateServer,
Expand Down
5 changes: 3 additions & 2 deletions Pythonwin/pywin/scintilla/bindings.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
import win32con
import win32ui

from . import ( # nopycln: import # Injects fast_readline into the IDLE auto-indent extension
IDLEenvironment,
from . import (
# https://github.com/astral-sh/ruff/issues/15705
IDLEenvironment, # noqa: F401 # Injects fast_readline into the IDLE auto-indent extension
Comment on lines +9 to +11
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

astral-sh/ruff#15705
This was also already affecting pycln

)

HANDLER_ARGS_GUESS = 0
Expand Down
2 changes: 1 addition & 1 deletion Pythonwin/pywin/scintilla/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from pywin.mfc import afxres, docview

from . import (
IDLEenvironment, # nopycln: import # Injects fast_readline into the IDLE auto-indent extension
IDLEenvironment, # Injects fast_readline into the IDLE auto-indent extension
bindings,
control,
scintillacon,
Expand Down
2 changes: 1 addition & 1 deletion Pythonwin/pywin/test/test_pywin.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ def test_ia(self):
def test_docedit(self):
import tempfile

import pywin.scintilla.IDLEenvironment # nopycln: import # Injects fast_readline into the IDLE auto-indent extension
import pywin.scintilla.IDLEenvironment # Injects fast_readline into the IDLE auto-indent extension

##doc = pywin.framework.editor.editorTemplate.OpenDocumentFile(None)
def t_print(*args):
Expand Down
1 change: 0 additions & 1 deletion adodbapi/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# nopycln: file # undecidable cases due to explicit re-exports https://github.com/hadialqattan/pycln/issues/205
"""adodbapi - A python DB API 2.0 (PEP 249) interface to Microsoft ADO

Copyright (C) 2002 Henrik Ekelund, version 2.1 by Vernon Cole
Expand Down
4 changes: 2 additions & 2 deletions adodbapi/adodbapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -1015,7 +1015,7 @@ def executemany(self, operation, seq_of_parameters):

Return values are not defined.
"""
self.messages = list()
self.messages = []
total_recordcount = 0

self.prepare(operation)
Expand All @@ -1039,7 +1039,7 @@ def _fetch(self, limit=None):
return

if self.rs.State == adc.adStateClosed or self.rs.BOF or self.rs.EOF:
return list()
return []
if limit: # limit number of rows retrieved
ado_results = self.rs.GetRows(limit)
else: # get all rows
Expand Down
2 changes: 1 addition & 1 deletion adodbapi/apibase.py
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ def __next__(self):
yield self._getValue(n)

def __repr__(self): # create a human readable representation
taglist = sorted(list(self.rows.columnNames.items()), key=lambda x: x[1])
taglist = sorted(self.rows.columnNames.items(), key=lambda x: x[1])
s = "<SQLrow={"
for name, i in taglist:
s += f"{name}:{self._getValue(i)!r}, "
Expand Down
2 changes: 0 additions & 2 deletions com/win32com/client/combrowse.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,6 @@ def GetBitmapColumn(self):

class HLIRegisteredTypeLibrary(HLICOM):
def GetSubList(self):
import os

clsidstr, versionStr = self.myobject
collected = []
helpPath = ""
Expand Down
4 changes: 2 additions & 2 deletions com/win32com/client/makepy.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,8 @@ def LogWarning(self, desc):

class GUIProgress(SimpleProgress):
def __init__(self, verboseLevel):
# Import some modules we need to we can trap failure now.
import pywin # nopycln: import
# Import some modules we need so we can trap failure now.
import pywin # noqa: F401
import win32ui

SimpleProgress.__init__(self, verboseLevel)
Expand Down
2 changes: 1 addition & 1 deletion com/win32com/server/dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ def _trace_(self, *args):


try:
import win32trace # nopycln: import # Check for win32traceutil w/o importing it
import win32trace # noqa: F401 # Check for win32traceutil w/o importing it

DefaultDebugDispatcher: type[DispatcherTrace] = DispatcherWin32trace
except ImportError: # no win32trace module - just use a print based one.
Expand Down
2 changes: 1 addition & 1 deletion com/win32comext/adsi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
# interface, as well as via IDispatch.
import pythoncom

from .adsi import * # nopycln: import # Re-export everything from win32comext/adsi/adsi.pyd
from .adsi import * # Re-export everything from win32comext/adsi/adsi.pyd

LCID = 0

Expand Down
2 changes: 1 addition & 1 deletion com/win32comext/adsi/demos/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ def main():
break
else:
print("Test '%s' unknown - skipping" % arg)
if not len(dotests):
if not dotests:
print("Nothing to do!")
usage(tests)
for test in dotests:
Expand Down
2 changes: 1 addition & 1 deletion com/win32comext/mapi/emsabtags.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# nopycln: file # Re-exporting many constants
# ruff: noqa: F401 # Re-exporting many constants
# Converted "manually" from EMSABTAG.H
from .mapitags import (
PROP_TAG,
Expand Down
2 changes: 1 addition & 1 deletion com/win32comext/propsys/test/testpropsys.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from win32com.propsys import propsys, pscon # nopycln: import
from win32com.propsys import propsys, pscon

print("propsys was imported (sorry - that is the extent of the tests,")
print("but see the shell folder_view demo, which uses this module)")
Expand Down
13 changes: 0 additions & 13 deletions pycln.toml

This file was deleted.

48 changes: 26 additions & 22 deletions ruff.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
target-version = "py38" # Target the oldest supported version in editors and default CLI
target-version = "py38" # Target the oldest supported version
# This file is not UTF-8
extend-exclude = ["Pythonwin/pywin/test/_dbgscript.py"]

Expand All @@ -9,6 +9,7 @@ line-ending = "cr-lf"
select = [
"B028", # no-explicit-stacklevel
"C4", # flake8-comprehensions
"F401", # unused-import
"F811", # redefined-while-unused
"I", # isort
"PLC", # Pylint Convention
Expand All @@ -20,42 +21,45 @@ select = [
# String formatting, concatenating, interpolation, ...
"FLY", # static-join-to-f-string
"G", # flake8-logging-format
# Note, we still want to allow multiline ISC
"UP025", # Remove unicode literals from strings
"UP030", # Use implicit references for positional format fields
# TODO: Still lots of manual fixes needed
# "UP031", # Use format specifiers instead of percent format
# "UP032", # Use f-string instead of format call

# Ensure modern type annotation syntax and best practices
# Not including those covered by type-checkers or exclusive to Python 3.11+
"FA", # flake8-future-annotations
"F404", # late-future-import
"PYI", # flake8-pyi
"UP006", # non-pep585-annotation
"UP007", # non-pep604-annotation
"UP010", # unnecessary-future-import
"UP035", # deprecated-import
"UP037", # quoted-annotation
"UP043", # unnecessary-default-type-args

# Code modernization (strings, annotations, conditions, ...)
"UP", # pyupgrade

# Helps prevent circular imports and other unneeded imports
"TC", # flake8-type-checking
]

extend-ignore = [
# TODO: Consider passing exception around to ensure methods are only ever used within exception handlers
"PLE0704", # misplaced-bare-raise

# We prefer explicit open mode parameter
"UP015", # redundant-open-modes
# No such concerns for stdlib
"TC003", # typing-only-standard-library-import
# Lots of lazy or side-effect imports
"PLC0415", # import-outside-top-level
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added ignore for Ruff 0.12

# TODO: Consider passing exception around to ensure methods are only ever used within exception handlers
"PLE0704", # misplaced-bare-raise
# TODO: Still lots of manual fixes needed
"UP031", # Use format specifiers instead of percent format
"UP032", # Use f-string instead of format call
]

[lint.per-file-ignores]
# Explicit re-exports is fine in __init__.py, still a code smell elsewhere.
"__init__.py" = ["PLC0414"]
# TODO: Make adodbapi changes in their own PRs
"adodbapi/*" = ["C4", "YTT301", "UP031", "UP032"]
Comment on lines -54 to -58
Copy link
Collaborator Author

@Avasam Avasam Nov 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PLC0414 is now ignored in __init__.py by default

UP031 and UP032 are already ignored globally, so are redundant here.

YTT301 was already passing

C4 had 3 fairly minor and safe autofixes.

[lint.pyflakes]
allowed-unused-imports = [
# Modules with known side-effects
"coloreditor", # Adds doc template
"IDLEenvironment", # Injects fast_readline into the IDLE auto-indent extension
"pythoncom", # pythoncomXX.dll loader
"pywintypes", # pywintypesXX.dll loader
"win32com", # Sets pythoncom.frozen and adds modules to path based on the registry
"win32traceutil", # Redirects output to win32trace remote collector
"win32ui", # Must always be imported before dde
# Note: com/win32com/client/gencache.py does read files on import, but only to fill in it's own dicts from cache
]

[lint.isort]
combine-as-imports = true
Expand Down
10 changes: 5 additions & 5 deletions win32/Demos/service/pipeTestService.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@

# # Use "import *" to keep this looking as much as a "normal" service
# as possible. Real code shouldn't do this.
from ntsecuritycon import * # nopycln: import
from win32api import * # nopycln: import
from win32event import * # nopycln: import
from win32file import * # nopycln: import
from win32pipe import * # nopycln: import
from ntsecuritycon import *
from win32api import *
from win32event import *
from win32file import *
from win32pipe import *


def ApplyIgnoreError(fn, args):
Expand Down
6 changes: 3 additions & 3 deletions win32/Demos/service/pipeTestServiceClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@

# # Use "import *" to keep this looking as much as a "normal" service
# as possible. Real code shouldn't do this.
from win32event import * # nopycln: import
from win32file import * # nopycln: import
from win32pipe import * # nopycln: import
from win32event import *
from win32file import *
from win32pipe import *

verbose = 0

Expand Down
2 changes: 1 addition & 1 deletion win32/Demos/win32netdemo.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ def main():
break
else:
print("Test '%s' unknown - skipping" % arg)
if not len(dotests):
if not dotests:
print("Nothing to do!")
usage(tests)
for test in dotests:
Expand Down
2 changes: 1 addition & 1 deletion win32/Lib/win2kras.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@

import warnings

from win32ras import * # nopycln: import
from win32ras import *

warnings.warn(str(__doc__), category=DeprecationWarning, stacklevel=2)
2 changes: 1 addition & 1 deletion win32/Lib/winxptheme.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
around _winxptheme.
"""

from _winxptheme import * # nopycln: import
from _winxptheme import *
2 changes: 1 addition & 1 deletion win32/scripts/h2py.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ def process(fp, outfp, env={}):
try:
inclfp = open(dir + "/" + filename)
break
except IOError:
except OSError:
pass
if inclfp:
with inclfp:
Expand Down
5 changes: 0 additions & 5 deletions win32/scripts/regsetup.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,6 @@ def FindPythonExe(exeAlias, possibleRealNames, searchPaths):

def QuotedFileName(fname):
"""Given a filename, return a quoted version if necessary"""

import regutil

try:
fname.index(" ") # Other chars forcing quote?
return '"%s"' % fname
Expand All @@ -183,8 +180,6 @@ def LocateFileName(fileNamesString, searchPaths):
"""
import os

import regutil

fileNames = fileNamesString.split(";")
for path in searchPaths:
for fileName in fileNames:
Expand Down
2 changes: 0 additions & 2 deletions win32/test/testall.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,6 @@ def __call__(self):


def get_demo_tests():
import win32api

ret = []
demo_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "Demos"))
assert os.path.isdir(demo_dir), demo_dir
Expand Down
4 changes: 2 additions & 2 deletions win32/winxpgui.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

import warnings

from win32console import ( # nopycln: import
from win32console import (
GetConsoleWindow as GetConsoleWindow, # noqa: PLC0414 # Explicit re-export
)
from win32gui import * # nopycln: import
from win32gui import *

warnings.warn(str(__doc__), category=DeprecationWarning, stacklevel=2)