__repr__() should not refresh the lock
Problem
__repr__ evaluates self.is_locked
def __repr__(self):
return '<%s %s [%s: %s] pid=%s at %#xx>' % (
self.__class__.__name__,
self._lockfile,
('locked' if self.is_locked else 'unlocked'),
self._lifetime, os.getpid(), id(self))
self.is_locked resets the lifetime of the lock.
@property
def is_locked(self):
"""True if we own the lock, False if we do not.
Checking the status of the lock resets the lock's lifetime, which
helps avoid race conditions during the lock status test.
"""
# Discourage breaking the lock for a while.
try:
self._touch()
except PermissionError:
# We can't touch the file because we're not the owner. I don't see
# how we can own the lock if we're not the owner.
log.error('No permission to refresh the log')
return False
# XXX Can the link count ever be > 2?
if self._linkcount != 2:
return False
return self._read() == self._claimfile
A way this may become a problem is when an unknowing user uses this in logging or prints it out.
>>> import logging
>>> logging.basicConfig()
>>> logging.getLogger().setLevel(logging.DEBUG)
>>> import datetime
>>> from flufl.lock import Lock
>>> a = Lock('b.txt', lifetime=datetime.timedelta(seconds=10))
DEBUG:flufl.lock:__del__: b.txt
DEBUG:flufl.lock:finalize: b.txt
DEBUG:flufl.lock:unlocked: b.txt
>>> a.lock()
DEBUG:flufl.lock:laying claim: b.txt
DEBUG:flufl.lock:got the lock: b.txt
>>> time.sleep(10)
>>> f"{a}"
'<Lock b.txt [locked: 0:00:10] pid=31296 at 0x10fce1790x>'
>>> b.lock(datetime.timedelta(seconds=1))
DEBUG:flufl.lock:laying claim: b.txt
DEBUG:flufl.lock:waiting for claim: b.txt
ERROR:flufl.lock:timed out
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/molee/lipy-deployment-runner_trunk/build/lipy-deployment-runner/environments/development-venv/lib/python3.7/site-packages/flufl/lock/_lockfile.py", line 259, in lock
raise TimeOutError('Could not acquire the lock')
flufl.lock._lockfile.TimeOutError: Could not acquire the lock
Solution
I think the solution can be 2 parts:
- Add support for
__str__that doesn't useis_lockedor remove the refresh functionality fromis_lockedand put it inrefreshinstead. I think the latter might be more bug free. - If a process owns the lock but the lock expired, the
is_lockedwill still print True. We might want to add checks the lock hasn't expired before printing True.
Thanks!
Edited by Barry Warsaw