Package: threaded
threadedthreaded is a set of decorators, which wrap functions in:concurrent.futures.ThreadPoolthreading.Threadasyncio.Taskin Python 3.Why? Because copy-paste ofloop.create_task,threading.Threadandthread_pool.submitis boring,
especially if target functions is used by this way only.Pros:Free software: Apache licenseOpen Source:https://github.com/python-useful-helpers/threadedPyPI packaged:https://pypi.python.org/pypi/threadedTested: see bages on topDecorators:ThreadPooled- nativeconcurrent.futures.ThreadPool.threadpooledis alias forThreadPooled.Threaded- wrap inthreading.Thread.threadedis alias forThreaded.AsyncIOTask- wrap inasyncio.Task. Uses the same API, asThreadPooled.asynciotaskis alias forAsyncIOTask.UsageThreadPooledMostly it is required decorator: submit function to ThreadPoolExecutor on call.threaded.ThreadPooled.configure(max_workers=3)NoteBy default, if executor is not configured - it configures with default parameters:max_workers=CPU_COUNT * 5@threaded.ThreadPooleddeffunc():passconcurrent.futures.wait([func()])Usage with asyncio:Noteifloop_getteris not callable,loop_getter_need_contextis ignored.loop=asyncio.get_event_loop()@threaded.ThreadPooled(loop_getter=loop,loop_getter_need_context=False)deffunc():passloop.run_until_complete(asyncio.wait_for(func(),timeout))Python 3.5+ usage with asyncio and loop extraction from call arguments:loop_getter=lambdatgt_loop:tgt_loop@threaded.ThreadPooled(loop_getter=loop_getter,loop_getter_need_context=True)# loop_getter_need_context is requireddeffunc(*args,**kwargs):passloop=asyncio.get_event_loop()loop.run_until_complete(asyncio.wait_for(func(loop),timeout))During application shutdown, pool can be stopped (while it will be recreated automatically, if some component will request).threaded.ThreadPooled.shutdown()ThreadedClassicthreading.Thread. Useful for running until close and self-closing threads without return.Usage example:@threaded.Threadeddeffunc(*args,**kwargs):passthread=func()thread.start()thread.join()Without arguments, thread name will use pattern:'Threaded: ' + func.__name__NoteIf func.__name__ is not accessible, str(hash(func)) will be used instead.Override name can be don via corresponding argument:@threaded.Threaded(name='Function in thread')deffunc(*args,**kwargs):passThread can be daemonized automatically:@threaded.Threaded(daemon=True)deffunc(*args,**kwargs):passAlso, if no any addition manipulations expected before thread start,
it can be started automatically before return:@threaded.Threaded(started=True)deffunc(*args,**kwargs):passAsyncIOTaskWrap inasyncio.Task.usage with asyncio:@threaded.AsyncIOTaskdeffunc():passloop=asyncio.get_event_loop()loop.run_until_complete(asyncio.wait_for(func(),timeout))Provide event loop directly:Noteifloop_getteris not callable,loop_getter_need_contextis ignored.loop=asyncio.get_event_loop()@threaded.AsyncIOTask(loop_getter=loop)deffunc():passloop.run_until_complete(asyncio.wait_for(func(),timeout))Usage with loop extraction from call arguments:loop_getter=lambdatgt_loop:tgt_loop@threaded.AsyncIOTask(loop_getter=loop_getter,loop_getter_need_context=True)deffunc(*args,**kwargs):passloop=asyncio.get_event_loop()loop.run_until_complete(asyncio.wait_for(func(loop),timeout))TestingThe main test mechanism for the packagethreadedis usingtox.
Available environments can be collected viatox -lCI systemsFor code checking several CI systems is used in parallel:GitHub actions:is used for checking: PEP8, pylint, bandit, installation possibility and unit tests.coveralls:is used for coverage display.CD systemGitHub actions:is used for package delivery on PyPI.