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"]
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))
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()
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")
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())
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")
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
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])
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())
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.", )
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}))
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')
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')
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
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()
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())
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
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.", )
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, )
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")
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
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
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
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()
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)
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")
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)
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()
def to_async(callback, as_task=True): corofunc = sync.sync_to_async(callback) if as_task and pool.pool: corofunc = gentask(corofunc) return corofunc
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()