# Path: weblablib/utils.py
# def create_token(size=None):
#     if size is None:
#         size = 32
#     tok = os.urandom(size)
#     safe_token = base64.urlsafe_b64encode(tok).strip().replace(b'=', b'').replace(b'-', b'_')
#     safe_token = safe_token.decode('utf8')
#     return safe_token
# 
# def _current_session_id():
#     return _current_weblab()._session_id()
# 
# def _current_weblab():
#     if 'weblab' not in current_app.extensions:
#         raise WebLabNotInitializedError("App not initialized with weblab.init_app()")
#     return current_app.extensions['weblab']
# 
# Path: weblablib/exc.py
# class AlreadyRunningError(WebLabError):
#     """When creating a task (:meth:`WebLab.task`) with ``unique='global'`` or ``unique='user'``, the second thread/process attempting to run the same method will obtain this error"""
#     pass
# 
# class TimeoutError(WebLabError):
#     """When joining (:meth:`WebLabTask.join`) a task with a timeout, this error may arise"""
#     pass


import sys
import time
import threading
import traceback
import six
import redis
from werkzeug.local import LocalProxy
from werkzeug.datastructures import ImmutableDict
from flask import g
from weblablib.utils import create_token, _current_session_id, _current_weblab
from weblablib.exc import AlreadyRunningError, TimeoutError
    See also :meth:`WebLab.task`.
    """
    def __init__(self, weblab, task_id):
        self._weblab = weblab
        self._backend = weblab._backend
        self._task_id = task_id
        self._task_data = self._backend.get_task(task_id)
        if self._task_data is None:
            raise ValueError("task id {} not found".format(task_id))

    def join(self, timeout=None, error_on_timeout=True):
        """
        Wait for the task to finish. timeout (in seconds), if set it will raise an exception
        if error_on_timeout, otherwise it will just finish. You can't call this method from
        the task itself (a :class:`TimeoutError` will be raised).

        Be aware that if task1 starts task2 and joins, and task2 joins task1 a deadlock will happen.

        :param timeout: ``None`` (to wait forever) or number of seconds to wait. It accepts float.
        :param error_on_timeout: if ``True``, a :class:`TimeoutError` will be raised.
        """
        if current_task:
            if current_task.task_id == self._task_id:
                raise RuntimeError("Deadlock detected: you're calling join from the task itself")

        initial_time = time.time()
        while not self.retrieve().finished:
            if timeout:
                if time.time() - initial_time > timeout:
                    if error_on_timeout:

# Path: weblablib/utils.py
# def create_token(size=None):
#     if size is None:
#         size = 32
#     tok = os.urandom(size)
#     safe_token = base64.urlsafe_b64encode(tok).strip().replace(b'=', b'').replace(b'-', b'_')
#     safe_token = safe_token.decode('utf8')
#     return safe_token
# 
# def _current_session_id():
#     return _current_weblab()._session_id()
# 
# def _current_weblab():
#     if 'weblab' not in current_app.extensions:
#         raise WebLabNotInitializedError("App not initialized with weblab.init_app()")
#     return current_app.extensions['weblab']
# 
# Path: weblablib/exc.py
# class AlreadyRunningError(WebLabError):
#     """When creating a task (:meth:`WebLab.task`) with ``unique='global'`` or ``unique='user'``, the second thread/process attempting to run the same method will obtain this error"""
#     pass
# 
# class TimeoutError(WebLabError):
#     """When joining (:meth:`WebLabTask.join`) a task with a timeout, this error may arise"""
#     pass


# Path: weblablib/tasks.py
import sys
import time
import threading
import traceback
import six
import redis
from werkzeug.local import LocalProxy
from werkzeug.datastructures import ImmutableDict
from flask import g
from weblablib.utils import create_token, _current_session_id, _current_weblab
from weblablib.exc import AlreadyRunningError, TimeoutError

    See also :meth:`WebLab.task`.
    """
    def __init__(self, weblab, task_id):
        self._weblab = weblab
        self._backend = weblab._backend
        self._task_id = task_id
        self._task_data = self._backend.get_task(task_id)
        if self._task_data is None:
            raise ValueError("task id {} not found".format(task_id))

    def join(self, timeout=None, error_on_timeout=True):
        """
        Wait for the task to finish. timeout (in seconds), if set it will raise an exception
        if error_on_timeout, otherwise it will just finish. You can't call this method from
        the task itself (a :class:`TimeoutError` will be raised).

        Be aware that if task1 starts task2 and joins, and task2 joins task1 a deadlock will happen.

        :param timeout: ``None`` (to wait forever) or number of seconds to wait. It accepts float.
        :param error_on_timeout: if ``True``, a :class:`TimeoutError` will be raised.
        """
        if current_task:
            if current_task.task_id == self._task_id:
                raise RuntimeError("Deadlock detected: you're calling join from the task itself")

        initial_time = time.time()
        while not self.retrieve().finished:
            if timeout:
                if time.time() - initial_time > timeout:
                    if error_on_timeout:

                        raise TimeoutError("{} seconds passed".format(timeout))