Skip to content

Commit

Permalink
fixed tests, pyright, ruff, etc...
Browse files Browse the repository at this point in the history
  • Loading branch information
wolph committed Dec 31, 2024
1 parent 422f630 commit a993d64
Show file tree
Hide file tree
Showing 14 changed files with 194 additions and 104 deletions.
25 changes: 25 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
target-branch: master
labels:
- "meta: CI"
schedule:
interval: monthly
groups:
actions:
patterns:
- "*"

- package-ecosystem: pip
directory: /
target-branch: master
labels:
- "meta: deps"
schedule:
interval: monthly
groups:
actions:
patterns:
- "*"
5 changes: 5 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ on:
env:
FORCE_COLOR: 1

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
lint:
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ on:
env:
FORCE_COLOR: 1

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
# Run os specific tests on the slower OS X/Windows machines
windows_osx:
Expand Down
73 changes: 73 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
ci:
autoupdate_branch: "master"
autoupdate_commit_msg: "⬆️ update pre-commit hooks"
skip:
- basedpyright

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-added-large-files
- id: check-ast
- id: check-case-conflict
- id: check-docstring-first
- id: check-executables-have-shebangs
- id: check-illegal-windows-names
- id: check-json
- id: check-merge-conflict
- id: check-shebang-scripts-are-executable
- id: check-symlinks
- id: check-toml
- id: check-vcs-permalinks
- id: check-xml
- id: check-yaml
- id: debug-statements
- id: destroyed-symlinks
- id: detect-aws-credentials
args: [--allow-missing-credentials]
- id: detect-private-key
- id: fix-byte-order-marker
- id: forbid-submodules
- id: name-tests-test
args: [--pytest-test-first]
- id: no-commit-to-branch
args: [--branch, master]
- id: trailing-whitespace
args: [--markdown-linebreak-ext=md]

- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.43.0
hooks:
- id: markdownlint

- repo: https://github.com/executablebooks/mdformat
rev: 0.7.21
hooks:
- id: mdformat
additional_dependencies:
- mdformat-gfm
- mdformat-gfm-alerts

- repo: https://github.com/crate-ci/typos
rev: v1.28.4
hooks:
- id: typos

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.4
hooks:
- id: ruff
args: [--fix, --show-fixes]
types_or: [python, pyi]

- id: ruff-format
types_or: [python, pyi]

- repo: local
hooks:
- id: basedpyright
name: basedpyright
entry: uv run --no-sync --locked basedpyright
language: system
types_or: [python, pyi]
7 changes: 7 additions & 0 deletions docs/portalocker.types.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
portalocker.types module
========================

.. automodule:: portalocker.types
:members:
:undoc-members:
:show-inheritance:
2 changes: 1 addition & 1 deletion portalocker/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
try: # pragma: no cover
from .redis import RedisLock
except ImportError: # pragma: no cover
RedisLock = None # type: ignore
RedisLock = None # type: ignore[assignment,misc]


#: The package name on Pypi
Expand Down
2 changes: 1 addition & 1 deletion portalocker/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
#: non-blocking
LOCK_NB = 0x4
#: unlock
LOCK_UN = msvcrt.LK_UNLCK # type: ignore
LOCK_UN = msvcrt.LK_UNLCK # type: ignore[attr-defined]

elif os.name == 'posix': # pragma: no cover
import fcntl
Expand Down
4 changes: 2 additions & 2 deletions portalocker/portalocker.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def lock(file_: types.IO | int, flags: LockFlags) -> None:
if savepos:
file_.seek(0)

os_fh = msvcrt.get_osfhandle(file_.fileno()) # type: ignore
os_fh = msvcrt.get_osfhandle(file_.fileno()) # type: ignore[attr-defined]
try:
win32file.LockFileEx(os_fh, mode, 0, -0x10000, __overlapped)
except pywintypes.error as exc_value:
Expand All @@ -70,7 +70,7 @@ def unlock(file_: types.IO) -> None:
if savepos:
file_.seek(0)

os_fh = msvcrt.get_osfhandle(file_.fileno()) # type: ignore
os_fh = msvcrt.get_osfhandle(file_.fileno()) # type: ignore[attr-defined]
try:
win32file.UnlockFileEx(
os_fh,
Expand Down
2 changes: 1 addition & 1 deletion portalocker/redis.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
DEFAULT_THREAD_SLEEP_TIME = 0.1


class PubSubWorkerThread(redis.client.PubSubWorkerThread): # type: ignore
class PubSubWorkerThread(redis.client.PubSubWorkerThread):
def run(self) -> None:
try:
super().run()
Expand Down
2 changes: 1 addition & 1 deletion portalocker/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ def acquire(
else:
fh = super().acquire(timeout, check_interval, fail_when_locked)
self._acquire_count += 1
assert fh
assert fh is not None
return fh

def release(self) -> None:
Expand Down
2 changes: 1 addition & 1 deletion portalocker_tests/test_combined.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ def test_combined(tmpdir):

sys.path.append(output_file.dirname)
# Combined is being generated above but linters won't understand that
import combined # type: ignore
import combined # pyright: ignore[reportMissingImports]

assert combined
45 changes: 35 additions & 10 deletions portalocker_tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import math
import multiprocessing
import os
import sys
import time
import typing

Expand All @@ -19,7 +20,7 @@
fcntl.lockf,
]
else:
LOCKERS = [None] # type: ignore
LOCKERS = [None] # type: ignore[list-item]


@pytest.fixture
Expand Down Expand Up @@ -61,7 +62,7 @@ def test_with_timeout(tmpfile):
print('writing more stuff to my cache...', file=fh)


def test_without_timeout(tmpfile, monkeypatch):
def test_without_timeout(tmpfile):
# Open the file 2 times
with pytest.raises(portalocker.LockException):
with portalocker.Lock(tmpfile, timeout=None) as fh:
Expand Down Expand Up @@ -333,6 +334,10 @@ def lock(


@pytest.mark.parametrize('fail_when_locked', [True, False])
@pytest.mark.skipif(
'pypy' in sys.version.lower(),
reason='pypy3 does not support the multiprocessing test',
)
def test_shared_processes(tmpfile, fail_when_locked):
flags = LockFlags.SHARED | LockFlags.NON_BLOCKING
print()
Expand All @@ -351,8 +356,25 @@ def test_shared_processes(tmpfile, fail_when_locked):
assert result == LockResult()


def _lock_and_sleep(
filename: str,
fail_when_locked: bool,
flags: LockFlags,
keep_locked: float = 0.1,
) -> LockResult:
result = lock(filename, fail_when_locked, flags)
print(f'{result=}')
time.sleep(keep_locked)
return result


@pytest.mark.parametrize('fail_when_locked', [True, False])
@pytest.mark.parametrize('locker', LOCKERS, indirect=True)
# Skip pypy3
@pytest.mark.skipif(
'pypy' in sys.version.lower(),
reason='pypy3 does not support the multiprocessing test',
)
def test_exclusive_processes(
tmpfile: str,
fail_when_locked: bool,
Expand All @@ -367,23 +389,26 @@ def test_exclusive_processes(
result_b = pool.apply_async(lock, [tmpfile, fail_when_locked, flags])

try:
a = result_a.get(timeout=1.1) # Wait for 'a' with timeout
a = result_a.get(timeout=1) # Wait for 'a' with timeout
except multiprocessing.TimeoutError:
a = None

print(f'{a=}')
print(repr(a))

try:
# Lower timeout since we already waited with `a`
b = result_b.get(timeout=0.2) # Wait for 'b' with timeout
b = result_b.get(timeout=0.1) # Wait for 'b' with timeout
except multiprocessing.TimeoutError:
b = None

print(f'{b=}')
print(repr(b))

assert a or b
# Make sure a is always filled
if b:
b, a = b, a

print(f'{a=}')
print(f'{b=}')
if a is None:
b, a = a, b

# make pyright happy
assert a is not None
Expand All @@ -394,7 +419,7 @@ def test_exclusive_processes(

assert not a.exception_class or not b.exception_class
assert issubclass(
a.exception_class or b.exception_class, # type: ignore
a.exception_class or b.exception_class, # type: ignore[arg-type]
portalocker.LockException,
)
else:
Expand Down
40 changes: 38 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,12 @@ classifiers = [
'Topic :: System :: Monitoring',
'Typing :: Typed',
]
requires-python = '>=3.8'
dependencies = ['pywin32>=226; platform_system == "Windows"']
requires-python = '>=3.9'
dependencies = [
'pywin32>=226; platform_system == "Windows"',
'tomli-w>=1.0.0',
'tomlkit>=0.13.2',
]

[project.urls]
bugs = 'https://github.com/wolph/portalocker/issues'
Expand Down Expand Up @@ -103,6 +107,38 @@ packages = ['portalocker', 'portalocker_tests']
ignore_missing_imports = true
check_untyped_defs = true
exclude = ['dist', 'docs', '.venv', 'venv']
enable_error_code = ['ignore-without-code', 'truthy-bool', 'redundant-expr']
warn_unreachable = true

[[tool.mypy.overrides]]
module = ['portalocker_tests.*']
disallow_untyped_defs = false

[dependency-groups]
dev = [
'pytest-doc>=0.0.1',
'pytest>=8.3.4',
'pytest-docs>=0.1.0',
'pytest-mypy>=0.10.3',
'pytest-timeout>=2.3.1',
'redis>=5.2.1',
'sphinx>=7.1.2',
'types-redis>=4.6.0.20241004',
'mypy>=1.14.0',
'pytest-cov>=5.0.0',
]

[tool.ruff]
src = ['portalocker', 'portalocker_tests']
include = ['portalocker/**/*.py', 'portalocker_tests/**/*.py']

[tool.repo-review]
ignore = [
'PY004', # no /docs
'PY007', # tox configured in tox.toml
'PP301', # pytest is irrelevant
'PC111', # no blacken-docs because markdown has no code
'PC140', # manual typecheck pre-commit hooks
'PC170', # no pygrep-hooks because no rST
'RTD', # no RTD
]
Loading

0 comments on commit a993d64

Please sign in to comment.