معرفی شرکت ها


asynckivy-0.6.0.dev0


Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر

توضیحات

Async library for Kivy
ویژگی مقدار
سیستم عامل -
نام فایل asynckivy-0.6.0.dev0
نام asynckivy
نسخه کتابخانه 0.6.0.dev0
نگهدارنده []
ایمیل نگهدارنده []
نویسنده Nattōsai Mitō
ایمیل نویسنده flow4re2c@gmail.com
آدرس صفحه اصلی https://github.com/gottadiveintopython/asynckivy
آدرس اینترنتی https://pypi.org/project/asynckivy/
مجوز MIT
# AsyncKivy [Youtube](https://www.youtube.com/playlist?list=PLNdhqAjzeEGjTpmvNck4Uykps8s9LmRTJ) [日本語doc](https://github.com/gottadiveintopython/asynckivy/blob/main/README_jp.md) `asynckivy` is an async library that saves you from ugly callback-based code, like most of async libraries do. Let's say you want to do: 1. `print('A')` 1. wait for 1sec 1. `print('B')` 1. wait for a button to be pressed 1. `print('C')` in that order. Your code would look like this: ```python from kivy.clock import Clock def what_you_want_to_do(button): print('A') def one_sec_later(__): print('B') button.bind(on_press=on_button_press) Clock.schedule_once(one_sec_later, 1) def on_button_press(button): button.unbind(on_press=on_button_press) print('C') ``` It's barely readable and not easy to understand. If you use `asynckivy`, the code above will become: ```python import asynckivy as ak async def what_you_want_to_do(button): print('A') await ak.sleep(1) print('B') await ak.event(button, 'on_press') print('C') ``` ## Installation If you use this module, it's recommended to pin the minor version, because if it changed, it means some *important* breaking changes occurred. ```text poetry add asynckivy@~0.5 pip install "asynckivy>=0.5,<0.6" ``` ## Usage ```python import asynckivy as ak async def some_task(button): # wait for 1sec dt = await ak.sleep(1) print(f'{dt} seconds have passed') # wait until a button is pressed await ak.event(button, 'on_press') # wait until 'button.x' changes __, x = await ak.event(button, 'x') print(f'button.x is now {x}') # wait until 'button.x' becomes greater than 100 if button.x <= 100: __, x = await ak.event(button, 'x', filter=lambda __, x: x>100) print(f'button.x is now {x}') # wait until EITHER a button is pressed OR 5sec passes. # i.e. wait at most 5 seconds for a button to be pressed tasks = await ak.or_( ak.event(button, 'on_press'), ak.sleep(5), ) print("The button was pressed" if tasks[0].done else "Timeout") # wait until a button is pressed AND 5sec passes. tasks = await ak.and_( ak.event(button, 'on_press'), ak.sleep(5), ) # nest as you want. # wait for a button to be pressed AND (5sec OR 'other_async_func' to complete) tasks = await ak.and_( ak.event(button, 'on_press'), ak.or_( ak.sleep(5), other_async_func(), ), ) child_tasks = tasks[1].result print("5sec passed" if child_tasks[0].done else "other_async_func has completed") ak.start(some_task(some_button)) ``` ### animation ```python import asynckivy as ak async def some_task(widget): # start an animation and wait for the completion. # keyword-arguments are the same as kivy.animation.Animation's. await ak.animate(widget, width=200, t='in_out_quad', d=.5) # interpolate between the values 0 and 200 in an async-manner. # keyword-arguments are the same as kivy.animation.Animation's. async for v in ak.interpolate(0, 200, s=.2, d=2, t='linear'): print(v) # await ak.sleep(1) # Do not await anything during this iteration # change the text of Label with fade-transition label = Label(...) async with ak.fade_transition(label): label.text = 'new text' # If you want more low-level control over animations, use the vanim module. # Read the module doc for details. from asynckivy import vanim async for dt in vanim.delta_time(): ... ``` ### touch handling You can easily handle `on_touch_xxx` events via `asynckivy.rest_of_touch_moves()`. ```python import asynckivy as ak class Painter(RelativeLayout): def on_touch_down(self, touch): if self.collide_point(*touch.opos): ak.start(self.draw_rect(touch)) return True async def draw_rect(self, touch): from kivy.graphics import Line, Color, Rectangle from kivy.utils import get_random_color with self.canvas: Color(*get_random_color()) line = Line(width=2) ox, oy = self.to_local(*touch.opos) async for __ in ak.rest_of_touch_moves(self, touch): # This part is iterated everytime 'on_touch_move' is fired. x, y = self.to_local(*touch.pos) min_x, max_x = (x, ox) if x < ox else (ox, x) min_y, max_y = (y, oy) if y < oy else (oy, y) line.rectangle = (min_x, min_y, max_x - min_x, max_y - min_y, ) # await ak.sleep(1) # Do not await anything during this iteration else: print("'on_touch_up' was fired") ``` ### threading `asynckivy` does not have any I/O primitives like Trio and asyncio do, thus threads are the only way to perform them without blocking the main-thread: ```python from concurrent.futures import ThreadPoolExecuter import asynckivy as ak executer = ThreadPoolExecuter() def thread_blocking_operation(): '''This function is called from outside the main-thread, so you are not allowed to touch gui components here.''' async def some_task(): # create a new thread, run a function inside it, then # wait for the completion of that thread r = await ak.run_in_thread(thread_blocking_operation) print("return value:", r) # run a function inside a ThreadPoolExecuter, and wait for the completion # (ProcessPoolExecuter is not supported) r = await ak.run_in_executer(thread_blocking_operation, executer) print("return value:", r) ``` Exceptions(not BaseExceptions) are propagated to the caller so you can catch them like you do in synchronous code: ```python import requests import asynckivy as ak async def some_task(label): try: response = await ak.run_in_thread(lambda: requests.get('htt...', timeout=10)) except requests.Timeout: label.text = "TIMEOUT!" else: label.text = "RECEIVED: " + response.text ``` ### synchronizing and communicating between tasks There is a [trio.Event](https://trio.readthedocs.io/en/stable/reference-core.html#trio.Event) equivalent. ```python import asynckivy as ak async def task_A(e): print('A1') await e.wait() print('A2') async def task_B(e): print('B1') await e.wait() print('B2') e = ak.Event() ak.start(task_A(e)) # A1 ak.start(task_B(e)) # B1 e.set() # A2 # B2 ``` Unlike Trio's and asyncio's, when you call ``Event.set()``, the tasks waiting for it to happen will *immediately* be resumed. As a result, ``e.set()`` will return *after* ``A2`` and ``B2`` are printed. And there is an [asyncio.Queue](https://docs.python.org/3/library/asyncio-queue.html) equivalent. ```python from kivy.app import App import asynckivy as ak from asynckivy.queue import Queue async def producer(q, items): for i in items: await q.put(i) q.close() async def consumer(q): assert ''.join([item async for item in q]) == 'ABCD' # Queue is async-iterable async def consumer2(q): '''The ``consumer()`` above can be written in more primitive way like this''' items = [] try: while True: items.append(await q.get()) except ak.EndOfResource: assert ''.join(items) == 'ABCD' q = Queue() ak.start(producer(q, 'ABCD')) ak.start(consumer(q)) App().run() # Queue relies on Clock so you need to run the event-loop ``` ### dealing with cancellations ``asynckivy.start()`` returns a ``Task``, which can be used to cancel the execution. ```python task = asynckivy.start(async_func()) ... task.cancel() ``` When `.cancel()` is called, `GeneratorExit` will occur inside the task, which means you can prepare for cancellations as follows: ```python async def async_func(): try: ... except GeneratorExit: print('cancelled') raise # You must re-raise !! finally: print('cleanup resources here') ``` You are not allowed to `await` inside `except-GeneratorExit-clause` and `finally-clause` if you want the task to be cancellable because cancellations always must be done immediately. ```python async def async_func(): try: await something # <-- ALLOWED except Exception: await something # <-- ALLOWED except GeneratorExit: await something # <-- NOT ALLOWED raise finally: await something # <-- NOT ALLOWED ``` You are allowed to `await` inside `finally-clause` if the task will never get cancelled. ```python async def async_func(): # Assuming this never gets cancelled try: await something # <-- ALLOWED except Exception: await something # <-- ALLOWED finally: await something # <-- ALLOWED ``` As long as you follow the above rules, you can cancel tasks as you wish. But note that if there are lots of explicit calls to `Task.cancel()` in your code, **it's a sign of your code being not well-structured**. You can usually avoid it by using `asynckivy.and_()` and `asynckivy.or_()`. ### misc ```python import asynckivy as ak # schedule an awaitable/Task to start after the next frame ak.start_soon(awaitable_or_task) ``` ## Notes ### Places you cannot await I already mentioned about this but I'll say again. **You cannot await while iterating `rest_of_touch_moves()` or `interpolate()`.** ```python import asynckivy as ak async def async_fn(): async for v in ak.interpolate(...): await something # <-- NOT ALLOWED async for __ in ak.rest_of_touch_moves(...): await something # <-- NOT ALLOWED ``` ### asynckivy cannot be used with asyncio or trio `asyncio` and `trio` do some hacky stuff, `sys.set_asyncgen_hooks()` and `sys.get_asyncgen_hooks`, which likely hinders asynckivy-flavored async generators. You can see its details [here](https://peps.python.org/pep-0525/#finalization). I don't know how to make it work. Maybe if [PEP355](https://peps.python.org/pep-0533/) is accepted, it might work. ### Structured Concurrency (This section is incomplete, and will be filled some day.) `asynckivy.and_()` and `asynckivy.or_()` follow the concept of [structured concurrency][njs_sc]. ```python import asynckivy as ak async def root(): await ak.or_(child1(), child2()) async def child1(): ... async def child2(): await ak.and_(ground_child1(), ground_child2()) async def ground_child1(): ... async def ground_child2(): ... ``` ```mermaid flowchart TB root --> C1(child 1) & C2(child 2) C2 --> GC1(ground child 1) & GC2(ground child 2) ``` ## Tested on - CPython 3.7 + Kivy 2.1.0 - CPython 3.8 + Kivy 2.1.0 - CPython 3.9 + Kivy 2.1.0 - CPython 3.10 + Kivy 2.1.0 ## Why this even exists Kivy supports two legit async libraries, [asyncio][asyncio] and [Trio][trio], from version 2.0.0 so developing another one seems [reinventing the wheel][reinventing]. Actually, I started this one just for learning how async/await works so it *was* initially "reinventing the wheel". But after playing with Trio and Kivy for a while, I noticed that Trio is not suitable for the situation where fast reactions are required e.g. touch events. The same is true of asyncio. You can confirm it by running `investigation/why_xxx_is_not_suitable_for_handling_touch_events.py`, and masshing a mouse button. You'll see sometimes `up` is not paired with `down`. You'll see the coordinates aren't relative to the `RelativeLayout` even though the `target` belongs to it. The cause of those problems is that `trio.Event.set()` and `asyncio.Event.set()` don't *immediately* resume the tasks waiting for the `Event` to be set. They just schedule the tasks to resume. Same thing can be said to `nursery.start_soon()` and `asyncio.create_task()`. Trio and asyncio are async **I/O** libraries after all. They probably don't have to immediately resumes/starts tasks, which I think necessary for Kivy's touch handling. (If a touch is not handled immediately, its coordinate's origin may change, its `pos` might be updated and the previous value will be lost.) Their core design might not be suitable for GUI in the first place. That's why I'm still developing this `asynckivy` library to this day. [asyncio]:https://docs.python.org/3/library/asyncio.html [trio]:https://trio.readthedocs.io/en/stable/ [reinventing]:https://en.wikipedia.org/wiki/Reinventing_the_wheel [njs_sc]:https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/


نیازمندی

مقدار نام
>=0.5,<0.6 asyncgui


زبان مورد نیاز

مقدار نام
>=3.7,<4.0 Python


نحوه نصب


نصب پکیج whl asynckivy-0.6.0.dev0:

    pip install asynckivy-0.6.0.dev0.whl


نصب پکیج tar.gz asynckivy-0.6.0.dev0:

    pip install asynckivy-0.6.0.dev0.tar.gz