Using python multiprocessing.Lock as an argument type in mypy
Asked Answered
R

2

6

I have a python function that takes in a multiprocessing.Lock object as an input and uses the acquire and release functions on it. Evaluating it with mypy returns the error Function multiprocessing.Lock" is not valid as a type. How can I properly annotate this function?

Ralston answered 20/12, 2021 at 15:50 Comment(0)
L
7

Lock is actually a plain function that returns a _LockType, which is defined as _LockType = synchronize.Lock, so you can do:

from multiprocessing.synchronize import Lock as LockBase

def func(lock: LockBase):
    pass

Although, the fact that they have _LockType as module private suggests they're treating it as an implementation detail that may change in the future, so be careful.


There's also this comment block above where _LockType is defined:

# The following type aliases can be used to annotate the return values of
# the corresponding functions. They are not defined at runtime.
#
# from multiprocessing import Lock
# from typing import TYPE_CHECKING
# if TYPE_CHECKING:
#     from multiprocessing import _LockType
# lock: _LockType = Lock() 
. . .
_LockType = synchronize.Lock
Leonelleonelle answered 20/12, 2021 at 15:57 Comment(0)
D
0

For multiprocessing factory functions Lock() and RLock(), there are at least corresponding classes in the multiprocessing.synchronize submodule.

from multiprocessing.synchronize import Lock as LockT, RLock as RLockT

The situation is worse in the closely related threading package, which might need to solve this internally, but till that's done, one can get away with defining a little protocol for the two locks:

class _LockType(contextlib.AbstractContextManager, typing.Protocol):
    def acquire(self, blocking: bool = ..., timeout: float = ...) -> bool: ...
    def release(self) -> None: ...


def ensure_lock(lock: _LockType | None) -> _LockType:
    return threading.Lock() if lock is None else lock

lock1 = ensure_lock(None)
lock2 = ensure_lock(Lock())
rlock = ensure_lock(RLock())
lock1.acquire()
lock1.release()  # mypy (1.7.1) is happy about all of the above

This protocol would be universally suitable for the locks from both the threading and multiprocessing packages, but it's not, because the multiprocessing.Lock.acquire has block as the 1st argument, while threading.Lock.acquire has blocking. I wonder if that's intentional.

Dubitable answered 5/3 at 11:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.