Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using python multiprocessing.Lock as an argument type in mypy

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?

like image 899
dmmpie Avatar asked Jul 29 '26 12:07

dmmpie


2 Answers

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
like image 193
Carcigenicate Avatar answered Jul 31 '26 01:07

Carcigenicate


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.

like image 41
tlwhitec Avatar answered Jul 31 '26 01:07

tlwhitec



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!