Mini Shell
"""Context Managers for RADS.
Context managers modify the behavior of an indented block of code
in some way by silently calling __enter__() and __exit__() when you
change indentation. __exit__() will always be called, even if the
indented code raised an exception. For example in fabric, settings
is a context manager:
def function_name():
with settings(warn_only=True):
run('some_command')
This part of RADS is very closely tied to rads.decorators.
Python 3.2 introduces contextlib.ContextDecorator which allows
something to behave as both a decorator and a context manager.
Older versions of python need to implement this manually.
rads.implementation.contextdecorator works around that.
Decorators modify the behavior of an entire function. For example
in fabric, with_settings is a decorator:
@with_settings(warn_only=True)
def function_name():
run('some_command')
"""
import __main__ as main_obj
import time
from rads.implementation.contextdecorator import contextmanager
from rads.exceptions import S_LockError
import socket
try:
import MySQLdb
MYSQLDB = True
except ImportError:
MYSQLDB = False
import hashlib
@contextmanager
def db_cur(_autocommit=False, _yield_conn=False, *args, **kwargs):
"""Yield a database cursor as a context manager. Args are the same
as with MySQLdb.connect, except for:
_autocommit(default False) whether to set autocommit
_yield_conn(default False) whether to yield conn, cur isntead of just cur"""
if not MYSQLDB:
raise ImportError('imh-python-mysql is not installed')
conn = MySQLdb.connect(*args, **kwargs)
if _autocommit:
conn.autocommit(True)
cur = conn.cursor()
try:
if _yield_conn:
yield conn, cur
else:
yield cur
finally:
cur.close()
conn.close()
@contextmanager
def s_lock(name=None):
"""Create an abstract UNIX socket which will behave as a "lock" or
raise socket.error if the "lock" already existed. This can be used
en lieu of /var/run file pids/locks to determine if an instance of
said process is already running. This method ensures no file locks
are left behind if the process terminates prematurely"""
if name is None:
# caveat: this will crash if run in an interactive python shell
name = main_obj.__file__
lock_socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
try:
lock_socket.bind('\0%s' % hashlib.sha256(name).hexdigest())
except socket.error:
raise S_LockError
try:
yield
finally:
lock_socket.close()
@contextmanager
def wait_lock(name=None, sleep=0.5, max_sleep=None):
if name is None:
# caveat: this will crash if run in an interactive python shell
name = main_obj.__file__
slept = 0.0
while True:
try:
with s_lock(name):
yield
return
except S_LockError:
time.sleep(sleep)
slept += sleep
if max_sleep is not None and slept >= max_sleep:
raise
# rads.decorators inspects this. When adding new context managers to this
# module, please add them to this too.
__rads_context_managers__ = [s_lock, wait_lock]
Zerion Mini Shell 1.0