# Path: concert/helpers.py
# def memoize(func):
#     """
#     Memoize the result of *func*.
# 
#     Remember the result of *func* depending on its arguments. Note, that this
#     requires that the function is free from any side effects, e.g. returns the
#     same value given the same arguments.
#     """
#     memo = {}
# 
#     if inspect.iscoroutinefunction(func):
#         async def wrapper(*args):
#             if args in memo:
#                 return memo[args]
# 
#             result = await func(*args)
#             memo[args] = result
#             return result
#     else:
#         def wrapper(*args):
#             if args in memo:
#                 return memo[args]
# 
#             result = func(*args)
#             memo[args] = result
#             return result
# 
#     return wrapper
# 
# Path: concert/coroutines/base.py
# def background(coroutine):
#     """Same as :func:`.start`, just meant to be used as a decorator."""
#     @functools.wraps(coroutine)
#     def inner(*args, **kwargs):
#         return start(coroutine(*args, **kwargs))
# 
#     return inner
# 
# def run_in_loop(coroutine):
#     """Wrap *coroutine* into a `asyncio.Task`, run it in the current loop, block until it finishes
#     and return the result.  On KeyboardInterrupt, the task is cancelled.
#     """
#     loop = asyncio.get_event_loop()
#     task = asyncio.ensure_future(coroutine, loop=loop)
# 
#     try:
#         result = loop.run_until_complete(task)
#         return result
#     except KeyboardInterrupt:
#         # _coro instead of get_coro() for Python 3.7 compatibilityget_coro()
#         LOG.log(AIODEBUG, "KeyboardInterrupt in `%s', cancelling", task._coro.__qualname__)
#         task.cancel()
# 
# async def wait_until(condition, sleep_time=1e-1 * q.s, timeout=None):
#     """Wait until a callable *condition* returns True. *sleep_time* is the time to sleep
#     between consecutive checks of *condition*. If *timeout* is given and the *condition* doesn't
#     return True within the time specified by it a :class:`.WaitingError` is raised.
#     """
#     sleep_time = sleep_time.to(q.s).magnitude
#     if timeout:
#         start = time.time()
#         timeout = timeout.to(q.s).magnitude
# 
#     while not await condition():
#         if timeout and time.time() - start > timeout:
#             raise WaitError('Waiting timed out')
#         await asyncio.sleep(sleep_time)
# 
# Path: concert/quantities.py



import asyncio
import numpy as np
import logging
import functools
import inspect
import types
from concert.helpers import memoize
from concert.coroutines.base import background, run_in_loop, wait_until
from concert.quantities import q
        from concert.session.utils import get_default_table
        from concert.session.utils import get_default_table
        super(QuantityValue, self).__init__(instance, quantity)
        self._lower = quantity.lower
        self._upper = quantity.upper
        self._external_upper_getter = quantity.external_upper_getter
        self._external_lower_getter = quantity.external_lower_getter
        self._user_lower_getter = quantity.user_lower_getter
        self._user_lower_setter = quantity.user_lower_setter
        self._user_upper_getter = quantity.user_upper_getter
        self._user_upper_setter = quantity.user_upper_setter
        self._limits_locked = False

    def lock_limits(self, permanent=False):
        """Lock limits, if *permanent* is True the limits cannot be unlocked anymore."""
        def unlock_not_allowed():
            raise LockError('Limits are locked permanently')

        self._limits_locked = True
        if permanent:
            self.unlock_limits = unlock_not_allowed

    def unlock_limits(self):
        """Unlock limits."""
        self._limits_locked = False

    @property
    def lower(self):
        return run_in_loop(self.get_lower())

    @lower.setter
    def lower(self, value):

# Path: concert/helpers.py
# def memoize(func):
#     """
#     Memoize the result of *func*.
# 
#     Remember the result of *func* depending on its arguments. Note, that this
#     requires that the function is free from any side effects, e.g. returns the
#     same value given the same arguments.
#     """
#     memo = {}
# 
#     if inspect.iscoroutinefunction(func):
#         async def wrapper(*args):
#             if args in memo:
#                 return memo[args]
# 
#             result = await func(*args)
#             memo[args] = result
#             return result
#     else:
#         def wrapper(*args):
#             if args in memo:
#                 return memo[args]
# 
#             result = func(*args)
#             memo[args] = result
#             return result
# 
#     return wrapper
# 
# Path: concert/coroutines/base.py
# def background(coroutine):
#     """Same as :func:`.start`, just meant to be used as a decorator."""
#     @functools.wraps(coroutine)
#     def inner(*args, **kwargs):
#         return start(coroutine(*args, **kwargs))
# 
#     return inner
# 
# def run_in_loop(coroutine):
#     """Wrap *coroutine* into a `asyncio.Task`, run it in the current loop, block until it finishes
#     and return the result.  On KeyboardInterrupt, the task is cancelled.
#     """
#     loop = asyncio.get_event_loop()
#     task = asyncio.ensure_future(coroutine, loop=loop)
# 
#     try:
#         result = loop.run_until_complete(task)
#         return result
#     except KeyboardInterrupt:
#         # _coro instead of get_coro() for Python 3.7 compatibilityget_coro()
#         LOG.log(AIODEBUG, "KeyboardInterrupt in `%s', cancelling", task._coro.__qualname__)
#         task.cancel()
# 
# async def wait_until(condition, sleep_time=1e-1 * q.s, timeout=None):
#     """Wait until a callable *condition* returns True. *sleep_time* is the time to sleep
#     between consecutive checks of *condition*. If *timeout* is given and the *condition* doesn't
#     return True within the time specified by it a :class:`.WaitingError` is raised.
#     """
#     sleep_time = sleep_time.to(q.s).magnitude
#     if timeout:
#         start = time.time()
#         timeout = timeout.to(q.s).magnitude
# 
#     while not await condition():
#         if timeout and time.time() - start > timeout:
#             raise WaitError('Waiting timed out')
#         await asyncio.sleep(sleep_time)
# 
# Path: concert/quantities.py



# Path: concert/base.py
import asyncio
import numpy as np
import logging
import functools
import inspect
import types
from concert.helpers import memoize
from concert.coroutines.base import background, run_in_loop, wait_until
from concert.quantities import q
        from concert.session.utils import get_default_table
        from concert.session.utils import get_default_table

        super(QuantityValue, self).__init__(instance, quantity)
        self._lower = quantity.lower
        self._upper = quantity.upper
        self._external_upper_getter = quantity.external_upper_getter
        self._external_lower_getter = quantity.external_lower_getter
        self._user_lower_getter = quantity.user_lower_getter
        self._user_lower_setter = quantity.user_lower_setter
        self._user_upper_getter = quantity.user_upper_getter
        self._user_upper_setter = quantity.user_upper_setter
        self._limits_locked = False

    def lock_limits(self, permanent=False):
        """Lock limits, if *permanent* is True the limits cannot be unlocked anymore."""
        def unlock_not_allowed():
            raise LockError('Limits are locked permanently')

        self._limits_locked = True
        if permanent:
            self.unlock_limits = unlock_not_allowed

    def unlock_limits(self):
        """Unlock limits."""
        self._limits_locked = False

    @property
    def lower(self):
        return run_in_loop(self.get_lower())

    @lower.setter
    def lower(self, value):

        run_in_loop(self.set_lower(value))