Skip to content

Commit 430e55a

Browse files
chore: use ruff with ruff.toml file (#594)
* feat: Introducing Ruff config, removing .flake8, updating pre-commit-config * feat: Adding ruff-format hook to pre-commit, updating fixed files * feat: Adding linting rules to Ruff config, updating fixed file * feat: Extending Ruff linting rules list, updating fixed files * feat: Reverting change breaking doc build, updating ignored linting rules * Apply suggestions from code review Co-authored-by: Sébastien Morais <[email protected]> * feat: Updating pyansys_logging and ruff config based on review comments * Update doc/source/how-to/code/test_pyansys_logging.py Co-authored-by: Sébastien Morais <[email protected]> * feat: Removing ignored rules from ruff config and updating files accordingly * Update doc/source/how-to/code/test_pyansys_logging.py --------- Co-authored-by: Sébastien Morais <[email protected]>
1 parent 3d31419 commit 430e55a

File tree

8 files changed

+75
-74
lines changed

8 files changed

+75
-74
lines changed

.flake8

Lines changed: 0 additions & 7 deletions
This file was deleted.

.github/labeler.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ documentation:
33
- any-glob-to-any-file: ['doc/source/**/*']
44
maintenance:
55
- changed-files:
6-
- any-glob-to-any-file: ['.github/**/*', '.flake8', 'pyproject.toml', 'docker/**/*']
6+
- any-glob-to-any-file: ['.github/**/*', 'ruff.toml', 'pyproject.toml', 'docker/**/*']
77
dependencies:
88
- changed-files:
99
- any-glob-to-any-file: ['requirements/*']

.pre-commit-config.yaml

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,18 @@
11
repos:
22

33

4-
- repo: https://github.com/psf/black
5-
rev: 25.1.0 # IF VERSION CHANGES --> MODIFY "blacken-docs" MANUALLY AS WELL!!
4+
- repo: https://github.com/astral-sh/ruff-pre-commit
5+
rev: v0.11.8
66
hooks:
7-
- id: black
8-
args: [
9-
"doc/source/conf.py",
10-
"examples"
11-
]
7+
- id: ruff
8+
- id: ruff-format
129

1310
- repo: https://github.com/adamchainz/blacken-docs
1411
rev: 1.19.1
1512
hooks:
1613
- id: blacken-docs
1714
additional_dependencies: [black==24.8.0]
1815

19-
- repo: https://github.com/pycqa/isort
20-
rev: 6.0.1
21-
hooks:
22-
- id: isort
23-
args: [
24-
"--profile", "black",
25-
"--force-sort-within-sections",
26-
"--line-length", "100",
27-
]
28-
29-
- repo: https://github.com/PyCQA/flake8
30-
rev: 7.2.0
31-
hooks:
32-
- id: flake8
33-
3416
- repo: https://github.com/codespell-project/codespell
3517
rev: v2.4.1
3618
hooks:

doc/source/doc-style/code/sample_func.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
def func(arg1, arg2):
1+
def func(arg1, arg2): # noqa: D100
22
"""Summary line <should be only one line>.
33
44
Extended description of the function. The extended description,
@@ -25,7 +25,7 @@ def func(arg1, arg2):
2525
2626
Examples
2727
--------
28-
>>> func(1, 'foo')
28+
>>> func(1, "foo")
2929
True
3030
3131
"""

doc/source/how-to/code/pyansys_logging.py

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Module for PyAnsys logging."""
2+
13
from copy import copy
24
from datetime import datetime
35
import logging
@@ -10,9 +12,7 @@
1012

1113

1214
# Formatting
13-
STDOUT_MSG_FORMAT = (
14-
"%(levelname)s - %(instance_name)s - %(module)s - %(funcName)s - %(message)s"
15-
)
15+
STDOUT_MSG_FORMAT = "%(levelname)s - %(instance_name)s - %(module)s - %(funcName)s - %(message)s"
1616
FILE_MSG_FORMAT = STDOUT_MSG_FORMAT
1717

1818
DEFAULT_STDOUT_HEADER = """
@@ -59,6 +59,7 @@ def __init__(self, logger, extra=None):
5959
self.std_out_handler = logger.std_out_handler
6060

6161
def process(self, msg, kwargs):
62+
"""Get instance_name for logging."""
6263
kwargs["extra"] = {}
6364
# These are the extra parameters sent to log
6465
# here self.extra is the argument pass to the log records.
@@ -77,7 +78,6 @@ def log_to_file(self, filename=FILE_NAME, level=LOG_LEVEL):
7778
Level of logging, for example ``'DEBUG'``. By default
7879
``logging.DEBUG``.
7980
"""
80-
8181
self.logger = add_file_handler(
8282
self.logger, filename=filename, level=level, write_headers=True
8383
)
@@ -106,6 +106,8 @@ def setLevel(self, level="DEBUG"):
106106

107107

108108
class PyAnsysPercentStyle(logging.PercentStyle):
109+
"""Log message formatting."""
110+
109111
def __init__(self, fmt, *, defaults=None):
110112
self._fmt = fmt or self.default_format
111113
self._defaults = defaults
@@ -154,6 +156,7 @@ class InstanceFilter(logging.Filter):
154156
"""Ensures that instance_name record always exists."""
155157

156158
def filter(self, record):
159+
"""If record had no attribute instance_name, create it and populate with empty string."""
157160
if not hasattr(record, "instance_name"):
158161
record.instance_name = ""
159162
return True
@@ -193,14 +196,11 @@ def __init__(
193196
cleanup=True,
194197
):
195198
"""Initialize Logger class."""
196-
197-
self.logger = logging.getLogger(
198-
"pyproject_global"
199-
) # Creating default main logger.
199+
self.logger = logging.getLogger("pyproject_global") # Creating default main logger.
200200
self.logger.addFilter(InstanceFilter())
201201
self.logger.setLevel(level)
202202
self.logger.propagate = True
203-
self.level = self.logger.level # TODO: TO REMOVE
203+
self.level = self.logger.level # noqa: TD002, TD003 # TODO: TO REMOVE
204204

205205
# Writing logging methods.
206206
self.debug = self.logger.debug
@@ -233,10 +233,7 @@ def log_to_file(self, filename=FILE_NAME, level=LOG_LEVEL):
233233
level : str, optional
234234
Level of logging. E.x. 'DEBUG'. By default LOG_LEVEL
235235
"""
236-
237-
self = add_file_handler(
238-
self, filename=filename, level=level, write_headers=True
239-
)
236+
self = add_file_handler(self, filename=filename, level=level, write_headers=True)
240237

241238
def log_to_stdout(self, level=LOG_LEVEL):
242239
"""Add standard output handler to the logger.
@@ -246,7 +243,6 @@ def log_to_stdout(self, level=LOG_LEVEL):
246243
level : str, optional
247244
Level of logging record. By default LOG_LEVEL
248245
"""
249-
250246
self = add_stdout_handler(self, level=level)
251247

252248
def setLevel(self, level="DEBUG"):
@@ -333,9 +329,7 @@ def _add_product_instance_logger(self, name, product_instance, level):
333329
self._make_child_logger("NO_NAMED_YET", level), product_instance
334330
)
335331
else:
336-
raise TypeError(
337-
f"``name`` parameter must be a string or None, not f{type(name)}"
338-
)
332+
raise TypeError(f"``name`` parameter must be a string or None, not f{type(name)}")
339333

