Commit e4b25c8e authored by Josué Ortega's avatar Josué Ortega

Import portalocker_1.0.0.orig.tar.gz

parent c4a45fbc
0.1:
* Initial release
0.2:
* Added `Lock` class to help prevent cache race conditions
0.3:
* Now actually returning the file descriptor from the `Lock` class
0.4:
* Fixing a few bugs, added coveralls support, switched to py.test and added
100% test coverage.
- Fixing exception thrown when fail_when_locked is true
- Fixing exception "Lock object has no attribute '_release_lock'" when
fail_when_locked is true due to the call to Lock._release_lock() which
fails because _release_lock is not defined.
0.5:
* Python 3 support
0.6:
* Added msvcrt support for Windows
Metadata-Version: 1.1
Name: portalocker
Version: 0.6.1
Version: 1.0.0
Summary: Wraps the portalocker recipe for easy usage
Home-page: https://github.com/WoLpH/portalocker
Author: Rick van Hattem
......@@ -14,7 +14,7 @@ Description: ############################################
:alt: Linux Test Status
:target: https://travis-ci.org/WoLpH/portalocker
.. image:: https://img.shields.io/appveyor/ci/WoLpH/portalocker.svg
.. image:: https://ci.appveyor.com/api/projects/status/mgqry98hgpy4prhh?svg=true
:alt: Windows Tests Status
:target: https://ci.appveyor.com/project/WoLpH/portalocker
......@@ -22,10 +22,6 @@ Description: ############################################
:alt: Coverage Status
:target: https://coveralls.io/r/WoLpH/portalocker?branch=master
.. image:: https://landscape.io/github/WoLpH/portalocker/master/landscape.png
:target: https://landscape.io/github/WoLpH/portalocker/master
:alt: Code Health
Overview
--------
......@@ -79,15 +75,18 @@ Description: ############################################
Do note that your data might still be in a buffer so it is possible that your
data is not available until you `flush()` or `close()`.
More examples can be found in the
`tests <http://portalocker.readthedocs.io/en/latest/_modules/tests/tests.html>`_.
Changelog
---------
See CHANGELOG file
See the `changelog <http://portalocker.readthedocs.io/en/latest/changelog.html>`_ page.
License
-------
see the LICENSE file
See the `LICENSE <https://github.com/WoLpH/portalocker/blob/develop/LICENSE>`_ file.
Keywords: locking,locks,with statement,windows,linux,unix
......
......@@ -6,7 +6,7 @@ portalocker - Cross-platform locking library
:alt: Linux Test Status
:target: https://travis-ci.org/WoLpH/portalocker
.. image:: https://img.shields.io/appveyor/ci/WoLpH/portalocker.svg
.. image:: https://ci.appveyor.com/api/projects/status/mgqry98hgpy4prhh?svg=true
:alt: Windows Tests Status
:target: https://ci.appveyor.com/project/WoLpH/portalocker
......@@ -14,10 +14,6 @@ portalocker - Cross-platform locking library
:alt: Coverage Status
:target: https://coveralls.io/r/WoLpH/portalocker?branch=master
.. image:: https://landscape.io/github/WoLpH/portalocker/master/landscape.png
:target: https://landscape.io/github/WoLpH/portalocker/master
:alt: Code Health
Overview
--------
......@@ -71,13 +67,16 @@ than you can do it like this:
Do note that your data might still be in a buffer so it is possible that your
data is not available until you `flush()` or `close()`.
More examples can be found in the
`tests <http://portalocker.readthedocs.io/en/latest/_modules/tests/tests.html>`_.
Changelog
---------
See CHANGELOG file
See the `changelog <http://portalocker.readthedocs.io/en/latest/changelog.html>`_ page.
License
-------
see the LICENSE file
See the `LICENSE <https://github.com/WoLpH/portalocker/blob/develop/LICENSE>`_ file.
Metadata-Version: 1.1
Name: portalocker
Version: 0.6.1
Version: 1.0.0
Summary: Wraps the portalocker recipe for easy usage
Home-page: https://github.com/WoLpH/portalocker
Author: Rick van Hattem
......@@ -14,7 +14,7 @@ Description: ############################################
:alt: Linux Test Status
:target: https://travis-ci.org/WoLpH/portalocker
.. image:: https://img.shields.io/appveyor/ci/WoLpH/portalocker.svg
.. image:: https://ci.appveyor.com/api/projects/status/mgqry98hgpy4prhh?svg=true
:alt: Windows Tests Status
:target: https://ci.appveyor.com/project/WoLpH/portalocker
......@@ -22,10 +22,6 @@ Description: ############################################
:alt: Coverage Status
:target: https://coveralls.io/r/WoLpH/portalocker?branch=master
.. image:: https://landscape.io/github/WoLpH/portalocker/master/landscape.png
:target: https://landscape.io/github/WoLpH/portalocker/master
:alt: Code Health
Overview
--------
......@@ -79,15 +75,18 @@ Description: ############################################
Do note that your data might still be in a buffer so it is possible that your
data is not available until you `flush()` or `close()`.
More examples can be found in the
`tests <http://portalocker.readthedocs.io/en/latest/_modules/tests/tests.html>`_.
Changelog
---------
See CHANGELOG file
See the `changelog <http://portalocker.readthedocs.io/en/latest/changelog.html>`_ page.
License
-------
see the LICENSE file
See the `LICENSE <https://github.com/WoLpH/portalocker/blob/develop/LICENSE>`_ file.
Keywords: locking,locks,with statement,windows,linux,unix
......
CHANGELOG
LICENSE
MANIFEST.in
README.rst
setup.cfg
setup.py
portalocker/__about__.py
portalocker/__init__.py
portalocker/constants.py
portalocker/exceptions.py
portalocker/portalocker.py
portalocker/utils.py
portalocker.egg-info/PKG-INFO
portalocker.egg-info/SOURCES.txt
portalocker.egg-info/dependency_links.txt
portalocker.egg-info/not-zip-safe
portalocker.egg-info/top_level.txt
tests/test_combined.py
tests/tests.py
\ No newline at end of file
__package_name__ = 'portalocker'
__author__ = 'Rick van Hattem'
__email__ = 'wolph@wol.ph'
__version__ = '1.0.0'
__description__ = '''Wraps the portalocker recipe for easy usage'''
__url__ = 'https://github.com/WoLpH/portalocker'
from .portalocker import lock, unlock, LOCK_EX, LOCK_SH, LOCK_NB, LockException
from .utils import Lock, AlreadyLocked, open_atomic
from . import __about__
from . import constants
from . import exceptions
from . import portalocker
from . import utils
#: The package name on Pypi
__package_name__ = __about__.__package_name__
#: Current author and maintainer, view the git history for the previous ones
__author__ = __about__.__author__
#: Current author's email address
__email__ = __about__.__email__
#: Version number
__version__ = __about__.__version__
#: Package description for Pypi
__description__ = __about__.__description__
#: Package homepage
__url__ = __about__.__url__
#: Exception thrown when the file is already locked by someone else
AlreadyLocked = exceptions.AlreadyLocked
#: Exception thrown if an error occurred during locking
LockException = exceptions.LockException
#: Lock a file. Note that this is an advisory lock on Linux/Unix systems
lock = portalocker.lock
#: Unlock a file
unlock = portalocker.unlock
#: Place an exclusive lock.
#: Only one process may hold an exclusive lock for a given file at a given
#: time.
LOCK_EX = constants.LOCK_EX
#: Place a shared lock.
#: More than one process may hold a shared lock for a given file at a given
#: time.
LOCK_SH = constants.LOCK_SH
#: Acquire the lock in a non-blocking fashion.
LOCK_NB = constants.LOCK_NB
#: Remove an existing lock held by this process.
LOCK_UN = constants.LOCK_UN
#: Locking utility class to automatically handle opening with timeouts and
#: context wrappers
Lock = utils.Lock
open_atomic = utils.open_atomic
__all__ = [
'lock',
......@@ -7,6 +56,7 @@ __all__ = [
'LOCK_EX',
'LOCK_SH',
'LOCK_NB',
'LOCK_UN',
'LockException',
'Lock',
'AlreadyLocked',
......
import os
# The actual tests will execute the code anyhow so the following code can
# safely be ignored from the coverage tests
if os.name == 'nt': # pragma: no cover
import msvcrt
LOCK_EX = 0x1
LOCK_SH = 0x2
LOCK_NB = 0x4
LOCK_UN = msvcrt.LK_UNLCK
elif os.name == 'posix': # pragma: no cover
import fcntl
LOCK_EX = fcntl.LOCK_EX
LOCK_SH = fcntl.LOCK_SH
LOCK_NB = fcntl.LOCK_NB
LOCK_UN = fcntl.LOCK_UN
else: # pragma: no cover
raise RuntimeError('PortaLocker only defined for nt and posix platforms')
class BaseLockException(Exception):
# Error codes:
LOCK_FAILED = 1
class LockException(BaseLockException):
pass
class AlreadyLocked(BaseLockException):
pass
# portalocker.py - Cross-platform (posix/nt) API for flock-style file locking.
# Requires python 1.5.2 or better.
'''Cross-platform (posix/nt) API for flock-style file locking.
Synopsis:
import portalocker
file = open('somefile', 'r+')
portalocker.lock(file, portalocker.LOCK_EX)
file.seek(12)
file.write('foo')
file.close()
If you know what you're doing, you may choose to
portalocker.unlock(file)
before closing the file, but why?
Methods:
lock( file, flags )
unlock( file )
Constants:
LOCK_EX
LOCK_SH
LOCK_NB
Exceptions:
LockException
Notes:
For the 'nt' platform, this module requires the Python Extensions for Windows.
Be aware that this may not work as expected on Windows 95/98/ME.
History:
I learned the win32 technique for locking files from sample code
provided by John Nielsen <nielsenjf@my-deja.com> in the documentation
that accompanies the win32 modules.
Author: Jonathan Feinberg <jdf@pobox.com>,
Lowell Alleman <lalleman@mfps.com>
Version: $Id: portalocker.py 5474 2008-05-16 20:53:50Z lowell $
'''
import os
from . import exceptions
from . import constants
__all__ = [
'lock',
'unlock',
'LOCK_EX',
'LOCK_SH',
'LOCK_NB',
'LockException',
]
class LockException(Exception):
# Error codes:
LOCK_FAILED = 1
if os.name == 'nt': # pragma: no cover
import msvcrt
LOCK_EX = 0x1 # exclusive - msvcrt.LK_LOCK or msvcrt.LK_NBLCK
LOCK_SH = 0x2 # shared - msvcrt.LK_RLOCK or msvcrt.LK_NBRLCK
LOCK_NB = 0x4 #
elif os.name == 'posix':
import fcntl
LOCK_EX = fcntl.LOCK_EX
LOCK_SH = fcntl.LOCK_SH
LOCK_NB = fcntl.LOCK_NB
else: # pragma: no cover
raise RuntimeError('PortaLocker only defined for nt and posix platforms')
def nt_lock(file_, flags): # pragma: no cover
if flags & LOCK_SH:
mode = msvcrt.LK_NBRLCK if (flags & LOCK_NB) else msvcrt.LK_RLOCK
else:
mode = msvcrt.LK_NBLCK if (flags & LOCK_NB) else msvcrt.LK_LOCK
# windows locks byte ranges, so make sure to lock from file start
try:
savepos = file_.tell()
if savepos:
# [ ] test exclusive lock fails on seek here
# [ ] test if shared lock passes this point
file_.seek(0)
# [x] check if 0 param locks entire file (not documented in Python)
# [x] just fails with "IOError: [Errno 13] Permission denied",
# but -1 seems to do the trick
def lock(file_, flags):
if flags & constants.LOCK_SH:
if flags & constants.LOCK_NB:
mode = msvcrt.LK_NBRLCK
else:
mode = msvcrt.LK_RLOCK
else:
if flags & constants.LOCK_NB:
mode = msvcrt.LK_NBLCK
else:
mode = msvcrt.LK_LOCK
# windows locks byte ranges, so make sure to lock from file start
try:
msvcrt.locking(file_.fileno(), mode, -1)
except IOError as exc_value:
# [ ] be more specific here
raise LockException(LockException.LOCK_FAILED, exc_value.strerror)
finally:
savepos = file_.tell()
if savepos:
file_.seek(savepos)
except IOError as exc_value:
raise LockException(LockException.LOCK_FAILED, exc_value.strerror)
# [ ] test exclusive lock fails on seek here
# [ ] test if shared lock passes this point
file_.seek(0)
# [x] check if 0 param locks entire file (not documented in
# Python)
# [x] just fails with "IOError: [Errno 13] Permission denied",
# but -1 seems to do the trick
try:
msvcrt.locking(file_.fileno(), mode, -1)
except IOError as exc_value:
# [ ] be more specific here
raise exceptions.LockException(
exceptions.LockException.LOCK_FAILED, exc_value.strerror)
finally:
if savepos:
file_.seek(savepos)
except IOError as exc_value:
raise exceptions.LockException(
exceptions.LockException.LOCK_FAILED, exc_value.strerror)
def nt_unlock(file_): # pragma: no cover
try:
savepos = file_.tell()
if savepos:
file_.seek(0)
def unlock(file_):
try:
msvcrt.locking(file_.fileno(), msvcrt.LK_UNLCK, -1)
except IOError as exc_value:
raise LockException(LockException.LOCK_FAILED, exc_value.strerror)
finally:
savepos = file_.tell()
if savepos:
file_.seek(savepos)
except IOError as exc_value:
raise LockException(LockException.LOCK_FAILED, exc_value.strerror)
file_.seek(0)
try:
msvcrt.locking(file_.fileno(), constants.LOCK_UN, -1)
except IOError as exc_value:
raise exceptions.LockException(
exceptions.LockException.LOCK_FAILED, exc_value.strerror)
finally:
if savepos:
file_.seek(savepos)
except IOError as exc_value:
raise exceptions.LockException(
exceptions.LockException.LOCK_FAILED, exc_value.strerror)
def posix_lock(file_, flags):
try:
fcntl.flock(file_.fileno(), flags)
except IOError as exc_value:
# The exception code varies on different systems so we'll catch
# every IO error
raise LockException(exc_value)
elif os.name == 'posix': # pragma: no cover
import fcntl
def lock(file_, flags):
try:
fcntl.flock(file_.fileno(), flags)
except IOError as exc_value:
# The exception code varies on different systems so we'll catch
# every IO error
raise exceptions.LockException(exc_value)
def posix_unlock(file_):
fcntl.flock(file_.fileno(), fcntl.LOCK_UN)
def unlock(file_):
fcntl.flock(file_.fileno(), constants.LOCK_UN)
if os.name == 'nt': # pragma: no cover
lock = nt_lock
unlock = nt_unlock
elif os.name == 'posix':
lock = posix_lock
unlock = posix_unlock
else: # pragma: no cover
raise RuntimeError('Your os %r is unsupported.' % os.name)
raise RuntimeError('PortaLocker only defined for nt and posix platforms')
......@@ -2,29 +2,26 @@ import os
import time
import tempfile
import contextlib
from . import exceptions
from . import constants
from . import portalocker
DEFAULT_TIMEOUT = 5
DEFAULT_CHECK_INTERVAL = 0.25
LOCK_METHOD = portalocker.LOCK_EX | portalocker.LOCK_NB
LOCK_METHOD = constants.LOCK_EX | constants.LOCK_NB
__all__ = [
'Lock',
'AlreadyLocked',
'open_atomic',
]
class AlreadyLocked(Exception):
pass
@contextlib.contextmanager
def open_atomic(filename, binary=True):
'''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
is still not atomic in all cases and won't work on existing files.
this makes the assumption that a rename is atomic on your platform which
is generally the case but not a guarantee.
http://docs.python.org/library/os.html#os.rename
......@@ -33,7 +30,7 @@ def open_atomic(filename, binary=True):
... os.remove(filename)
>>> with open_atomic(filename) as fh:
... fh.write('test')
... written = fh.write(b'test')
>>> assert os.path.exists(filename)
>>> os.remove(filename)
......@@ -66,7 +63,7 @@ def open_atomic(filename, binary=True):
class Lock(object):
def __init__(
self, filename, mode='a', truncate=0, timeout=DEFAULT_TIMEOUT,
self, filename, mode='a', timeout=DEFAULT_TIMEOUT,
check_interval=DEFAULT_CHECK_INTERVAL, fail_when_locked=True,
flags=LOCK_METHOD):
'''Lock manager with build-in timeout
......@@ -88,6 +85,12 @@ class Lock(object):
mode will result in truncate _BEFORE_ the lock is checked.
'''
if 'w' in mode:
truncate = True
mode = mode.replace('w', 'a')
else:
truncate = False
self.fh = None
self.filename = filename
self.mode = mode
......@@ -97,8 +100,6 @@ class Lock(object):
self.fail_when_locked = fail_when_locked
self.flags = flags
assert 'w' not in mode, 'Mode "w" clears the file before locking'
def acquire(
self, timeout=None, check_interval=None, fail_when_locked=None):
'''Acquire the locked filehandle'''
......@@ -123,7 +124,7 @@ class Lock(object):
try:
# Try to lock
fh = self._get_lock(fh)
except portalocker.LockException as exception:
except exceptions.LockException as exception:
# Try till the timeout is 0
while timeout > 0:
# Wait a bit
......@@ -136,19 +137,19 @@ class Lock(object):
# We already tried to the get the lock
# If fail_when_locked is true, then stop trying
if fail_when_locked:
raise AlreadyLocked(exception)
raise exceptions.AlreadyLocked(exception)
else: # pragma: no cover
# We've got the lock
fh = self._get_lock(fh)
break
except portalocker.LockException:
except exceptions.LockException:
pass
else:
# We got a timeout... reraising
raise portalocker.LockException(exception)
raise exceptions.LockException(exception)
# Prepare the filehandle (truncate if needed)
fh = self._prepare_fh(fh)
......@@ -174,19 +175,16 @@ class Lock(object):
portalocker.lock(fh, self.flags)
return fh
def _prepare_fh(self, fh, truncate=None):
def _prepare_fh(self, fh):
'''
Prepare the filehandle for usage
If truncate is a number, the file will be truncated to that amount of
bytes
'''
if truncate is None:
truncate = self.truncate
if truncate is not None:
fh.seek(truncate)
fh.truncate(truncate)
if self.truncate:
fh.seek(0)
fh.truncate(0)
return fh
......
......@@ -12,6 +12,9 @@ upload-dir = docs/_build/html
[bdist_wheel]
universal = 1
[aliases]
test = pytest
[egg_info]
tag_build =
tag_date = 0
......
import sys
from __future__ import print_function
import re
import os
import setuptools
from setuptools.command.test import test as TestCommand
__package_name__ = 'portalocker'
__author__ = 'Rick van Hattem'
__email__ = 'wolph@wol.ph'
__version__ = '0.6.1'
__description__ = '''Wraps the portalocker recipe for easy usage'''
__url__ = 'https://github.com/WoLpH/portalocker'
extra = {}
if sys.version_info >= (3, 0):
extra.update(use_2to3=True)
# To prevent importing about and thereby breaking the coverage info we use this
# exec hack
about = {}
with open('portalocker/__about__.py') as fp:
exec(fp.read(), about)
test_requirements_file = os.path.join('tests', 'requirements.txt')
if os.path.isfile(test_requirements_file):
with open(test_requirements_file) as fh:
tests_require = fh.read().splitlines()
else:
tests_require = ['pytest>=3.0']
class PyTest(TestCommand):
class Combine(setuptools.Command):
description = 'Build single combined portalocker file'
relative_import_re = re.compile(r'^from \. import (?P<name>.+)$',
re.MULTILINE)
user_options = [
('output-file=', 'o', 'Path to the combined output file'),
]
def initialize_options(self):
self.output_file = os.path.join(
'dist', '%(package_name)s_%(version)s.py' % dict(
package_name=about['__package_name__'],
version=about['__version__'].replace('.', '-'),
))
def finalize_options(self):
TestCommand.finalize_options(self)
self.test_args = ['tests']
self.test_suite = True
pass
def run(self):
dirname = os.path.dirname(self.output_file)
if dirname and not os.path.isdir(dirname):
os.makedirs(dirname)
output = open(self.output_file, 'w')
print("'''", file=output)
with open('README.rst') as fh:
output.write(fh.read().rstrip())
print('', file=output)
print('', file=output)
def run_tests(self):
# import here, cause outside the eggs aren't loaded
import pytest
errno = pytest.main(self.test_args)
sys.exit(errno)
with open('LICENSE') as fh:
output.write(fh.read().rstrip())
print('', file=output)
print("'''", file=output)
names = set()
lines = []
for line in open('portalocker/__init__.py'):
match = self.relative_import_re.match(line)
if match:
names.add(match.group('name'))
with open('portalocker/%(name)s.py' % match.groupdict()) as fh:
line = fh.read()
line = self.relative_import_re.sub('', line)
lines.append(line)
import_attributes = re.compile(r'\b(%s)\.' % '|'.join(names))
for line in lines[:]:
line = import_attributes.sub('', line)
output.write(line)
print('Wrote combined file to %r' % self.output_file)
if __name__ == '__main__':
setuptools.setup(
name=__package_name__,
version=__version__,
description=__description__,
name=about['__package_name__'],
version=about['__version__'],
description=about['__description__'],
long_description=open('README.rst').read(),
classifiers=[
'Intended Audience :: Developers',
......@@ -46,14 +94,19 @@ if __name__ == '__main__':
'Programming Language :: Python :: Implementation :: PyPy',
],
keywords='locking, locks, with statement, windows, linux, unix',
author=__author__,
author_email=__email__,
url=__url__,
author=about['__author__'],
author_em