Skip to content

Commit

Permalink
added more type hinting to fix #60
Browse files Browse the repository at this point in the history
  • Loading branch information
wolph committed Sep 14, 2021
1 parent 871814f commit 3025e66
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 12 deletions.
7 changes: 7 additions & 0 deletions msvcrt.pyi
@@ -0,0 +1,7 @@
LK_LOCK: int
LK_NBLCK: int
LK_NBRLCK: int
LK_RLCK: int
LK_UNLCK: int

def locking(file: int, mode: int, lock_length: int) -> int: ...
12 changes: 10 additions & 2 deletions portalocker/exceptions.py
@@ -1,10 +1,18 @@
import typing


class BaseLockException(Exception):
# Error codes:
LOCK_FAILED = 1

def __init__(self, *args, fh=None, **kwargs):
def __init__(
self,
*args: typing.Any,
fh: typing.Optional[typing.IO] = None,
**kwargs: typing.Any,
) -> None:
self.fh = fh
Exception.__init__(self, *args, **kwargs)
Exception.__init__(self, *args)


class LockException(BaseLockException):
Expand Down
2 changes: 1 addition & 1 deletion portalocker/redis.py
Expand Up @@ -18,7 +18,7 @@
DEFAULT_THREAD_SLEEP_TIME = 0.1


class PubSubWorkerThread(client.PubSubWorkerThread):
class PubSubWorkerThread(client.PubSubWorkerThread): # type: ignore

def run(self):
try:
Expand Down
24 changes: 16 additions & 8 deletions portalocker/utils.py
Expand Up @@ -28,7 +28,7 @@
Filename = typing.Union[str, pathlib.Path]


def coalesce(*args, test_value=None):
def coalesce(*args: typing.Any, test_value: typing.Any = None) -> typing.Any:
'''Simple coalescing function that returns the first value that is not
equal to the `test_value`. Or `None` if no value is valid. Usually this
means that the last given value is the default value.
Expand Down Expand Up @@ -56,7 +56,8 @@ def coalesce(*args, test_value=None):


@contextlib.contextmanager
def open_atomic(filename: Filename, binary: bool = True):
def open_atomic(filename: Filename, binary: bool = True) \
-> typing.Iterator[typing.IO]:
'''Open a file for atomic writing. Instead of locking this method allows
you to write the entire file and move it to the actual location. Note that
this makes the assumption that a rename is atomic on your platform which
Expand Down Expand Up @@ -129,21 +130,23 @@ def acquire(
fail_when_locked: bool = None):
return NotImplemented

def _timeout_generator(self, timeout, check_interval):
timeout = coalesce(timeout, self.timeout, 0.0)
check_interval = coalesce(check_interval, self.check_interval, 0.0)
def _timeout_generator(self, timeout: typing.Optional[float],
check_interval: typing.Optional[float]) \
-> typing.Iterator[int]:
f_timeout = coalesce(timeout, self.timeout, 0.0)
f_check_interval = coalesce(check_interval, self.check_interval, 0.0)

yield 0
i = 0

start_time = time.perf_counter()
while start_time + timeout > time.perf_counter():
while start_time + f_timeout > time.perf_counter():
i += 1
yield i

# Take low lock checks into account to stay within the interval
since_start_time = time.perf_counter() - start_time
time.sleep(max(0.001, (i * check_interval) - since_start_time))
time.sleep(max(0.001, (i * f_check_interval) - since_start_time))

@abc.abstractmethod
def release(self):
Expand All @@ -152,8 +155,13 @@ def release(self):
def __enter__(self):
return self.acquire()

def __exit__(self, type_, value, tb):
def __exit__(self,
exc_type: typing.Optional[typing.Type[BaseException]],
exc_value: typing.Optional[BaseException],
traceback: typing.Any, # Should be typing.TracebackType
) -> typing.Optional[bool]:
self.release()
return None

def __delete__(self, instance):
instance.release()
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -128,7 +128,7 @@ def run(self):
author_email=about['__email__'],
url=about['__url__'],
license='PSF',
package_data=dict(portalocker=['py.typed']),
package_data=dict(portalocker=['py.typed', 'msvcrt.pyi']),
packages=setuptools.find_packages(exclude=[
'examples', 'portalocker_tests']),
# zip_safe=False,
Expand Down
5 changes: 5 additions & 0 deletions tox.ini
Expand Up @@ -14,6 +14,11 @@ basepython =
deps = -e{toxinidir}[tests,redis]
commands = python -m pytest {posargs}

[testenv:mypy]
basepython = python3
deps = mypy
commands = mypy {toxinidir}/portalocker

[testenv:flake8]
basepython = python3
deps = flake8
Expand Down

0 comments on commit 3025e66

Please sign in to comment.