340334
return instance_logger
341335

@@ -379,21 +373,20 @@ def add_instance_logger(self, name, product_instance, level=None):
379373
return self._instances[new_name]
380374

381375
def __getitem__(self, key):
376+
"""Define custom KeyError message."""
382377
if key in self._instances.keys():
383378
return self._instances[key]
384379
else:
385380
raise KeyError(f"There are no instances with name {key}")
386381

387382
def add_handling_uncaught_expections(self, logger):
388-
"""This just redirects the output of an exception to the logger."""
383+
"""Redirect the output of an exception to the logger."""
389384

390385
def handle_exception(exc_type, exc_value, exc_traceback):
391386
if issubclass(exc_type, KeyboardInterrupt):
392387
sys.__excepthook__(exc_type, exc_value, exc_traceback)
393388
return
394-
logger.critical(
395-
"Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback)
396-
)
389+
logger.critical("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
397390

398391
sys.excepthook = handle_exception
399392

@@ -405,7 +398,7 @@ def __del__(self):
405398
for handler in self.logger.handlers:
406399
handler.close()
407400
self.logger.removeHandler(handler)
408-
except Exception as e:
401+
except Exception:
409402
try:
410403
if self.logger is not None:
411404
self.logger.error("The logger was not deleted properly.")
@@ -434,7 +427,6 @@ def add_file_handler(logger, filename=FILE_NAME, level=LOG_LEVEL, write_headers=
434427
logger
435428
Return the logger or Logger object.
436429
"""
437-
438430
file_handler = logging.FileHandler(filename)
439431
file_handler.setLevel(level)
440432
file_handler.setFormatter(logging.Formatter(FILE_MSG_FORMAT))
@@ -471,7 +463,6 @@ def add_stdout_handler(logger, level=LOG_LEVEL, write_headers=False):
471463
logger
472464
The logger or Logger object.
473465
"""
474-
475466
std_out_handler = logging.StreamHandler(sys.stdout)
476467
std_out_handler.setLevel(level)
477468
std_out_handler.setFormatter(PyProjectFormatter(STDOUT_MSG_FORMAT))

doc/source/how-to/code/test_pyansys_logging.py

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
"""Test for PyAnsys logging."""
2+
13
import io
24
import logging
3-
import os
5+
from pathlib import Path
46
import sys
57
import weakref
68

@@ -9,25 +11,24 @@
911

1012
def test_default_logger():
1113
"""Create a logger with default options.
12-
Only stdout logger must be used."""
1314
15+
Only stdout logger must be used.
16+
"""
1417
capture = CaptureStdOut()
1518
with capture:
1619
test_logger = pyansys_logging.Logger()
1720
test_logger.info("Test stdout")
1821

19-
assert (
20-
"INFO - - test_pyansys_logging - test_default_logger - Test stdout"
21-
in capture.content
22-
)
22+
assert "INFO - - test_pyansys_logging - test_default_logger - Test stdout" in capture.content
2323
# File handlers are not activated.
24-
assert os.path.exists(os.path.exists(os.path.join(os.getcwd(), "PyProject.log")))
24+
assert (Path.cwd() / "PyProject.log").exists()
2525

2626

2727
def test_level_stdout():
2828
"""Create a logger with default options.
29-
Only stdout logger must be used."""
3029
30+
Only stdout logger must be used.
31+
"""
3132
capture = CaptureStdOut()
3233
with capture:
3334
test_logger = pyansys_logging.Logger(level=logging.INFO)
@@ -85,34 +86,28 @@ def test_level_stdout():
8586
)
8687

8788
# File handlers are not activated.
88-
assert os.path.exists(os.path.exists(os.path.join(os.getcwd(), "PyProject.log")))
89+
assert (Path.cwd() / "PyProject.log").exists()
8990

9091

9192
def test_file_handlers(tmpdir):
9293
"""Activate a file handler different from `PyProject.log`."""
93-
9494
file_logger = tmpdir.mkdir("sub").join("test_logger.txt")
9595

9696
test_logger = pyansys_logging.Logger(to_file=True, filename=file_logger)
9797
test_logger.info("Test Misc File")
9898

99-
with open(file_logger, "r") as f:
99+
with Path.open(file_logger, "r") as f:
100100
content = f.readlines()
101101

102-
assert os.path.exists(
103-
file_logger
104-
) # The file handler is not the default PyProject.Log
102+
assert Path.exists(file_logger) # The file handler is not the default PyProject.Log
105103
assert len(content) == 6
106104
assert "NEW SESSION" in content[2]
107105
assert (
108106
"==============================================================================="
109107
in content[3]
110108
)
111109
assert "LEVEL - INSTANCE NAME - MODULE - FUNCTION - MESSAGE" in content[4]
112-
assert (
113-
"INFO - - test_pyansys_logging - test_file_handlers - Test Misc File"
114-
in content[5]
115-
)
110+
assert "INFO - - test_pyansys_logging - test_file_handlers - Test Misc File" in content[5]
116111

117112
# Delete the logger and its file handler.
118113
test_logger_ref = weakref.ref(test_logger)
@@ -127,9 +122,11 @@ def __init__(self):
127122
self._stream = io.StringIO()
128123

129124
def __enter__(self):
125+
"""Runtime context is entered."""
130126
sys.stdout = self._stream
131127

132128
def __exit__(self, type, value, traceback):
129+
"""Runtime context is exited."""
133130
sys.stdout = sys.__stdout__
134131

135132
@property

examples/pyvista_example.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121
# SOFTWARE.
2222

23+
# ruff: noqa: D400
2324
"""
2425
.. _adding_a_new_gallery_example:
2526

ruff.toml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
exclude = [
2+
"build",
3+
"doc/source/conf.py",
4+
]
5+
6+
line-length = 100
7+
8+
[format]
9+
quote-style = "double"
10+
indent-style = "space"
11+
docstring-code-format = true
12+
13+
[lint]
14+
select = [
15+
"D", # pydocstyle, see https://docs.astral.sh/ruff/rules/#pydocstyle-d
16+
"E", # pycodestyle, see https://docs.astral.sh/ruff/rules/#pycodestyle-e-w
17+
"F", # pyflakes, see https://docs.astral.sh/ruff/rules/#pyflakes-f
18+
"I", # isort, see https://docs.astral.sh/ruff/rules/#isort-i
19+
"N", # pep8-naming, see https://docs.astral.sh/ruff/rules/#pep8-naming-n
20+
"PTH", # flake8-use-pathlib, https://docs.astral.sh/ruff/rules/#flake8-use-pathlib-pth
21+
"TD", # flake8-todos, https://docs.astral.sh/ruff/rules/#flake8-todos-td
22+
"W", # pycodestyle, see https://docs.astral.sh/ruff/rules/#pycodestyle-e-w
23+
]
24+
ignore = []
25+
26+
[lint.pydocstyle]
27+
convention = "numpy"
28+
29+
[lint.isort]
30+
combine-as-imports = true
31+
force-sort-within-sections = true
32+
33+
[lint.mccabe]
34+
max-complexity = 10
35+
36+
[lint.pep8-naming]
37+
ignore-names = ["setLevel"]

0 commit comments

Comments
 (0)