예제 #1
0
파일: test_sync.py 프로젝트: devxpy/asgiref
async def test_thread_sensitive_outside_async():
    """
    Tests that thread_sensitive SyncToAsync where the outside is async code runs
    in a single, separate thread.
    """

    result_1 = {}
    result_2 = {}

    # Outer sync function
    def outer(result):
        middle(result)

    outer = sync_to_async(outer, thread_sensitive=True)

    # Middle async function
    @async_to_sync
    async def middle(result):
        await inner(result)

    # Inner sync function
    def inner(result):
        result["thread"] = threading.current_thread()

    inner = sync_to_async(inner, thread_sensitive=True)

    # Run it (in supposed parallel!)
    await asyncio.wait([outer(result_1), inner(result_2)])

    # They should not have run in the main thread, but in the same thread
    assert result_1["thread"] != threading.current_thread()
    assert result_1["thread"] == result_2["thread"]
예제 #2
0
    def __call__(self, scope):
        # Close old database connections to prevent usage of timed out connections
        sync_to_async(close_old_connections)()

        # Get the token
        token = parse_qs(scope["query_string"].decode("utf8"))["token"][0]

        # Try to authenticate the user
        try:
            # This will automatically validate the token and raise an error if token is invalid
            UntypedToken(token)
        except (InvalidToken, TokenError) as e:
            # Token is invalid
            return self.inner(dict(scope, user=None))
        else:
            #  Then token is valid, decode it
            decoded_data = jwt_decode(token,
                                      settings.SECRET_KEY,
                                      algorithms=["HS256"])
            # Will return a dictionary like -
            # {
            #     "token_type": "access",
            #     "exp": 1568770772,
            #     "jti": "5c15e80d65b04c20ad34d77b6703251b",
            #     "user_id": 6
            # }
            # Get the user using ID
            user = sync_to_async(User.objects.get)(id=decoded_data["user_id"])

        # Return the inner application directly and let it run everything else
        return self.inner(dict(scope, user=user))
예제 #3
0
파일: test_sync.py 프로젝트: devxpy/asgiref
async def test_thread_sensitive_double_nested_async():
    """
    Tests that thread_sensitive SyncToAsync nests inside itself where the
    outside is async.
    """

    result = {}

    # Sync level 1
    def level1():
        level2()

    level1 = sync_to_async(level1, thread_sensitive=True)

    # Async level 2
    @async_to_sync
    async def level2():
        await level3()

    # Sync level 3
    def level3():
        level4()

    level3 = sync_to_async(level3, thread_sensitive=True)

    # Async level 4
    @async_to_sync
    async def level4():
        result["thread"] = threading.current_thread()

    # Run it
    await level1()
    assert result["thread"] == threading.current_thread()
예제 #4
0
 def post(self, request, *args, **kwargs):
     form = FlavorForm(request.POST)
     if form.is_valid():
         sync_to_async(form.save())
     else:
         return render(request, {'form': form}, "flavor_form.html")
     return redirect("flavor:detail")
예제 #5
0
 def connect(self):
     self.accept()
     async_to_sync(self.channel_layer.group_add("users", self.channel_name))
     user = self.scope['user']
     if user.is_authenticated:
         sync_to_async(self.update_user_status(user, True))
         async_to_sync(self.send_status())
예제 #6
0
async def tran_handler(request):
    """
    view type:test
    content:数据库事务 celery异步 视图异步
    """
    def create_db():
        try:
            with transaction.atomic():
                article = UserLog.objects.create(name="测试", info="测试视图")
            return article.pk
        except Exception as err:
            return err

    article = await sync_to_async(create_db)()
    # https://docs.celeryproject.org/en/stable/userguide/tasks.html#database-transactions
    # 如果任务在提交事务之前开始执行,则存在竞争条件。
    # on_commit成功提交所有事务后,使用回调启动您的Celery任务 django version > 1.9
    # 但是on_commit无法返回匿名函数结果,忽略装饰器,使用with语法保证异步效率
    sync_to_async(
        on_commit(lambda: select.delay(article if article == 1 else 1)))

    res = await sync_to_async(
        select.apply_async((article if article == 1 else 1, )).get)()
    # print(res.keys())
    # return HttpResponseRedirect('/app01/example/')
    return HttpResponse("OK")
예제 #7
0
    async def _get_iam_role_async(account_id, role_name,
                                  conn) -> Optional[Dict[str, Any]]:
        tasks = []
        client = await sync_to_async(boto3_cached_conn)(
            "iam",
            account_number=account_id,
            assume_role=config.get("policies.role_name"),
            read_only=True,
            retry_max_attempts=2,
            client_kwargs=config.get("boto3.client_kwargs", {}),
        )
        role_details = asyncio.ensure_future(
            sync_to_async(client.get_role)(RoleName=role_name))
        tasks.append(role_details)

        all_tasks = [
            get_role_managed_policies,
            get_role_inline_policies,
            list_role_tags,
        ]

        for t in all_tasks:
            tasks.append(
                asyncio.ensure_future(
                    sync_to_async(t)({
                        "RoleName": role_name
                    }, **conn)))

        responses = asyncio.gather(*tasks)
        async_task_result = await responses
        role = async_task_result[0]["Role"]
        role["ManagedPolicies"] = async_task_result[1]
        role["InlinePolicies"] = async_task_result[2]
        role["Tags"] = async_task_result[3]
        return role
예제 #8
0
async def test_fetch_data_from_db(mocker):
    def _sync_batch_load(keys):
        data = Example.objects.filter(id__in=keys)

        return list(data)

    prepare_db = sync_to_async(_prepare_db)
    batch_load = sync_to_async(_sync_batch_load)

    ids = await prepare_db()

    async def idx(keys) -> List[Example]:
        return await batch_load(keys)

    mock_loader = mocker.Mock(side_effect=idx)

    loader = DataLoader(load_fn=mock_loader)

    @strawberry.type
    class Query:
        hello: str = "strawberry"

        @strawberry.field
        async def get_example(self, id: strawberry.ID) -> str:
            example = await loader.load(id)

            return example.name

    schema = strawberry.Schema(query=Query)

    query = f"""{{
        a: getExample(id: "{ids[0]}")
        b: getExample(id: "{ids[1]}")
        c: getExample(id: "{ids[2]}")
        d: getExample(id: "{ids[3]}")
        e: getExample(id: "{ids[4]}")
    }}"""

    factory = RequestFactory()
    request = factory.post(
        "/graphql/", {"query": query}, content_type="application/json"
    )

    response = await AsyncGraphQLView.as_view(schema=schema)(request)
    data = json.loads(response.content.decode())

    assert not data.get("errors")
    assert data["data"] == {
        "a": "This is a demo async 0",
        "b": "This is a demo async 1",
        "c": "This is a demo async 2",
        "d": "This is a demo async 3",
        "e": "This is a demo async 4",
    }

    reset_db = sync_to_async(lambda: Example.objects.all().delete())
    await reset_db()

    mock_loader.assert_called_once_with([str(id_) for id_ in ids])
예제 #9
0
    def disconnect(self, code):
        async_to_sync(
            self.channel_layer.group_discard("users", self.channel_name))

        user = self.scope['user']
        if user.is_authenticated:
            sync_to_async(self.update_user_status(user, False))
            async_to_sync(self.send_status())
예제 #10
0
def test_sync_to_async_fail_non_function():
    """
    async_to_sync raises a TypeError when called with a non-function.
    """
    with pytest.raises(TypeError) as excinfo:
        sync_to_async(1)

    assert excinfo.value.args == (
        "sync_to_async can only be applied to sync functions.", )
예제 #11
0
    def post(self, request, **kwargs):
        quantity = request.POST.get('quantity', 1)
        item = Item.objects.select_related('product').get(
            id=kwargs.get('item_id'))

        sync_to_async(self.add_to_cart(request.user, item, quantity))

        return HttpResponseRedirect(
            reverse('shop_product_detail',
                    kwargs={'product_id': item.product.id}))
예제 #12
0
    def save_model(self, request, obj, form, change):
        """新增或更新时调用"""
        # 调用ModelAdmin中save_model来实现更新或新增
        super().save_model(request, obj, form, change)

        # 附加操作:发出生成静态首页的任务
        print('发出重新生成静态首页的任务')
        sync_to_async(generate_static_index_html(), thread_sensitive=True)
        # 附加操作: 清除首页缓存
        cache.delete('index_page_data')
예제 #13
0
    def delete_model(self, request, obj):
        """删除数据时调用"""
        # 调用ModelAdmin中delete_model来实现删除操作
        super().delete_model(request, obj)

        # 附加操作:发出生成静态首页的任
        print('发出重新生成静态首页的任务')
        sync_to_async(generate_static_index_html(), thread_sensitive=True)
        # 附加操作: 清除首页缓存
        cache.delete('index_page_data')
예제 #14
0
 def create_admin(self, validated_data):
     """ Register new user """
     email = validated_data.get("email")
     """ comparison of password """
     password = BaseUserManager.make_random_password(self)
     user = User.objects.create(email=email, role=constants.ADMIN)
     user.set_password(password)
     user.save()
     """ send mail for admin with generated password """
     sync_to_async(send_email("Admin", user.email, password))
     return user
예제 #15
0
    def create_message(self, sender, recipient, message):
        sync_to_async(print(sender.username, recipient.username))
        msg = MessageSerializer(
            data={
                'sender': sender.id,
                'recipient': recipient.id,
                'message': message
            }
        )

        if msg.is_valid():
            msg.save()
예제 #16
0
def password_reset_token_created(sender, instance, reset_password_token, *args,
                                 **kwargs):
    print(reset_password_token.user.email)
    """
    Handles password reset tokens
    When a token is created, an e-mail needs to be sent to the user
    :param sender: View Class that sent the signal
    :param instance: View Instance that sent the signal
    :param reset_password_token: Token Model Object
    :param args:
    :param kwargs:
    :return:
    """
    # send an e-mail to the user
    year = datetime.date.today().year
    context = {
        'current_user':
        reset_password_token.user,
        'username':
        reset_password_token.user.get_fullname,
        'email':
        reset_password_token.user.email,
        'reset_password_url':
        "{}?token={}".format(
            reverse('account:password_reset:reset-password-request'),
            reset_password_token.key),
        'token':
        reset_password_token.key,
        'life_time':
        settings.DJANGO_REST_MULTITOKENAUTH_RESET_TOKEN_EXPIRY_TIME,
        'year':
        year,
    }

    # render email text
    email_html_message = render_to_string('email/user_reset_password.html',
                                          context)
    email_plaintext_message = render_to_string('email/user_reset_password.txt',
                                               context)

    msg = EmailMultiAlternatives(
        # title:
        "Şifrəni yenilə - {title}".format(title="Tech.az"),
        # message:
        email_plaintext_message,
        # from:
        "*****@*****.**",
        # to:
        [reset_password_token.user.email])

    msg.attach_alternative(email_html_message, "text/html")
    sync_to_async(msg.send())
예제 #17
0
    async def _get_iam_user_async(account_id, user_name,
                                  conn) -> Optional[Dict[str, Any]]:
        tasks = []
        client = await sync_to_async(boto3_cached_conn)(
            "iam",
            account_number=account_id,
            assume_role=config.get("policies.role_name"),
            read_only=True,
            retry_max_attempts=2,
            client_kwargs=config.get("boto3.client_kwargs", {}),
        )
        user_details = asyncio.ensure_future(
            sync_to_async(client.get_user)(UserName=user_name))
        tasks.append(user_details)

        all_tasks = [
            get_user_managed_policies,
            get_user_inline_policies,
        ]

        for t in all_tasks:
            tasks.append(
                asyncio.ensure_future(
                    sync_to_async(t)({
                        "UserName": user_name
                    }, **conn)))

        user_tag_details = asyncio.ensure_future(
            sync_to_async(client.list_user_tags)(UserName=user_name))
        tasks.append(user_tag_details)

        user_group_details = asyncio.ensure_future(
            sync_to_async(client.list_groups_for_user)(UserName=user_name))
        tasks.append(user_group_details)

        responses = asyncio.gather(*tasks)
        async_task_result = await responses
        user = async_task_result[0]["User"]
        user["ManagedPolicies"] = async_task_result[1]
        inline_policies = []
        for name, policy in async_task_result[2].items():
            inline_policies.append({
                "PolicyName": name,
                "PolicyDocument": policy
            })
        user["InlinePolicies"] = inline_policies
        user["Tags"] = async_task_result[3].get("Tags", [])
        user["Groups"] = async_task_result[4].get("Groups", [])
        return user
예제 #18
0
async def test_async_to_sync_fail_partial():
    """
    sync_to_async raises a TypeError when applied to a sync partial.
    """
    with pytest.raises(TypeError) as excinfo:

        async def test_function(*args):
            pass

        partial_function = functools.partial(test_function, 42)
        sync_to_async(partial_function)

    assert excinfo.value.args == (
        "sync_to_async can only be applied to sync functions.",
    )
예제 #19
0
async def test_sync_to_async_uses_executor():
    """
    Tests that SyncToAsync uses the passed in executor correctly.
    """

    class CustomExecutor:
        def __init__(self):
            self.executor = ThreadPoolExecutor(max_workers=1)
            self.times_submit_called = 0

        def submit(self, callable_, *args, **kwargs):
            self.times_submit_called += 1
            return self.executor.submit(callable_, *args, **kwargs)

    expected_result = "expected_result"

    def sync_func():
        return expected_result

    custom_executor = CustomExecutor()
    async_function = sync_to_async(
        sync_func, thread_sensitive=False, executor=custom_executor
    )
    actual_result = await async_function()
    assert actual_result == expected_result
    assert custom_executor.times_submit_called == 1

    pytest.raises(
        TypeError,
        sync_to_async,
        sync_func,
        thread_sensitive=True,
        executor=custom_executor,
    )
예제 #20
0
async def get_stories_async():
    print("prepating to get the stories...")
    await asyncio.sleep(5)
    #time.sleep(5)
    qs = sync_to_async(Story.objects.all())
    print(qs)
    print("stories fetched")
예제 #21
0
async def test_sync_to_async():
    """
    Tests we can call sync functions from an async thread
    (even if the number of thread workers is less than the number of calls)
    """
    # Define sync function
    def sync_function():
        time.sleep(1)
        return 42
    # Wrap it
    async_function = sync_to_async(sync_function)
    # Check it works right
    start = time.monotonic()
    result = await async_function()
    end = time.monotonic()
    assert result == 42
    assert end - start >= 1
    # Set workers to 1, call it twice and make sure that works right
    old_threadpool, sync_to_async.threadpool = sync_to_async.threadpool, ThreadPoolExecutor(max_workers=1)
    try:
        start = time.monotonic()
        await asyncio.wait([async_function(), async_function()])
        end = time.monotonic()
        # It should take at least 2 seconds as there's only one worker.
        assert end - start >= 2
    finally:
        sync_to_async.threadpool = old_threadpool
예제 #22
0
 def adapt_method_mode(
     self,
     is_async,
     method,
     method_is_async=None,
     debug=False,
     name=None,
 ):
     """
     Adapt a method to be in the correct "mode":
     - If is_async is False:
       - Synchronous methods are left alone
       - Asynchronous methods are wrapped with async_to_sync
     - If is_async is True:
       - Synchronous methods are wrapped with sync_to_async()
       - Asynchronous methods are left alone
     """
     if method_is_async is None:
         method_is_async = asyncio.iscoroutinefunction(method)
     if debug and not name:
         name = name or 'method %s()' % method.__qualname__
     if is_async:
         if not method_is_async:
             if debug:
                 logger.debug('Synchronous %s adapted.', name)
             return sync_to_async(method, thread_sensitive=True)
     elif method_is_async:
         if debug:
             logger.debug('Asynchronous %s adapted.', name)
         return async_to_sync(method)
     return method
