Skip to content

Instantly share code, notes, and snippets.

@theelous3
Created November 23, 2018 00:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save theelous3/3991905bbe43414be58f08948b62d473 to your computer and use it in GitHub Desktop.
Save theelous3/3991905bbe43414be58f08948b62d473 to your computer and use it in GitHub Desktop.
from threading import BoundedSemaphore
from types import GeneratorType
from collections.abc import MappingView, Sequence
from functools import partial
_ALLOWED_SEQUENCE_TYPES = (
Sequence,
MappingView,
GeneratorType
)
class Locker:
def __init__(self, obj, blocking=True, read='read', write='write'):
self.obj = obj
self.blocking = blocking
self._write_sema = BoundedSemaphore(value=1)
self._writeable = True
#handle lists of attribes to read and write protect
if not isinstance(read, str):
self._validate_containery_types(read)
read_dict = {
sub_read: partial(self._read, getattr(obj, sub_read))
for sub_read in read
}
else:
read_dict = read_dict = {read: partial(self._read, getattr(obj, read))}
if not isinstance(write, str):
self._validate_containery_types(write)
write_dict = {
sub_write: partial(self._write, getattr(obj, sub_write))
for sub_write in write
}
else:
write_dict = {write: partial(self._write, getattr(obj, write))}
self.__dict__.update(read_dict)
self.__dict__.update(write_dict)
def __getattr__(self, attr):
try:
return self.__dict__[attr]
except KeyError:
raise AttributeError("Locker wrapped '{}' object has no"
" attribute '{}'".format(type(self.obj), attr)
)
def __repr__(self):
return "Locker {} ({} {})".format(
hex(id(self)),
type(self.obj),
hex(id(self.obj)))
def _write(self, wrapped_method, *args, **kwargs):
if self._write_sema._value < 1:
if not self.blocking:
raise RuntimeError(
"Cannot write to non-blocking protected {} when it"
"is in use.".format(type(self.obj))
)
with self._write_sema:
return wrapped_method(*args, **kwargs)
def _read(self, wrapped_method, *args, **kwargs):
if self._write_sema._value < 1:
raise RuntimeError(
"Cannot read to non-blocking protected {} when it"
"is in write.".format(type(self.obj))
)
return wrapped_method(*args, **kwargs)
@staticmethod
def _validate_containery_types(x):
"""
Validates that the thing passed is some sort of sane
container of data. Why is there no collections.abc of
"thing you can put things in that isn't a str"!?
"""
if not isinstance(x, _ALLOWED_SEQUENCE_TYPES):
raise TypeError("Cannot pass {} as container of method names.".format(type(x)))
from io import StringIO
pstr = Locker(StringIO(), read=['getvalue', 'read'])
pstr.write('lol')
pstr.read()
pstr.getvalue()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment