Skip to content

Commit 34ff501

Browse files
Use ruff (#244)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent b445623 commit 34ff501

14 files changed

+126
-172
lines changed

.markdownlint.yaml

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

.pre-commit-config.yaml

Lines changed: 6 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,77 +2,31 @@ repos:
22
- repo: https://github.com/pre-commit/pre-commit-hooks
33
rev: v4.4.0
44
hooks:
5-
- id: check-ast
6-
- id: check-builtin-literals
7-
- id: check-docstring-first
8-
- id: check-merge-conflict
9-
- id: check-yaml
10-
- id: check-toml
11-
- id: debug-statements
125
- id: end-of-file-fixer
136
- id: trailing-whitespace
14-
- repo: https://github.com/asottile/add-trailing-comma
15-
rev: v2.4.0
7+
- repo: https://github.com/astral-sh/ruff-pre-commit
8+
rev: "v0.0.272"
169
hooks:
17-
- id: add-trailing-comma
18-
args: [--py36-plus]
19-
- repo: https://github.com/asottile/pyupgrade
20-
rev: v3.3.1
21-
hooks:
22-
- id: pyupgrade
23-
args: ["--py37-plus"]
24-
- repo: https://github.com/PyCQA/isort
25-
rev: 5.12.0
26-
hooks:
27-
- id: isort
10+
- id: ruff
11+
args: [--fix, --exit-non-zero-on-fix]
2812
- repo: https://github.com/psf/black
2913
rev: 23.3.0
3014
hooks:
3115
- id: black
32-
args: [--safe]
33-
- repo: https://github.com/asottile/blacken-docs
34-
rev: 1.13.0
35-
hooks:
36-
- id: blacken-docs
37-
additional_dependencies: [black==23.3]
38-
- repo: https://github.com/pre-commit/pygrep-hooks
39-
rev: v1.10.0
40-
hooks:
41-
- id: rst-backticks
4216
- repo: https://github.com/tox-dev/tox-ini-fmt
4317
rev: "1.3.0"
4418
hooks:
4519
- id: tox-ini-fmt
4620
args: ["-p", "fix"]
4721
- repo: https://github.com/tox-dev/pyproject-fmt
48-
rev: "0.9.2"
22+
rev: "0.11.2"
4923
hooks:
5024
- id: pyproject-fmt
51-
- repo: https://github.com/PyCQA/flake8
52-
rev: 6.0.0
53-
hooks:
54-
- id: flake8
55-
additional_dependencies:
56-
- flake8-bugbear==23.3.23
57-
- flake8-comprehensions==3.12
58-
- flake8-pytest-style==1.7.2
59-
- flake8-spellcheck==0.28
60-
- flake8-unused-arguments==0.0.13
61-
- flake8-noqa==1.3.1
62-
- pep8-naming==0.13.3
63-
- flake8-pyproject==1.2.3
6425
- repo: https://github.com/pre-commit/mirrors-prettier
65-
rev: "v2.7.1"
26+
rev: "v3.0.0-alpha.9-for-vscode"
6627
hooks:
6728
- id: prettier
68-
additional_dependencies:
69-
70-
- "@prettier/[email protected]"
7129
args: ["--print-width=120", "--prose-wrap=always"]
72-
- repo: https://github.com/igorshubovych/markdownlint-cli
73-
rev: v0.33.0
74-
hooks:
75-
- id: markdownlint
7630
- repo: meta
7731
hooks:
7832
- id: check-hooks-apply

docs/conf.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
1+
# noqa: INP001
2+
"""Configuration for Sphinx."""
13
from __future__ import annotations
24

3-
from datetime import date, datetime
5+
from datetime import datetime, timezone
6+
from typing import TYPE_CHECKING
47

58
from docutils.nodes import Element, Text
6-
from sphinx.addnodes import pending_xref
7-
from sphinx.application import Sphinx
8-
from sphinx.builders import Builder
9+
from filelock import __version__
910
from sphinx.domains.python import PythonDomain
10-
from sphinx.environment import BuildEnvironment
1111

12-
from filelock import __version__
12+
if TYPE_CHECKING:
13+
from sphinx.addnodes import pending_xref
14+
from sphinx.application import Sphinx
15+
from sphinx.builders import Builder
16+
from sphinx.environment import BuildEnvironment
1317

1418
name, company = "filelock", "tox-dev"
19+
now = datetime.now(tz=timezone.utc)
1520
version, release = ".".join(__version__.split(".")[:2]), __version__
16-
copyright = f"2014-{date.today().year}, {company}"
21+
copyright = f"2014-{now.date().year}, {company}" # noqa: A001
1722
extensions = [
1823
"sphinx.ext.autodoc",
1924
"sphinx.ext.autosectionlabel",
@@ -23,7 +28,7 @@
2328
"sphinx_autodoc_typehints",
2429
]
2530
html_theme = "furo"
26-
html_title, html_last_updated_fmt = name, datetime.now().isoformat()
31+
html_title, html_last_updated_fmt = name, now.isoformat()
2732
pygments_style, pygments_dark_style = "sphinx", "monokai"
2833
autoclass_content, autodoc_member_order, autodoc_typehints = "class", "bysource", "none"
2934
autodoc_default_options = {"member-order": "bysource", "undoc-members": True, "show-inheritance": True}
@@ -40,13 +45,19 @@
4045

4146

4247
def setup(app: Sphinx) -> None:
48+
"""
49+
Setup app.
50+
51+
:param app: the app
52+
"""
53+
4354
class PatchedPythonDomain(PythonDomain):
44-
def resolve_xref(
55+
def resolve_xref( # noqa: PLR0913
4556
self,
4657
env: BuildEnvironment,
4758
fromdocname: str,
4859
builder: Builder,
49-
type: str,
60+
type: str, # noqa: A002
5061
target: str,
5162
node: pending_xref,
5263
contnode: Element,

pyproject.toml

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
build-backend = "hatchling.build"
33
requires = [
44
"hatch-vcs>=0.3",
5-
"hatchling>=1.14",
5+
"hatchling>=1.17",
66
]
77

88
[project]
@@ -25,8 +25,12 @@ classifiers = [
2525
"License :: OSI Approved :: The Unlicense (Unlicense)",
2626
"Operating System :: OS Independent",
2727
"Programming Language :: Python",
28-
"Programming Language :: Python :: 3",
2928
"Programming Language :: Python :: 3 :: Only",
29+
"Programming Language :: Python :: 3.7",
30+
"Programming Language :: Python :: 3.8",
31+
"Programming Language :: Python :: 3.9",
32+
"Programming Language :: Python :: 3.10",
33+
"Programming Language :: Python :: 3.11",
3034
"Topic :: Internet",
3135
"Topic :: Software Development :: Libraries",
3236
"Topic :: System",
@@ -35,16 +39,16 @@ dynamic = [
3539
"version",
3640
]
3741
optional-dependencies.docs = [
38-
"furo>=2023.3.27",
39-
"sphinx>=6.1.3",
42+
"furo>=2023.5.20",
43+
"sphinx>=7.0.1",
4044
"sphinx-autodoc-typehints!=1.23.4,>=1.23",
4145
]
4246
optional-dependencies.testing = [
4347
"covdefaults>=2.3",
44-
"coverage>=7.2.3",
48+
"coverage>=7.2.7",
4549
"diff-cover>=7.5",
4650
"pytest>=7.3.1",
47-
"pytest-cov>=4",
51+
"pytest-cov>=4.1",
4852
"pytest-mock>=3.10",
4953
"pytest-timeout>=2.1",
5054
]
@@ -61,18 +65,6 @@ version.source = "vcs"
6165
[tool.black]
6266
line-length = 120
6367

64-
[tool.isort]
65-
profile = "black"
66-
known_first_party = ["filelock"]
67-
add_imports = ["from __future__ import annotations"]
68-
69-
[tool.flake8]
70-
max-complexity = 22
71-
max-line-length = 120
72-
unused-arguments-ignore-abstract-functions = true
73-
noqa-require-code = true
74-
dictionaries = ["en_US", "python", "technical", "django"]
75-
7668
[tool.coverage]
7769
html.show_contexts = true
7870
html.skip_covered = false
@@ -88,5 +80,26 @@ show_error_codes = true
8880
strict = true
8981
overrides = [{ module = ["appdirs.*", "jnius.*"], ignore_missing_imports = true }]
9082

91-
[tool.pep8]
92-
max-line-length = "120"
83+
[tool.ruff]
84+
select = ["ALL"]
85+
line-length = 120
86+
target-version = "py37"
87+
isort = {known-first-party = ["platformdirs", "tests"], required-imports = ["from __future__ import annotations"]}
88+
ignore = [
89+
"ANN101", # Missing type annotation for `self` in method
90+
"D301", # Use `r"""` if any backslashes in a docstring
91+
"D205", # 1 blank line required between summary line and description
92+
"D401", # First line of docstring should be in imperative mood
93+
"D203", # `one-blank-line-before-class` (D203) and `no-blank-line-before-class` (D211) are incompatible
94+
"D212", # `multi-line-summary-first-line` (D212) and `multi-line-summary-second-line` (D213) are incompatible
95+
"S104", # Possible binding to all interface
96+
]
97+
[tool.ruff.per-file-ignores]
98+
"tests/**/*.py" = [
99+
"S101", # asserts allowed in tests...
100+
"FBT", # don"t care about booleans as positional arguments in tests
101+
"INP001", # no implicit namespace
102+
"D", # don"t care about documentation in tests
103+
"S603", # `subprocess` call: check for execution of untrusted input
104+
"PLR2004", # Magic value used in comparison, consider replacing with a constant variable
105+
]

src/filelock/__init__.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,16 @@
2525
if sys.platform == "win32": # pragma: win32 cover
2626
_FileLock: type[BaseFileLock] = WindowsFileLock
2727
else: # pragma: win32 no cover
28-
if has_fcntl:
28+
if has_fcntl: # noqa: PLR5501
2929
_FileLock: type[BaseFileLock] = UnixFileLock
3030
else:
3131
_FileLock = SoftFileLock
3232
if warnings is not None:
3333
warnings.warn("only soft file lock is available", stacklevel=2)
3434

35-
if TYPE_CHECKING:
36-
FileLock = SoftFileLock
37-
else:
38-
#: Alias for the lock, which should be used for the current platform.
39-
FileLock = _FileLock
35+
36+
#: Alias for the lock, which should be used for the current platform.
37+
FileLock: type[BaseFileLock] = SoftFileLock if TYPE_CHECKING else _FileLock # type: ignore[assignment]
4038

4139

4240
__all__ = [

src/filelock/_api.py

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88
from abc import ABC, abstractmethod
99
from dataclasses import dataclass
1010
from threading import local
11-
from types import TracebackType
12-
from typing import Any
11+
from typing import TYPE_CHECKING, Any
1312

1413
from ._error import Timeout
1514

15+
if TYPE_CHECKING:
16+
from types import TracebackType
17+
1618
_LOGGER = logging.getLogger("filelock")
1719

1820

@@ -30,18 +32,16 @@ def __enter__(self) -> BaseFileLock:
3032

3133
def __exit__(
3234
self,
33-
exc_type: type[BaseException] | None, # noqa: U100
34-
exc_value: BaseException | None, # noqa: U100
35-
traceback: TracebackType | None, # noqa: U100
35+
exc_type: type[BaseException] | None,
36+
exc_value: BaseException | None,
37+
traceback: TracebackType | None,
3638
) -> None:
3739
self.lock.release()
3840

3941

4042
@dataclass
4143
class FileLockContext:
42-
"""
43-
A dataclass which holds the context for a ``BaseFileLock`` object.
44-
"""
44+
"""A dataclass which holds the context for a ``BaseFileLock`` object."""
4545

4646
# The context is held in a separate class to allow optional use of thread local storage via the
4747
# ThreadLocalFileContext class.
@@ -63,9 +63,7 @@ class FileLockContext:
6363

6464

6565
class ThreadLocalFileContext(FileLockContext, local):
66-
"""
67-
A thread local version of the ``FileLockContext`` class.
68-
"""
66+
"""A thread local version of the ``FileLockContext`` class."""
6967

7068

7169
class BaseFileLock(ABC, contextlib.ContextDecorator):
@@ -76,7 +74,7 @@ def __init__(
7674
lock_file: str | os.PathLike[Any],
7775
timeout: float = -1,
7876
mode: int = 0o644,
79-
thread_local: bool = True,
77+
thread_local: bool = True, # noqa: FBT001, FBT002
8078
) -> None:
8179
"""
8280
Create a new lock object.
@@ -151,9 +149,7 @@ def is_locked(self) -> bool:
151149

152150
@property
153151
def lock_counter(self) -> int:
154-
"""
155-
:return: The number of times this lock has been acquired (but not yet released).
156-
"""
152+
""":return: The number of times this lock has been acquired (but not yet released)."""
157153
return self._context.lock_counter
158154

159155
def acquire(
@@ -218,22 +214,21 @@ def acquire(
218214
if self.is_locked:
219215
_LOGGER.debug("Lock %s acquired on %s", lock_id, lock_filename)
220216
break
221-
elif blocking is False:
217+
if blocking is False:
222218
_LOGGER.debug("Failed to immediately acquire lock %s on %s", lock_id, lock_filename)
223-
raise Timeout(lock_filename)
224-
elif 0 <= timeout < time.perf_counter() - start_time:
219+
raise Timeout(lock_filename) # noqa: TRY301
220+
if 0 <= timeout < time.perf_counter() - start_time:
225221
_LOGGER.debug("Timeout on acquiring lock %s on %s", lock_id, lock_filename)
226-
raise Timeout(lock_filename)
227-
else:
228-
msg = "Lock %s not acquired on %s, waiting %s seconds ..."
229-
_LOGGER.debug(msg, lock_id, lock_filename, poll_interval)
230-
time.sleep(poll_interval)
222+
raise Timeout(lock_filename) # noqa: TRY301
223+
msg = "Lock %s not acquired on %s, waiting %s seconds ..."
224+
_LOGGER.debug(msg, lock_id, lock_filename, poll_interval)
225+
time.sleep(poll_interval)
231226
except BaseException: # Something did go wrong, so decrement the counter.
232227
self._context.lock_counter = max(0, self._context.lock_counter - 1)
233228
raise
234229
return AcquireReturnProxy(lock=self)
235230

236-
def release(self, force: bool = False) -> None:
231+
def release(self, force: bool = False) -> None: # noqa: FBT001, FBT002
237232
"""
238233
Releases the file lock. Please note, that the lock is only completely released, if the lock counter is 0. Also
239234
note, that the lock file itself is not automatically deleted.
@@ -262,9 +257,9 @@ def __enter__(self) -> BaseFileLock:
262257

263258
def __exit__(
264259
self,
265-
exc_type: type[BaseException] | None, # noqa: U100
266-
exc_value: BaseException | None, # noqa: U100
267-
traceback: TracebackType | None, # noqa: U100
260+
exc_type: type[BaseException] | None,
261+
exc_value: BaseException | None,
262+
traceback: TracebackType | None,
268263
) -> None:
269264
"""
270265
Release the lock.

src/filelock/_error.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from typing import Any
44

55

6-
class Timeout(TimeoutError):
6+
class Timeout(TimeoutError): # noqa: N818
77
"""Raised when the lock could not be acquired in *timeout* seconds."""
88

99
def __init__(self, lock_file: str) -> None:

0 commit comments

Comments
 (0)