Source code for libres.context.registry
import threading
from contextlib import contextmanager
from libres.modules import errors
from libres.context.core import Context
[docs]def create_default_registry():
""" Creates the default registry for libres. """
import re
from libres.context.registry import Registry
from libres.context.session import SessionProvider
from libres.context.settings import set_default_settings
from libres.context.exposure import Exposure
from uuid import uuid5 as new_namespace_uuid
registry = Registry()
def session_provider(context):
return SessionProvider(context.get_setting('dsn'))
def email_validator_factory(context):
# A very simple and stupid email validator. It's way too simple, but
# it can be extended to do more powerful checks.
def is_valid_email(email):
return re.match(r'[^@]+@[^@]+\.[^@]+', email)
return is_valid_email
def exposure_factory(context):
return Exposure()
def uuid_generator_factory(context):
def uuid_generator(name):
return new_namespace_uuid(
context.get_setting('uuid_namespace'),
'/'.join((context.name, name))
)
return uuid_generator
master = registry.master_context
master.set_service('email_validator', email_validator_factory)
master.set_service('session_provider', session_provider, cache=True)
master.set_service('exposure', exposure_factory)
master.set_service('uuid_generator', uuid_generator_factory)
set_default_settings(master)
master.lock()
return registry
[docs]class Registry(object):
""" Holds a number of contexts, managing their creation and defining
the currently active context.
A global registry instance is found in libres::
from libres import registry
Though if global state is something you need to avoid, you can create
your own version of the registry::
from libres.context.registry import create_default_registry
registry = create_default_registry()
"""
master_context = None
[docs] def __init__(self):
self.thread_lock = threading.RLock()
with self.thread_lock:
self.contexts = {}
self.local = threading.local()
self.master_context = self.register_context('master')
@property
def current_context(self):
if not hasattr(self.local, 'current_context'):
self.local.current_context = self.master_context
return self.local.current_context
def is_existing_context(self, name):
return name in self.contexts
def assert_not_locked(self, name):
if self.get_context(name).locked:
raise errors.ContextIsLocked
def assert_exists(self, name):
if not self.is_existing_context(name):
raise errors.UnknownContext
def assert_does_not_exist(self, name):
if self.is_existing_context(name):
raise errors.ContextAlreadyExists
[docs] def register_context(self, name, replace=False):
""" Registers a new context with the given name and returns it.
"""
with self.thread_lock:
if replace:
if self.is_existing_context(name):
self.assert_not_locked(name)
else:
self.assert_does_not_exist(name)
self.contexts[name] = Context(
name,
registry=self,
parent=self.master_context,
locked=False
)
return self.contexts[name]
def switch_context(self, name):
with self.thread_lock:
self.assert_exists(name)
self.local.current_context = self.get_context(name)
@contextmanager
def context(self, name):
previous = self.current_context.name
self.switch_context(name)
yield self.current_context
self.switch_context(previous)
def get_current_context(self):
return self.current_context
def get_context(self, name, autocreate=False):
if not autocreate:
self.assert_exists(name)
elif not self.is_existing_context(name):
self.register_context(name)
return self.contexts[name]