예제 #23
0
 async def dispatch(self, request, *args, **kwargs):
     """Add async support."""
     self.args = args
     self.kwargs = kwargs
     request = self.initialize_request(request, *args, **kwargs)
     self.request = request
     self.headers = self.default_response_headers
     try:
         await sync_to_async(self.initial)(request, *args,
                                           **kwargs)  # MODIFIED HERE
         if request.method.lower() in self.http_method_names:
             handler = getattr(self, request.method.lower(),
                               self.http_method_not_allowed)
         else:
             handler = self.http_method_not_allowed
         # accept both async and sync handlers
         # built-in handlers are sync handlers
         if not asyncio.iscoroutinefunction(handler):  # MODIFIED HERE
             handler = sync_to_async(handler)  # MODIFIED HERE
         response = await handler(request, *args, **kwargs)  # MODIFIED HERE
     except Exception as exc:
         response = self.handle_exception(exc)
     self.response = self.finalize_response(request, response, *args,
                                            **kwargs)
     return self.response
예제 #24
0
    async def example_async(self) -> str:
        def _get_name():
            return Example.objects.first().name

        get_name = sync_to_async(_get_name)

        return await get_name()
예제 #25
0
파일: test_sync.py 프로젝트: devxpy/asgiref
async def test_sync_to_async():
    """
    Tests we can call sync functions from an async thread
    (even if the number of thread workers is less than the number of calls)
    """

    # Define sync function
    def sync_function():
        time.sleep(1)
        return 42

    # Ensure outermost detection works
    # Wrap it
    async_function = sync_to_async(sync_function)
    # Check it works right
    start = time.monotonic()
    result = await async_function()
    end = time.monotonic()
    assert result == 42
    assert end - start >= 1
    # Set workers to 1, call it twice and make sure that works right
    loop = asyncio.get_event_loop()
    old_executor = loop._default_executor
    loop.set_default_executor(ThreadPoolExecutor(max_workers=1))
    try:
        start = time.monotonic()
        await asyncio.wait([async_function(), async_function()])
        end = time.monotonic()
        # It should take at least 2 seconds as there's only one worker.
        assert end - start >= 2
    finally:
        loop.set_default_executor(old_executor)
예제 #26
0
async def get_movies_async():
    print("preparing to get the movies... ")
    await asyncio.sleep(2)
    #time.sleep(2)
    qs = sync_to_async(Movie.objects.all())
    print(qs)
    print("movies fetched")
예제 #27
0
 async def asgi_wrapper(receive, send):
     try:
         return await application(receive, send)
     except Exception:
         traceback = get_current_traceback(
             skip=1,
             show_hidden_frames=self.show_hidden_frames,
             ignore_system_exceptions=True)
         for frame in traceback.frames:
             self.frames[frame.id] = frame
         self.tracebacks[traceback.id] = traceback
         environ = utils.message_to_environ(self.scope)
         is_trusted = sync_to_async(self.check_pin_trust)(environ)
         _traceback = traceback.render_full(evalex=self.evalex,
                                            evalex_trusted=is_trusted,
                                            secret=self.secret).encode(
                                                'utf-8', 'replace')
         headers = [
             (b'Content-Type', b'text/html; charset=utf-8'),
             # Disable Chrome's XSS protection, the debug
             # output can cause false-positives.
             (b'X-XSS-Protection', b'0'),
         ]
         response = http_response(self.scope,
                                  body=_traceback,
                                  status=500,
                                  headers=headers)
         return await response(receive, send)
예제 #28
0
파일: test_sync.py 프로젝트: devxpy/asgiref
async def test_async_to_sync_to_async():
    """
    Tests we can call async functions from a sync thread created by async_to_sync
    (even if the number of thread workers is less than the number of calls)
    """
    result = {}

    # Define async function
    async def inner_async_function():
        result["worked"] = True
        result["thread"] = threading.current_thread()
        return 65

    # Define sync function
    def sync_function():
        return async_to_sync(inner_async_function)()

    # Wrap it
    async_function = sync_to_async(sync_function)
    # Check it works right
    number = await async_function()
    assert number == 65
    assert result["worked"]
    # Make sure that it didn't needlessly make a new async loop
    assert result["thread"] == threading.current_thread()
예제 #29
0
def to_async(callback, as_task=True):
    corofunc = sync.sync_to_async(callback)

    if as_task and pool.pool:
        corofunc = gentask(corofunc)

    return corofunc
예제 #30
0
def async_add(manager, instance):
    """
    Returns `object.related_name.add(instance)` as an async func so it can be called by `await`.
    """

    func = functools.partial(manager.add, instance)
    async_func = sync_to_async(func)
    return async_func()