import  asyncio
 
 
def  create_interval( coro,  ms) :
	async def  inner( ) :
		i =  0 
		while  True :
			print ( f'{i} round' ) 
			await asyncio.sleep ( ms/1000 ) 
			await coro( ) 
			i +=  1 
	return  asyncio.create_task ( inner( ) ) 
 
 
def  task_error_handler( cb) :
	def  decorator( func) :
		async def  wrapper( *args,  **kwargs) :
			try :
				result =  await func( *args,  **kwargs) 
			except  Exception  as  exc:
				result =  await cb( exc) 
			return  result
		return  wrapper
	return  decorator
 
 
async def  simple_err_handler( exc) :
	result =  { 'error' : str ( type ( exc) ) } 
	print ( f'EXC OCCURED: {exc}' ) 
	await asyncio.sleep ( 0.5 ) 
	return  result
 
 
async def  test1( ) :
	print ( 'START TEST1' ) 
 
	@ task_error_handler( simple_err_handler) 
	async def  inner( name) :
		print ( f'{name} STARTED' ) 
		await asyncio.sleep ( 0.5 ) 
		raise  RuntimeError ( 'u suck' ) 
		print ( 'NEVER SHOULD BE PRINTED' ) 
		await asyncio.sleep ( 0.5 ) 
 
	t1 =  asyncio.create_task ( inner( 'Beta' ) ) 
	await asyncio.sleep ( 2 ) 
	t1.cancel ( ) 
	print ( 'TASK CANCELLED' ) 
	await asyncio.sleep ( 0.5 ) 
	print ( 'END TEST1' ) 
 
 
async def  test2( ) :
	print ( 'START TEST2' ) 
 
	@ task_error_handler( simple_err_handler) 
	async def  inner( name) :
		print ( f'{name} STARTED' ) 
		await asyncio.sleep ( 0.5 ) 
		raise  RuntimeError ( 'u suck' ) 
		print ( 'NEVER SHOULD BE PRINTED' ) 
		await asyncio.sleep ( 0.5 ) 
 
	t1 =  create_interval( inner( 'Charly' ) ,  500 ) 
	await asyncio.sleep ( 2 ) 
	t1.cancel ( ) 
	print ( 'TASK CANCELLED' ) 
	await asyncio.sleep ( 0.5 ) 
	print ( 'END TEST2' ) 
 
 
def  main( ) :
	asyncio.run ( test1( ) )   # не упадет 
	asyncio.run ( test2( ) )   # тихо сдыхает 
 
 
if  __name__ ==  '__main__' :
	main( ) 
 
				aW1wb3J0IGFzeW5jaW8KCgpkZWYgY3JlYXRlX2ludGVydmFsKGNvcm8sIG1zKToKCWFzeW5jIGRlZiBpbm5lcigpOgoJCWkgPSAwCgkJd2hpbGUgVHJ1ZToKCQkJcHJpbnQoZid7aX0gcm91bmQnKQoJCQlhd2FpdCBhc3luY2lvLnNsZWVwKG1zLzEwMDApCgkJCWF3YWl0IGNvcm8oKQoJCQlpICs9IDEKCXJldHVybiBhc3luY2lvLmNyZWF0ZV90YXNrKGlubmVyKCkpCgoKZGVmIHRhc2tfZXJyb3JfaGFuZGxlcihjYik6CglkZWYgZGVjb3JhdG9yKGZ1bmMpOgoJCWFzeW5jIGRlZiB3cmFwcGVyKCphcmdzLCAqKmt3YXJncyk6CgkJCXRyeToKCQkJCXJlc3VsdCA9IGF3YWl0IGZ1bmMoKmFyZ3MsICoqa3dhcmdzKQoJCQlleGNlcHQgRXhjZXB0aW9uIGFzIGV4YzoKCQkJCXJlc3VsdCA9IGF3YWl0IGNiKGV4YykKCQkJcmV0dXJuIHJlc3VsdAoJCXJldHVybiB3cmFwcGVyCglyZXR1cm4gZGVjb3JhdG9yCgkKCmFzeW5jIGRlZiBzaW1wbGVfZXJyX2hhbmRsZXIoZXhjKToKCXJlc3VsdCA9IHsnZXJyb3InOiBzdHIodHlwZShleGMpKX0KCXByaW50KGYnRVhDIE9DQ1VSRUQ6IHtleGN9JykKCWF3YWl0IGFzeW5jaW8uc2xlZXAoMC41KQoJcmV0dXJuIHJlc3VsdAoJCgphc3luYyBkZWYgdGVzdDEoKToKCXByaW50KCdTVEFSVCBURVNUMScpCgkKCUB0YXNrX2Vycm9yX2hhbmRsZXIoc2ltcGxlX2Vycl9oYW5kbGVyKQoJYXN5bmMgZGVmIGlubmVyKG5hbWUpOgoJCXByaW50KGYne25hbWV9IFNUQVJURUQnKQoJCWF3YWl0IGFzeW5jaW8uc2xlZXAoMC41KQoJCXJhaXNlIFJ1bnRpbWVFcnJvcigndSBzdWNrJykKCQlwcmludCgnTkVWRVIgU0hPVUxEIEJFIFBSSU5URUQnKQoJCWF3YWl0IGFzeW5jaW8uc2xlZXAoMC41KQoJCQoJdDEgPSBhc3luY2lvLmNyZWF0ZV90YXNrKGlubmVyKCdCZXRhJykpCglhd2FpdCBhc3luY2lvLnNsZWVwKDIpCgl0MS5jYW5jZWwoKQoJcHJpbnQoJ1RBU0sgQ0FOQ0VMTEVEJykKCWF3YWl0IGFzeW5jaW8uc2xlZXAoMC41KQoJcHJpbnQoJ0VORCBURVNUMScpCgkKCQphc3luYyBkZWYgdGVzdDIoKToKCXByaW50KCdTVEFSVCBURVNUMicpCgkKCUB0YXNrX2Vycm9yX2hhbmRsZXIoc2ltcGxlX2Vycl9oYW5kbGVyKQoJYXN5bmMgZGVmIGlubmVyKG5hbWUpOgoJCXByaW50KGYne25hbWV9IFNUQVJURUQnKQoJCWF3YWl0IGFzeW5jaW8uc2xlZXAoMC41KQoJCXJhaXNlIFJ1bnRpbWVFcnJvcigndSBzdWNrJykKCQlwcmludCgnTkVWRVIgU0hPVUxEIEJFIFBSSU5URUQnKQoJCWF3YWl0IGFzeW5jaW8uc2xlZXAoMC41KQoJCQoJdDEgPSBjcmVhdGVfaW50ZXJ2YWwoaW5uZXIoJ0NoYXJseScpLCA1MDApCglhd2FpdCBhc3luY2lvLnNsZWVwKDIpCgl0MS5jYW5jZWwoKQoJcHJpbnQoJ1RBU0sgQ0FOQ0VMTEVEJykKCWF3YWl0IGFzeW5jaW8uc2xlZXAoMC41KQoJcHJpbnQoJ0VORCBURVNUMicpCgkKCQpkZWYgbWFpbigpOgoJYXN5bmNpby5ydW4odGVzdDEoKSkgICMg0L3QtSDRg9C/0LDQtNC10YIKCWFzeW5jaW8ucnVuKHRlc3QyKCkpICAjINGC0LjRhdC+INGB0LTRi9GF0LDQtdGCCgkKCmlmIF9fbmFtZV9fID09ICdfX21haW5fXyc6CgltYWluKCk=