From 83587fe91eef3054430a8bd52ab2b4f68ce7bd1e Mon Sep 17 00:00:00 2001 From: mohitt31 Date: Wed, 9 Sep 2026 15:07:43 +0530 Subject: [PATCH 1/4] Switch python tooling to ruff The configuration was spread over .flake8, setup.cfg and pyproject.toml with two flake8 sections disagreeing on the line length, and setup.cfg also carried pycodestyle and pep8 sections for tools that were not run. Replace black, flake8 and pylint with ruff and ruff-format and put the configuration in a single .ruff.toml, matching what EDM4hep uses. Two kinds of suppression had to be adjusted. `# noqa: 402` was missing the E, so flake8 was treating it as a blanket noqa; it is now `# noqa: E402`. The `# pylint: disable=import-outside-toplevel` comments are not read by ruff and become `# noqa: PLC0415`. PLW2901 also fires on two deliberate loop rebinds that pylint did not flag. The reformatting that comes with ruff format is in the next commit. --- .flake8 | 6 - .github/scripts/pylint.rc | 353 ---------------------------- .pre-commit-config.yaml | 16 +- .ruff.toml | 16 ++ pyproject.toml | 3 - python/podio/arrow_io.py | 4 +- python/podio/frame.py | 2 +- python/podio/sio_io.py | 4 +- python/podio/test_ReaderSio.py | 4 +- python/podio_gen/julia_generator.py | 2 +- setup.cfg | 38 --- tools/podio-dump-legacy | 2 +- 12 files changed, 31 insertions(+), 419 deletions(-) delete mode 100644 .flake8 delete mode 100644 .github/scripts/pylint.rc create mode 100644 .ruff.toml delete mode 100644 pyproject.toml delete mode 100644 setup.cfg diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 58db8675a..000000000 --- a/.flake8 +++ /dev/null @@ -1,6 +0,0 @@ -[flake8] -max-line-length = 99 -extend-ignore = E203 - -per-file-ignores = - python/podio_gen/test_MemberParser.py: E501 diff --git a/.github/scripts/pylint.rc b/.github/scripts/pylint.rc deleted file mode 100644 index a3c9fb148..000000000 --- a/.github/scripts/pylint.rc +++ /dev/null @@ -1,353 +0,0 @@ -[MASTER] -# Specify a configuration file. -#rcfile= - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -#init-hook= - -# Add files or directories to the blacklist. They should be base names, not -# paths. -#ignore= - -# Add files or directories matching the regex patterns to the blacklist. The -# regex matches against base names, not paths. -ignore-patterns=.*\.cfg - -# Pickle collected data for later comparisons. -persistent=yes - -# List of plugins (as comma separated values of python modules names) to load, -# usually to register additional checkers. -load-plugins= - -# Use multiple processes to speed up Pylint. -jobs=1 - -# Allow loading of arbitrary C extensions. Extensions are imported into the -# active Python interpreter and may run arbitrary code. -unsafe-load-any-extension=no - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code -extension-pkg-whitelist= - - -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED -confidence= - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time (only on the command line, not in the configuration file where -# it should appear only once). See also the "--disable" option for examples. -#enable= - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once).You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use"--disable=all --enable=classes -# --disable=W" -disable=line-too-long, - useless-suppression, - trailing-whitespace, - suppressed-message, - too-many-positional-arguments, - - -[REPORTS] - -# Set the output format. Available formats are text, parseable, colorized, msvs -# (visual studio) and html. You can also give a reporter class, eg -# mypackage.mymodule.MyReporterClass. -output-format=text - -# Tells whether to display a full report or only the messages -reports=yes - -# Python expression which should return a note less than 10 (10 is the highest -# note). You have access to the variables errors warning, statement which -# respectively contain the number of errors / warnings messages and the total -# number of statements analyzed. This is used by the global evaluation report -# (RP0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) - -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details -#msg-template= - - -[BASIC] - -# Regular expression matching correct function names -function-rgx=[a-z_][A-Za-z0-9_]{2,50}$ - -# Regular expression matching correct variable names -variable-rgx=[a-z_][A-Za-z0-9_]{1,30}$ - -# Regular expression matching correct constant names -const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__)|(g[A-Z][a-zA-Z0-9]*))$ - -# Regular expression matching correct attribute names -attr-rgx=[a-z_][A-Za-z0-9_]{2,30}$ - -# Regular expression matching correct argument names -argument-rgx=[a-z_][A-Za-z0-9_]{1,30}$ - -# Regular expression matching correct class attribute names -class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Regular expression matching correct inline iteration names -inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ - -# Regular expression matching correct class names -class-rgx=[A-Z_][a-zA-Z0-9]+$ - -# Regular expression matching correct module names -module-rgx=(([a-z_][-a-z0-9_]*)|((test_)?[A-Z][-a-zA-Z0-9]+)|flymake.*)$ - -# Regular expression matching correct method names -method-rgx=[a-z_][A-Za-z0-9_]{2,50}$ - -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=__.*__|set[a-zA-Z]*|get[a-zA-Z]*|registerSwitches|Params|_?test_ - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 - -# Good variable names which should always be accepted, separated by a comma -good-names=e,i,j,k,x,ex,Run,_,S_OK,S_ERROR - -# Bad variable names which should always be refused, separated by a comma -bad-names=foo,bar,baz,toto,tutu,tata,spam,egg - - -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= - -# Include a hint for the correct naming format with invalid-name -include-naming-hint=no - -# List of decorators that produce properties, such as abc.abstractproperty. Add -# to this list to register other decorators that produce valid properties. -property-classes=abc.abstractproperty - -[FORMAT] - -# Maximum number of characters on a single line. -max-line-length=88 - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=^\s*(# )??$ - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=no - -# Maximum number of lines in a module -max-module-lines=1200 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=' ' - -# Number of spaces of indent required inside a hanging or continued line. -indent-after-paren=4 - -# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. -expected-line-ending-format= - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -notes=FIXME,XXX,TODO - -[SIMILARITIES] - -# Minimum lines number of a similarity. -min-similarity-lines=10 - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - -# Ignore imports when computing similarities. -ignore-imports=no - -[LOGGING] - -# Logging modules to check that the string format arguments are in logging -# function parameter format -logging-modules=logging - -[ELIF] - -# Maximum number of nested blocks for function / method body -max-nested-blocks=5 - - -[TYPECHECK] - -# Tells whether missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=yes - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis. It -# supports qualified module names, as well as Unix pattern matching. -ignored-modules=ROOT - -# List of class names for which member attributes should not be checked (useful -# for classes with dynamically set attributes). This supports the use of -# qualified names. -ignored-classes=SQLObject - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E1101 when accessed. Python regular -# expressions are accepted. -generated-members=REQUEST,acl_users,aq_parent - -# List of decorators that produce context managers, such as -# contextlib.contextmanager. Add to this list to register other decorators that -# produce valid context managers. -contextmanager-decorators=contextlib.contextmanager - -[VARIABLES] - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# A regular expression matching the name of dummy variables (i.e. expectedly -# not used). -dummy-variables-rgx=_|dummy - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -additional-builtins= - -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_,_cb - -# List of qualified module names which can have objects that can redefine -# builtins. -redefining-builtins-modules=six.moves,future.builtins - -[CLASSES] - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__,__new__,setUp,initialize - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=mcs - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict,_fields,_replace,_source,_make - -[DESIGN] - -# Maximum number of arguments for function / method -max-args=10 - -# Argument names that match this expression will be ignored. Default to name -# with leading underscore -ignored-argument-names=_.* - -# Maximum number of locals for function / method body -max-locals=25 - -# Maximum number of return / yield for function / method body -max-returns=8 - -# Maximum number of branch for function / method body -max-branches=15 - -# Maximum number of statements in function / method body -max-statements=50 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of attributes for a class (see R0902). -max-attributes=30 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=0 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - -# Maximum number of boolean expressions in a if statement -max-bool-expr=5 - - -[SPELLING] - -# Spelling dictionary name. Available dictionaries: none. To make it working -# install python-enchant package. -spelling-dict= - -# List of comma separated words that should not be checked. -spelling-ignore-words= - -# A path to a file that contains private dictionary; one word per line. -spelling-private-dict-file= - -# Tells whether to store unknown words to indicated private dictionary in -# --spelling-private-dict-file option instead of raising a message. -spelling-store-unknown-words=no - - -[IMPORTS] - -# Deprecated modules which should not be used, separated by a comma -deprecated-modules=regsub,TERMIOS,Bastion,rexec - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled) -#import-graph= - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled) -#ext-import-graph= - -# Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled) -int-import-graph= - -# Force import order to recognize a module as part of the standard -# compatibility libraries. -known-standard-library= - -# Force import order to recognize a module as part of a third party library. -known-third-party=enchant - -# Analyse import fallback blocks. This can be used to support both Python 2 and -# 3 compatible code, which means that the block might have code that exists -# only in one or another interpreter, leading to false positives when analysed. -analyse-fallback-blocks=no - - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when being caught. Defaults to -# "Exception" -overgeneral-exceptions=builtins.Exception diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 35825c28a..fcd834160 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,10 +5,6 @@ repos: - id: mixed-line-ending - id: trailing-whitespace exclude: (doc/ReleaseNotes.md) - - repo: https://github.com/psf/black - rev: 2a1c67e0b2f81df602ec1f6e7aeb030b9709dc7c # frozen: 23.11.0 - hooks: - - id: black - repo: local hooks: - id: clang-format @@ -17,14 +13,14 @@ repos: exclude: (tests/(datamodel|src|extra_code)/.*(h|cc)$|podioVersion.in.h) types: [c++] language: system - - id: pylint - name: pylint - entry: 'pylint --rcfile=.github/scripts/pylint.rc --msg-template="{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}"' + - id: ruff + name: ruff + entry: ruff check --force-exclude types: [python] language: system - - id: flake8 - name: flake8 - entry: 'flake8 --config=.flake8' + - id: ruff-format + name: ruff-format + entry: ruff format --force-exclude types: [python] language: system - id: cppcheck diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 000000000..52659c7fa --- /dev/null +++ b/.ruff.toml @@ -0,0 +1,16 @@ +target-version = "py310" + +line-length = 99 + +[format] +# Make things format the same way as black +quote-style = "double" +indent-style = "space" +skip-magic-trailing-comma = false +line-ending = "auto" + +[lint] +select = ["F", "E", "W", "PLE", "PLW", "PLC"] + +[lint.per-file-ignores] +"python/podio_gen/test_MemberParser.py" = ["E501"] diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 466e9b9cc..000000000 --- a/pyproject.toml +++ /dev/null @@ -1,3 +0,0 @@ -[tool.black] -line-length = 99 -target-version = ["py310"] diff --git a/python/podio/arrow_io.py b/python/podio/arrow_io.py index 1f7a31e5e..33b16233e 100644 --- a/python/podio/arrow_io.py +++ b/python/podio/arrow_io.py @@ -4,10 +4,10 @@ from ROOT import gSystem if gSystem.DynamicPathName("libpodioArrow.so", True): - gSystem.Load("libpodioArrow") # noqa: 402 + gSystem.Load("libpodioArrow") # noqa: E402 else: raise ImportError("Error when importing libpodioArrow") -from ROOT import podio # noqa: 402 # pylint: disable=wrong-import-position +from ROOT import podio # noqa: E402 # pylint: disable=wrong-import-position from podio.base_reader import BaseReaderMixin # pylint: disable=wrong-import-position from podio.base_writer import BaseWriterMixin # pylint: disable=wrong-import-position diff --git a/python/podio/frame.py b/python/podio/frame.py index 55eb24c36..2fe5363fd 100644 --- a/python/podio/frame.py +++ b/python/podio/frame.py @@ -346,7 +346,7 @@ def _get_param_keys_types(self): for key in keys: # Make sure to convert to a python string here to not have a dangling # reference here for the key. - key = str(key) + key = str(key) # noqa: PLW2901 # In order to support the use case of having the same key for multiple # types create a list of available types for the key, so that we can # disambiguate later. Storing a vector here, and check later how diff --git a/python/podio/sio_io.py b/python/podio/sio_io.py index 9926b33ff..144893500 100644 --- a/python/podio/sio_io.py +++ b/python/podio/sio_io.py @@ -4,10 +4,10 @@ from ROOT import gSystem if gSystem.DynamicPathName("libpodioSioIO.so", True): - gSystem.Load("libpodioSioIO") # noqa: 402 + gSystem.Load("libpodioSioIO") # noqa: E402 else: raise ImportError("Error when importing libpodioSioIO") -from ROOT import podio # noqa: 402 # pylint: disable=wrong-import-position +from ROOT import podio # noqa: E402 # pylint: disable=wrong-import-position from podio.base_reader import BaseReaderMixin # pylint: disable=wrong-import-position from podio.base_writer import BaseWriterMixin # pylint: disable=wrong-import-position diff --git a/python/podio/test_ReaderSio.py b/python/podio/test_ReaderSio.py index c879dad00..1dcc52624 100644 --- a/python/podio/test_ReaderSio.py +++ b/python/podio/test_ReaderSio.py @@ -17,7 +17,7 @@ class SioReaderTestCase(ReaderTestCaseMixin, unittest.TestCase): def setUp(self): """Setup the corresponding reader""" - from podio.sio_io import Reader # pylint: disable=import-outside-toplevel + from podio.sio_io import Reader # noqa: PLC0415 self.reader = Reader("sio_io/example_frame.sio") @@ -28,6 +28,6 @@ class SIOLegacyReaderTestCase(LegacyReaderTestCaseMixin, unittest.TestCase): def setUp(self): """Setup a reader, reading from the example files""" - from podio.sio_io import LegacyReader # pylint: disable=import-outside-toplevel + from podio.sio_io import LegacyReader # noqa: PLC0415 self.reader = LegacyReader(get_legacy_input("v00-16-06-example.sio")) diff --git a/python/podio_gen/julia_generator.py b/python/podio_gen/julia_generator.py index e96ceb0ab..7ee8c36fc 100644 --- a/python/podio_gen/julia_generator.py +++ b/python/podio_gen/julia_generator.py @@ -143,7 +143,7 @@ def _sort_components_and_datatypes(data): sorted_components.append(bare_types_mapping[component]) for deps in dependencies.values(): - deps -= ready + deps -= ready # noqa: PLW2901 # Return the Sorted Components (bare_types) return sorted_components diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index d3ed949da..000000000 --- a/setup.cfg +++ /dev/null @@ -1,38 +0,0 @@ -[pycodestyle] -max-line-length = 120 -ignore = - # indent is not a multiple of four - E111, - # indent is not a multiple of four - E114, - #continuation line with same indent as next logical line - E125, - # module level import not at the top - E402, - -hang_closing=true - -[pep8] -indent_size=2 - -[flake8] -exclude = .git,__pycache__,old,build,dist -ignore = - # indentation is not a multiple of 4 - E111, - # indentation is not a multiple of 4 (comment) - E114, - # closing bracket does not match visual indentation - E124, - # continuation line with same indent as next logical line - E125, - # continuation line over-indented for visual indent - E127, - # line break before binary operator - W503, - # module level import not at the top - E402, - -max-line-length=120 -hang_closing=true - diff --git a/tools/podio-dump-legacy b/tools/podio-dump-legacy index 07be68a13..963374e15 100755 --- a/tools/podio-dump-legacy +++ b/tools/podio-dump-legacy @@ -119,7 +119,7 @@ def dump_model(reader, model_name): def main(args): """Main""" - from podio.reading import get_reader # pylint: disable=import-outside-toplevel + from podio.reading import get_reader # noqa: PLC0415 try: reader = get_reader(args.inputfile) From 9d1a60e9a6e64924b722703c9ea64485c08f5712 Mon Sep 17 00:00:00 2001 From: mohitt31 Date: Wed, 9 Sep 2026 15:07:43 +0530 Subject: [PATCH 2/4] Reformat with ruff format Formatting only, no functional change. podio pinned black 23.11.0 while ruff format follows the newer black style, so a handful of files change in the blank line after a module docstring, joined implicit f-string concatenation, parenthesised right hand sides and spacing inside f-string expressions. --- python/podio/base_reader.py | 1 - python/podio/test_strace.py | 1 - python/podio_gen/podio_config_reader.py | 2 +- python/podio_gen/test_ClassDefinitionValidator.py | 12 ++++++------ tools/podio-vis | 2 +- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/python/podio/base_reader.py b/python/podio/base_reader.py index d834c1922..c942262da 100644 --- a/python/podio/base_reader.py +++ b/python/podio/base_reader.py @@ -2,7 +2,6 @@ """Python module for defining the basic reader interface that is used by the backend specific bindings""" - from podio.frame_iterator import FrameCategoryIterator diff --git a/python/podio/test_strace.py b/python/podio/test_strace.py index 03dd4afed..95753baa3 100644 --- a/python/podio/test_strace.py +++ b/python/podio/test_strace.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 """Create objects and collections to test strace output""" - from ROOT import ExampleHitCollection, ExampleHit, TestLink, TestLinkCollection, nsp import podio diff --git a/python/podio_gen/podio_config_reader.py b/python/podio_gen/podio_config_reader.py index 928f5a3c2..ff4657851 100644 --- a/python/podio_gen/podio_config_reader.py +++ b/python/podio_gen/podio_config_reader.py @@ -393,7 +393,7 @@ def _check_keys(cls, classname, definition): invalid_keys = [k for k in extracode if k not in cls.valid_extra_code_keys] if invalid_keys: raise DefinitionError( - f"{classname} defines invalid 'ExtraCode' categories: " f"{invalid_keys}" + f"{classname} defines invalid 'ExtraCode' categories: {invalid_keys}" ) @classmethod diff --git a/python/podio_gen/test_ClassDefinitionValidator.py b/python/podio_gen/test_ClassDefinitionValidator.py index 268c3c05b..4a6f352b7 100644 --- a/python/podio_gen/test_ClassDefinitionValidator.py +++ b/python/podio_gen/test_ClassDefinitionValidator.py @@ -103,9 +103,9 @@ def _assert_no_exception(self, exceptions, message, func, *args, **kwargs): def test_component_invalid_extra_code(self): component = deepcopy(self.valid_component) - component["Component"]["ExtraCode"][ - "const_declaration" - ] = "// not even valid c++ passes here" + component["Component"]["ExtraCode"]["const_declaration"] = ( + "// not even valid c++ passes here" + ) with self.assertRaises(DefinitionError): self.validate(make_dm(component, {}), False) @@ -216,9 +216,9 @@ def test_datatype_invalid_definitions(self): self.validate(make_dm({}, datatype), False) datatype = deepcopy(self.valid_datatype) - datatype["DataType"]["ExtraCode"][ - "invalid_extracode" - ] = "an invalid entry to the ExtraCode" + datatype["DataType"]["ExtraCode"]["invalid_extracode"] = ( + "an invalid entry to the ExtraCode" + ) with self.assertRaises(DefinitionError): self.validate(make_dm({}, datatype), False) diff --git a/tools/podio-vis b/tools/podio-vis index 8374a4a27..9f81e96ba 100755 --- a/tools/podio-vis +++ b/tools/podio-vis @@ -40,7 +40,7 @@ class ModelToGraphviz: # It doesn't matter if they are remade latter so we don't need # to check for that for i, (label, group) in enumerate(self.graph_conf.items()): - with self.graph.subgraph(name=f"cluster{i+1}") as subgraph: + with self.graph.subgraph(name=f"cluster{i + 1}") as subgraph: subgraph.attr(label=label) for name in group: if name in self.remove: From c2f7382f0258fc929ea2b248d6ceb409e8058469 Mon Sep 17 00:00:00 2001 From: mohitt31 Date: Wed, 9 Sep 2026 20:25:15 +0530 Subject: [PATCH 3/4] Move force-exclude into the ruff configuration It applies to both hooks and ruff documents it as the setting to use with pre-commit, so it belongs in .ruff.toml rather than being repeated in each hook entry. --- .pre-commit-config.yaml | 4 ++-- .ruff.toml | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fcd834160..6706c0f8c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,12 +15,12 @@ repos: language: system - id: ruff name: ruff - entry: ruff check --force-exclude + entry: ruff check types: [python] language: system - id: ruff-format name: ruff-format - entry: ruff format --force-exclude + entry: ruff format types: [python] language: system - id: cppcheck diff --git a/.ruff.toml b/.ruff.toml index 52659c7fa..3929b7577 100644 --- a/.ruff.toml +++ b/.ruff.toml @@ -2,6 +2,9 @@ target-version = "py310" line-length = 99 +# Respect the excludes even for the files pre-commit passes in explicitly. +force-exclude = true + [format] # Make things format the same way as black quote-style = "double" From 1a10f392ff4d662bc7f740a377fae25656eca91c Mon Sep 17 00:00:00 2001 From: mohitt31 Date: Wed, 9 Sep 2026 20:25:15 +0530 Subject: [PATCH 4/4] Drop the pylint suppressions Nothing runs pylint any more, so the disable comments are dead. Where a line also carried a noqa that ruff still needs, only the pylint part is removed. A couple of the standalone ones had a useful explanation next to them, which is kept as a plain comment. The reflow in a handful of files is ruff format reacting to the shorter lines. --- doc/conf.py | 2 -- python/podio/arrow_io.py | 8 ++++---- python/podio/base_writer.py | 3 +-- python/podio/data_source.py | 2 +- python/podio/frame.py | 3 +-- python/podio/frame_iterator.py | 2 +- python/podio/link_navigator.py | 3 +-- python/podio/root_io.py | 8 ++++---- python/podio/sio_io.py | 8 ++++---- python/podio/test_Frame.py | 1 - python/podio/test_Pythonizations.py | 2 +- python/podio/test_ReaderRoot.py | 1 - python/podio/test_ReaderSio.py | 1 - python/podio/version.py | 4 ++-- python/podio_class_generator.py | 3 --- python/podio_gen/cpp_generator.py | 8 ++++---- python/podio_gen/generator_base.py | 2 +- python/podio_gen/generator_utils.py | 4 ++-- python/podio_gen/podio_config_reader.py | 3 --- python/podio_gen/test_ClassDefinitionValidator.py | 2 +- python/podio_gen/test_MemberParser.py | 3 +-- tests/root_io/read_datasource.py | 2 +- tests/write_empty_collections.py | 6 +++--- tests/write_frame.py | 4 ++-- tools/podio-dump-legacy | 3 +-- tools/podio-merge-files | 12 ++++++------ 26 files changed, 42 insertions(+), 58 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 9920540ad..4b5d137fb 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -1,5 +1,3 @@ -# pylint: disable=invalid-name, redefined-builtin, missing-module-docstring - # Configuration file for the Sphinx documentation builder. # # This file only contains a selection of the most common options. For a full diff --git a/python/podio/arrow_io.py b/python/podio/arrow_io.py index 33b16233e..7ec0ebd78 100644 --- a/python/podio/arrow_io.py +++ b/python/podio/arrow_io.py @@ -7,11 +7,11 @@ gSystem.Load("libpodioArrow") # noqa: E402 else: raise ImportError("Error when importing libpodioArrow") -from ROOT import podio # noqa: E402 # pylint: disable=wrong-import-position +from ROOT import podio # noqa: E402 -from podio.base_reader import BaseReaderMixin # pylint: disable=wrong-import-position -from podio.base_writer import BaseWriterMixin # pylint: disable=wrong-import-position -from podio.utils import convert_to_str_paths # pylint: disable=wrong-import-position # noqa: E402 +from podio.base_reader import BaseReaderMixin +from podio.base_writer import BaseWriterMixin +from podio.utils import convert_to_str_paths # noqa: E402 class Reader(BaseReaderMixin): diff --git a/python/podio/base_writer.py b/python/podio/base_writer.py index fff5e6825..a90bf337e 100644 --- a/python/podio/base_writer.py +++ b/python/podio/base_writer.py @@ -52,7 +52,6 @@ def write_frame(self, frame, category, collections=None): collections (optional, default=None): The subset of collections to write. If None, all collections are written """ - # pylint: disable=protected-access args = [frame._frame, category] if collections is not None: args.append(collections) @@ -60,4 +59,4 @@ def write_frame(self, frame, category, collections=None): def finish(self): """Finish writing and flush all data to the output file.""" - self._writer.finish() # pylint: disable=protected-access + self._writer.finish() diff --git a/python/podio/data_source.py b/python/podio/data_source.py index 157c94781..4fc19e81c 100644 --- a/python/podio/data_source.py +++ b/python/podio/data_source.py @@ -8,6 +8,6 @@ ): raise ImportError("Error when loading libpodioDataSourceDict") -from ROOT import podio # pylint: disable=wrong-import-position +from ROOT import podio CreateDataFrame = podio.CreateDataFrame diff --git a/python/podio/frame.py b/python/podio/frame.py index 2fe5363fd..b21e04bc4 100644 --- a/python/podio/frame.py +++ b/python/podio/frame.py @@ -12,7 +12,7 @@ # We check whether we can actually load the header to not break python bindings # in environments with *ancient* podio versions if ROOT.gInterpreter.LoadFile("podio/Frame.h") == 0: # noqa: E402 - from ROOT import podio # noqa: E402 # pylint: disable=wrong-import-position + from ROOT import podio # noqa: E402 else: raise ImportError( "Could not load podio/Frame.h. Make sure it is available on ROOT_INCLUDE_PATH." @@ -173,7 +173,6 @@ def put(self, collection, name): # first one will throw an invalid_argument (as expected), which then # makes cppyy try the second one which fails with a type conversion. # Hence we catch the TypeError here and return a ValueError. - # pylint: disable-next=raise-missing-from raise ValueError(f"An object with key {name} already exists in the Frame") @property diff --git a/python/podio/frame_iterator.py b/python/podio/frame_iterator.py index 2ba11960b..371ce2efe 100644 --- a/python/podio/frame_iterator.py +++ b/python/podio/frame_iterator.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """Module defining the Frame iterator used by the Reader interface""" -# pylint: disable-next=import-error # gbl is a dynamic module from cppyy +# gbl is a dynamic module from cppyy from cppyy.gbl import std from podio.frame import Frame diff --git a/python/podio/link_navigator.py b/python/podio/link_navigator.py index d9590eab0..2777785bc 100644 --- a/python/podio/link_navigator.py +++ b/python/podio/link_navigator.py @@ -9,10 +9,9 @@ "Could not load podio/LinkNavigator.h. Make sure it is available on ROOT_INCLUDE_PATH." ) -from ROOT import podio # noqa: E402 # pylint: disable=wrong-import-position +from ROOT import podio # noqa: E402 -# pylint: disable-next=invalid-name def LinkNavigator(link_collection): """Create a LinkNavigator for the given LinkCollection. diff --git a/python/podio/root_io.py b/python/podio/root_io.py index 95702f086..6f484ba26 100644 --- a/python/podio/root_io.py +++ b/python/podio/root_io.py @@ -4,11 +4,11 @@ from ROOT import gSystem gSystem.Load("libpodioRootIO") # noqa: E402 -from ROOT import podio # noqa: E402 # pylint: disable=wrong-import-position +from ROOT import podio # noqa: E402 -from podio.base_reader import BaseReaderMixin # pylint: disable=wrong-import-position # noqa: E402 -from podio.base_writer import BaseWriterMixin # pylint: disable=wrong-import-position # noqa: E402 -from podio.utils import convert_to_str_paths # pylint: disable=wrong-import-position # noqa: E402 +from podio.base_reader import BaseReaderMixin # noqa: E402 +from podio.base_writer import BaseWriterMixin # noqa: E402 +from podio.utils import convert_to_str_paths # noqa: E402 class Reader(BaseReaderMixin): diff --git a/python/podio/sio_io.py b/python/podio/sio_io.py index 144893500..68cd3b835 100644 --- a/python/podio/sio_io.py +++ b/python/podio/sio_io.py @@ -7,11 +7,11 @@ gSystem.Load("libpodioSioIO") # noqa: E402 else: raise ImportError("Error when importing libpodioSioIO") -from ROOT import podio # noqa: E402 # pylint: disable=wrong-import-position +from ROOT import podio # noqa: E402 -from podio.base_reader import BaseReaderMixin # pylint: disable=wrong-import-position -from podio.base_writer import BaseWriterMixin # pylint: disable=wrong-import-position -from podio.utils import convert_to_str_paths # pylint: disable=wrong-import-position # noqa: E402 +from podio.base_reader import BaseReaderMixin +from podio.base_writer import BaseWriterMixin +from podio.utils import convert_to_str_paths # noqa: E402 class Reader(BaseReaderMixin): diff --git a/python/podio/test_Frame.py b/python/podio/test_Frame.py index 3633364c6..2f85ddc63 100644 --- a/python/podio/test_Frame.py +++ b/python/podio/test_Frame.py @@ -3,7 +3,6 @@ import unittest -# pylint: disable=import-error from ROOT import ExampleHitCollection from podio.frame import Frame diff --git a/python/podio/test_Pythonizations.py b/python/podio/test_Pythonizations.py index 97b6ceea5..27926cfd1 100644 --- a/python/podio/test_Pythonizations.py +++ b/python/podio/test_Pythonizations.py @@ -3,7 +3,7 @@ import unittest from ROOT import ex2 -from pythonizations import load_pythonizations # pylint: disable=import-error +from pythonizations import load_pythonizations # load all available pythonizations to the classes in a namespace # loading pythonizations changes the state of cppyy backend shared by all the tests in a process diff --git a/python/podio/test_ReaderRoot.py b/python/podio/test_ReaderRoot.py index bfa8b0b7e..44a08417a 100644 --- a/python/podio/test_ReaderRoot.py +++ b/python/podio/test_ReaderRoot.py @@ -3,7 +3,6 @@ import unittest -# pylint: disable-next=import-error from test_Reader import ( ReaderTestCaseMixin, LegacyReaderTestCaseMixin, diff --git a/python/podio/test_ReaderSio.py b/python/podio/test_ReaderSio.py index 1dcc52624..15e4fea80 100644 --- a/python/podio/test_ReaderSio.py +++ b/python/podio/test_ReaderSio.py @@ -3,7 +3,6 @@ import unittest -# pylint: disable-next=import-error from test_Reader import ( ReaderTestCaseMixin, LegacyReaderTestCaseMixin, diff --git a/python/podio/version.py b/python/podio/version.py index 6b8077896..302f388df 100644 --- a/python/podio/version.py +++ b/python/podio/version.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """Module that facilitates working with the podio::version::Version""" -from podio import __version__ # pylint: disable=wrong-import-order +from podio import __version__ import ROOT @@ -9,7 +9,7 @@ if ROOT.gInterpreter.LoadFile("podio/podioVersion.h") != 0: # noqa: E402 raise ImportError("Cannot find the podio/podioVersion.h header") -from ROOT import podio # noqa: E402 # pylint: disable=wrong-import-position +from ROOT import podio # noqa: E402 Version = podio.version.Version diff --git a/python/podio_class_generator.py b/python/podio_class_generator.py index 7b082dd70..9764646a1 100755 --- a/python/podio_class_generator.py +++ b/python/podio_class_generator.py @@ -88,7 +88,6 @@ def parse_version(version_str): if __name__ == "__main__": - # pylint: disable=invalid-name # before 2.5.0 pylint is too strict with the naming here parser = argparse.ArgumentParser( description="Given a description yaml file this script generates " "the necessary c++ or julia files in the target directory" @@ -204,5 +203,3 @@ def parse_version(version_str): gen.formatter_func = clang_format_file gen.process() - - # pylint: enable=invalid-name diff --git a/python/podio_gen/cpp_generator.py b/python/podio_gen/cpp_generator.py index 01c2b6545..0bc24f395 100644 --- a/python/podio_gen/cpp_generator.py +++ b/python/podio_gen/cpp_generator.py @@ -121,7 +121,7 @@ class IncludeFrom(IntEnum): class CPPClassGenerator(ClassGeneratorBaseMixin): """The c++ class / code generator for podio""" - def __init__( # pylint: disable=too-many-arguments + def __init__( self, yamlfile, install_dir, @@ -461,7 +461,7 @@ def _preprocess_for_class(self, datatype): includes.add(self._build_include(vectormember)) includes.update(datatype.get("ExtraCode", {}).get("includes", "").split("\n")) - # TODO: in principle only the mutable classes need these includes! # pylint: disable=fixme + # TODO: in principle only the mutable classes need these includes! includes.update(datatype.get("MutableExtraCode", {}).get("includes", "").split("\n")) # When we have a relation to the same type we have the header that we are @@ -549,7 +549,7 @@ def _preprocess_for_collection(self, datatype): # the ostream operator needs a bit of help from the python side in the form # of some pre processing but also in the form of formatting, both are done # here. - # TODO: handle array members properly. These are currently ignored # pylint: disable=fixme + # TODO: handle array members properly. These are currently ignored header_contents = [] for member in datatype["Members"]: header = {"name": member.name} @@ -696,7 +696,7 @@ def _read_old_schemas(self): old_datamodels[old_schema_version] = comparison_results.old_datamodel # Store old definitions for items that have actually changed - # TODO: Move this somewher else? # pylint: disable=fixme + # TODO: Move this somewher else? for change in comparison_results.schema_changes: if hasattr(change, "klassname"): # Handle components (both existing and removed) diff --git a/python/podio_gen/generator_base.py b/python/podio_gen/generator_base.py index e70b5fc61..c9919fa41 100644 --- a/python/podio_gen/generator_base.py +++ b/python/podio_gen/generator_base.py @@ -293,7 +293,7 @@ def _write_file(self, name, content): if not self.dryrun: self.generated_files.append(fullname) if self.formatter_func is not None: - content = self.formatter_func(content, fullname) # pylint: disable=not-callable + content = self.formatter_func(content, fullname) changed = write_file_if_changed(fullname, content) self.any_changes = changed or self.any_changes diff --git a/python/podio_gen/generator_utils.py b/python/podio_gen/generator_utils.py index 327a1584c..3af3ac429 100644 --- a/python/podio_gen/generator_utils.py +++ b/python/podio_gen/generator_utils.py @@ -336,7 +336,7 @@ def _to_json(self): return f"{self.full_type} {self.name}{def_val}{unit}{description}" -class DataModel: # pylint: disable=too-few-public-methods +class DataModel: """A class for holding a complete datamodel read from a configuration file""" def __init__( @@ -383,6 +383,6 @@ def default(self, o): """The override for the default, first trying to call _to_json, otherwise handing off to the default JSONEncoder""" try: - return o._to_json() # pylint: disable=protected-access + return o._to_json() except AttributeError: return super().default(o) diff --git a/python/podio_gen/podio_config_reader.py b/python/podio_gen/podio_config_reader.py index ff4657851..0061b2349 100644 --- a/python/podio_gen/podio_config_reader.py +++ b/python/podio_gen/podio_config_reader.py @@ -130,7 +130,6 @@ def parse(self, string, require_description=True): # check whether we could parse this if we don't require a description and # provide more details in the error if we can self._parse_with_regexps(string, no_desc_matchers_cbs) - # pylint: disable-next=raise-missing-from raise DefinitionError( f"'{string}' is not a valid member definition. " "Description comment is missing.\n" @@ -567,10 +566,8 @@ def parse_model( f"schema_version has to be larger than 0 (is {schema_version})" ) except KeyError: - # pylint: disable-next=raise-missing-from raise DefinitionError("Please provide a 'schema_version' in your definition") except ValueError: - # pylint: disable-next=raise-missing-from raise DefinitionError( f"schema_version has to be convertible to int (is {model_dict['schema_version']})" ) diff --git a/python/podio_gen/test_ClassDefinitionValidator.py b/python/podio_gen/test_ClassDefinitionValidator.py index 4a6f352b7..c82476558 100644 --- a/python/podio_gen/test_ClassDefinitionValidator.py +++ b/python/podio_gen/test_ClassDefinitionValidator.py @@ -22,7 +22,7 @@ def make_dm(components, datatypes, interfaces=None, links=None, options=None): return DataModel(datatypes, components, interfaces, links, options) -class ClassDefinitionValidatorTest(unittest.TestCase): # pylint: disable=too-many-public-methods +class ClassDefinitionValidatorTest(unittest.TestCase): """Unit tests for the ClassDefinitionValidator""" def setUp(self): diff --git a/python/podio_gen/test_MemberParser.py b/python/podio_gen/test_MemberParser.py index f2e3fa7b0..05d275c90 100644 --- a/python/podio_gen/test_MemberParser.py +++ b/python/podio_gen/test_MemberParser.py @@ -12,7 +12,7 @@ class MemberParserTest(unittest.TestCase): """Unit tests for the MemberParser""" - def test_parse_valid(self): # pylint: disable=too-many-statements + def test_parse_valid(self): """Test if valid member definitions pass""" parser = MemberParser() @@ -241,7 +241,6 @@ def test_parse_invalid(self): try: self.assertRaises(DefinitionError, parser.parse, inp) except AssertionError: - # pylint: disable-next=raise-missing-from raise AssertionError( f"'{inp}' should raise a DefinitionError from the MemberParser" ) diff --git a/tests/root_io/read_datasource.py b/tests/root_io/read_datasource.py index b8528568d..cefe27550 100644 --- a/tests/root_io/read_datasource.py +++ b/tests/root_io/read_datasource.py @@ -2,7 +2,7 @@ """Small test case for checking DataSource based creating RDataFrames is accessible from python""" import ROOT -from podio.data_source import CreateDataFrame # pylint: disable=import-error, no-name-in-module +from podio.data_source import CreateDataFrame if ROOT.gSystem.Load("libTestDataModelDict") < 0: raise RuntimeError("Could not load TestDataModel dictionary") diff --git a/tests/write_empty_collections.py b/tests/write_empty_collections.py index 6086de9e4..5f3d061a7 100644 --- a/tests/write_empty_collections.py +++ b/tests/write_empty_collections.py @@ -13,9 +13,9 @@ if ROOT.gSystem.Load("libTestDataModelDict") < 0: # type: ignore[attr-defined] raise RuntimeError("Could not load TestDataModel dictionary") -from ROOT import ExampleHitCollection # pylint: disable=wrong-import-position +from ROOT import ExampleHitCollection -from podio import Frame, reading, root_io # pylint: disable=wrong-import-position +from podio import Frame, reading, root_io def create_frame(): @@ -60,7 +60,7 @@ def write_file(filename): # The important part: explicitly pass an empty list writer.write_frame(frame, "events", []) - writer._writer.finish() # pylint: disable=protected-access + writer._writer.finish() # Use the standard (TTree) reader inference and validate contents. reader = reading.get_reader(filename) diff --git a/tests/write_frame.py b/tests/write_frame.py index 95b02f9a2..a20a57c3c 100644 --- a/tests/write_frame.py +++ b/tests/write_frame.py @@ -9,7 +9,7 @@ if ROOT.gSystem.Load("libTestDataModelDict") < 0: # noqa: E402 raise RuntimeError("Could not load TestDataModel dictionary") -from ROOT import ( # pylint: disable=wrong-import-position +from ROOT import ( ExampleHitCollection, ExampleClusterCollection, TestLinkCollection, @@ -17,7 +17,7 @@ TypeWithEnergy, ) # noqa: E402 -from podio import Frame # pylint: disable=wrong-import-position +from podio import Frame def create_hit_collection(): diff --git a/tools/podio-dump-legacy b/tools/podio-dump-legacy index 963374e15..47349c522 100755 --- a/tools/podio-dump-legacy +++ b/tools/podio-dump-legacy @@ -94,7 +94,7 @@ def print_frame(frame, cat_name, ientry, detailed): ientry (int): The entry number of this Frame detailed (bool): Print just an overview or dump the whole contents """ - print("{:#^82}".format(f" {cat_name}: {ientry} ")) # pylint: disable=consider-using-f-string + print("{:#^82}".format(f" {cat_name}: {ientry} ")) if detailed: print_frame_detailed(frame) @@ -174,7 +174,6 @@ if __name__ == "__main__": " version files." ) - # pylint: disable=invalid-name # before 2.5.0 pylint is too strict with the naming here parser = argparse.ArgumentParser( description="Dump contents of a podio file to stdout.", epilog=_EPILOG ) diff --git a/tools/podio-merge-files b/tools/podio-merge-files index c0e35ad7c..98e785f13 100755 --- a/tools/podio-merge-files +++ b/tools/podio-merge-files @@ -30,8 +30,8 @@ parser.add_argument( args = parser.parse_args() # Import podio later for quick help messages -import podio # pylint: disable=wrong-import-position # noqa: E402 -from podio.root_merge import merge_files # pylint: disable=wrong-import-position # noqa: E402 +import podio # noqa: E402 +from podio.root_merge import merge_files # noqa: E402 all_files = set() for f in args.files: @@ -45,19 +45,19 @@ if first.endswith(".root"): merge_files(args.files, args.output_file, metadata=args.metadata, compression=args.compression) elif first.endswith(".sio"): # Slow path: frame-by-frame copy - from podio import reading # pylint: disable=wrong-import-position # noqa: E402 - from podio import sio_io # pylint: disable=wrong-import-position # noqa: E402 + from podio import reading # noqa: E402 + from podio import sio_io # noqa: E402 reader = reading.get_reader(args.files) writer = sio_io.Writer(args.output_file) categories = list(reader.categories) - is_metadata_available = True # pylint: disable=invalid-name + is_metadata_available = True try: # All frames will be copied as they are except the metadata ones categories.remove("metadata") except ValueError: - is_metadata_available = False # pylint: disable=invalid-name + is_metadata_available = False for category in tqdm(categories): all_frames = reader.get(category)