Commit 8159a6ee authored by SVN-Git Migration's avatar SVN-Git Migration

Imported Upstream version 0.3~ds0

parents
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
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
--------------------------------------------
1. This LICENSE AGREEMENT is between the Python Software Foundation
("PSF"), and the Individual or Organization ("Licensee") accessing and
otherwise using this software ("Python") in source or binary form and
its associated documentation.
2. Subject to the terms and conditions of this License Agreement, PSF hereby
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
analyze, test, perform and/or display publicly, prepare derivative works,
distribute, and otherwise use Python alone or in any derivative version,
provided, however, that PSF's License Agreement and PSF's notice of copyright,
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Python Software Foundation; All Rights Reserved" are retained in Python alone or
in any derivative version prepared by Licensee.
3. In the event Licensee prepares a derivative work that is based on
or incorporates Python or any part thereof, and wants to make
the derivative work available to others as provided herein, then
Licensee hereby agrees to include in any such work a brief summary of
the changes made to Python.
4. PSF is making Python available to Licensee on an "AS IS"
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
6. This License Agreement will automatically terminate upon a material
breach of its terms and conditions.
7. Nothing in this License Agreement shall be deemed to create any
relationship of agency, partnership, or joint venture between PSF and
Licensee. This License Agreement does not grant permission to use PSF
trademarks or trade name in a trademark sense to endorse or promote
products or services of Licensee, or any third party.
8. By copying, installing or otherwise using Python, Licensee
agrees to be bound by the terms and conditions of this License
Agreement.
include CHANGELOG
include README.rest
include LICENSE
############################################
portalocker - Cross-platform locking library
############################################
Overview
--------
Portalocker is a library to provide an easy API to file locking.
Originally created as a Python Recipe by Jonathan Feinberg and Lowell Alleman
http://code.activestate.com/recipes/65203-portalocker-cross-platform-posixnt-api-for-flock-s/
Examples
--------
To make sure your cache generation scripts don't race, use the `Lock` class:
>>> import portalocker
>>> with portalocker.Lock('somefile', timeout=1) as fh:
print >>fh, 'writing some stuff to my cache...'
To lock a file exclusively, use the `lock` method:
>>> import portalocker
>>> file = open('somefile', 'r+')
>>> portalocker.lock(file, portalocker.LOCK_EX)
>>> file.seek(12)
>>> file.write('foo')
>>> file.close()
There is no explicit need to unlock the file as it is automatically unlocked
after `file.close()`. If you still feel the need to manually unlock a file
than you can do it like this:
>>> portalocker.unlock(file)
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()`.
Contact
-------
The module is maintaned by Rick van Hattem <Rick.van.Hattem@Fawo.nl>.
The project resides at https://github.com/WoLpH/portalocker . Bugs and feature
requests can be submitted there. Patches are also very welcome.
Changelog
---------
See CHANGELOG file
License
-------
see the LICENSE file
from portalocker import *
from utils import *
# 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 $
'''
__all__ = [
'lock',
'unlock',
'LOCK_EX',
'LOCK_SH',
'LOCK_NB',
'LockException',
]
import os
class LockException(Exception):
# Error codes:
LOCK_FAILED = 1
if os.name == 'nt':
import win32con
import win32file
import pywintypes
LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
LOCK_SH = 0 # the default
LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
# is there any reason not to reuse the following structure?
__overlapped = pywintypes.OVERLAPPED()
elif os.name == 'posix':
import fcntl
LOCK_EX = fcntl.LOCK_EX
LOCK_SH = fcntl.LOCK_SH
LOCK_NB = fcntl.LOCK_NB
else:
raise RuntimeError, 'PortaLocker only defined for nt and posix platforms'
if os.name == 'nt':
def lock(file, flags):
hfile = win32file._get_osfhandle(file.fileno())
try:
win32file.LockFileEx(hfile, flags, 0, -0x10000, __overlapped)
except pywintypes.error, exc_value:
# error: (33, 'LockFileEx', 'The process cannot access the file because another process has locked a portion of the file.')
if exc_value[0] == 33:
raise LockException(LockException.LOCK_FAILED, exc_value[2])
else:
# Q: Are there exceptions/codes we should be dealing with here?
raise
def unlock(file):
hfile = win32file._get_osfhandle(file.fileno())
try:
win32file.UnlockFileEx(hfile, 0, -0x10000, __overlapped)
except pywintypes.error, exc_value:
if exc_value[0] == 158:
# error: (158, 'UnlockFileEx', 'The segment is already unlocked.')
# To match the 'posix' implementation, silently ignore this error
pass
else:
# Q: Are there exceptions/codes we should be dealing with here?
raise
elif os.name == 'posix':
def lock(file, flags):
try:
fcntl.flock(file.fileno(), flags)
except IOError, exc_value:
# The exception code varies on different systems so we'll catch
# every IO error
raise LockException(*exc_value)
def unlock(file):
fcntl.flock(file.fileno(), fcntl.LOCK_UN)
if __name__ == '__main__':
from time import time, strftime, localtime
import sys
import portalocker
log = open('log.txt', 'a+')
portalocker.lock(log, portalocker.LOCK_EX)
timestamp = strftime('%m/%d/%Y %H:%M:%S\n', localtime(time()))
log.write( timestamp )
print 'Wrote lines. Hit enter to release lock.'
dummy = sys.stdin.readline()
log.close()
from __future__ import with_statement
import time
from . import portalocker
DEFAULT_TIMEOUT = 5
DEFAULT_CHECK_INTERVAL = 0.25
LOCK_METHOD = portalocker.LOCK_EX | portalocker.LOCK_NB
__all__ = [
'Lock',
'AlreadyLocked',
]
class AlreadyLocked(Exception):
pass
class Lock(object):
def __init__(
self,
filename,
mode='a',
truncate=0,
timeout=DEFAULT_TIMEOUT,
check_interval=DEFAULT_CHECK_INTERVAL,
fail_when_locked=True,
):
'''Lock manager with build-in timeout
filename -- filename
mode -- the open mode, 'a' or 'ab' should be used for writing
truncate -- use truncate to emulate 'w' mode, None is disabled, 0 is
truncate to 0 bytes
timeout -- timeout when trying to acquire a lock
check_interval -- check interval while waiting
fail_when_locked -- after the initial lock failed, return an error
or lock the file
fail_when_locked is useful when multiple threads/processes can race
when creating a file. If set to true than the system will wait till
the lock was acquired and then return an AlreadyLocked exception.
Note that the file is opened first and locked later. So using 'w' as
mode will result in truncate _BEFORE_ the lock is checked.
'''
self.fh = None
self.filename = filename
self.mode = mode
self.truncate = truncate
self.timeout = timeout
self.check_interval = check_interval
self.fail_when_locked = fail_when_locked
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'''
if timeout is None:
timeout = self.timeout
if check_interval is None:
check_interval = self.check_interval
if fail_when_locked is None:
fail_when_locked = self.fail_when_locked
# If we already have a filehandle, return it
fh = self.fh
if fh:
return fh
# Get a new filehandler
fh = self._get_fh()
try:
# Try to lock
fh = self._get_lock(fh)
except portalocker.LockException, exception:
# Try till the timeout is 0
while timeout > 0:
# Wait a bit
time.sleep(check_interval)
timeout -= check_interval
# Try again
try:
fh = self._get_lock(fh)
# We've got the lock, now return an error if
# fail_when_locked is True or break if not
if fail_when_locked:
self._release_lock()
raise AlreadyLocked(*exception)
else:
break
except portalocker.LockException:
pass
else:
# We got a timeout... reraising
raise portalocker.LockException(*exception)
# Prepare the filehandle (truncate if needed)
fh = self._prepare_fh(fh)
self.fh = fh
return fh
def _get_fh(self):
'''Get a new filehandle'''
return open(self.filename, self.mode)
def _get_lock(self, fh):
'''
Try to lock the given filehandle
returns LockException if it fails'''
portalocker.lock(fh, LOCK_METHOD)
return fh
def _prepare_fh(self, fh, truncate=None):
'''
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)
return fh
def __enter__(self):
self.fh = self.acquire()
return self.fh
def __exit__(self, type, value, tb):
if self.fh:
self.fh.close()
[egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0
import sys
extra = {}
if sys.version_info >= (3, 0):
extra.update(use_2to3=True)
try:
from setuptools import setup, find_packages
except ImportError:
from distutils.core import setup, find_packages
author = 'Rick van Hattem'
email = 'Rick.van.Hattem@Fawo.nl'
version = '0.3'
desc = '''Wraps the portalocker recipe for easy usage'''
setup(name='portalocker',
version=version,
description=desc,
long_description=open('README.rest').read(),
classifiers=[
'Intended Audience :: Developers',
'Programming Language :: Python',
'Programming Language :: Python :: 2.5',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.1',
],
keywords='locking, locks, with statement, windows, linux, unix',
author=author,
author_email=email,
url='https://github.com/WoLpH/portalocker',
license='PSF',
packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
zip_safe=False,
platforms=['any'],
test_suite='nose.collector',
**extra
)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment