diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | python-awaitwhat.spec | 597 | ||||
-rw-r--r-- | sources | 1 |
3 files changed, 599 insertions, 0 deletions
@@ -0,0 +1 @@ +/awaitwhat-21.1.tar.gz diff --git a/python-awaitwhat.spec b/python-awaitwhat.spec new file mode 100644 index 0000000..1d851b8 --- /dev/null +++ b/python-awaitwhat.spec @@ -0,0 +1,597 @@ +%global _empty_manifest_terminate_build 0 +Name: python-awaitwhat +Version: 21.1 +Release: 1 +Summary: async/await introspection +License: MIT +URL: https://github.com/dimaqq/awaitwhat +Source0: https://mirrors.aliyun.com/pypi/web/packages/08/fd/2c94a7ed767a24c73f1c85016825a1474d2f2ba27168658af81173d8068e/awaitwhat-21.1.tar.gz +BuildArch: noarch + + +%description +# Await, What? + +Tells you what waits for what in an `async/await` program. + +### Python 3.10.0a1 + +It seems the API was changed in 3.10 and the C extension doesn't compile. +I'll investigate... + +### Alpine + +You'll need `apk add build-base openssl-dev libffi-dev` + +## 2019 Sprint Setup + +Comms: https://gitter.im/awaitwhat/community + +* Python 3.9, Python 3.8 (preferred) or Python 3.7 +* Your platform dev tools (compiler, etc). +* Ensure that `python` is 3.9 or 3.8 or 3.7 +* Install `poetry` +* Install `graphviz` +* Clone this repository +* Look at [tests](https://github.com/dimaqq/awaitwhat/tree/master/test) +* Look at [issues](https://github.com/dimaqq/awaitwhat/issues) + +```console +> python --version +Python 3.9.0b4 #🧡 +Python 3.8.4 #👌 + +> dot -V +dot - graphviz version 2.40.1 + +> curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python +# add ~/.poetry/bin to your PATH + +> git clone git@github.com:dimaqq/awaitwhat.git +> cd awaitwhat +~/awaitwhat (dev|✔) > poetry shell # creates a venv and drops you in it + +(awaitwhat-x-py3.9) ~/awaitwhat (dev|✔) > poetry install # installs projects dependencies in a venv +(awaitwhat-x-py3.9) ~/awaitwhat (dev|✔) > poetry build # builds a C extension in this project + +(awaitwhat-x-py3.9) ~/awaitwhat (dev|✔) > env PYTHONPATH=. python examples/test_shield.py | tee graph.dot +(awaitwhat-x-py3.9) ~/awaitwhat (dev|✔) > dot -Tsvg graph.dot -o graph.svg +(awaitwhat-x-py3.9) ~/awaitwhat (dev|✔) > open graph.svg # or load it in a browser +``` + +### TL;DR + +Say you have this code: +```py + +async def job(): + await foo() + + +async def foo(): + await bar() + + +async def bar(): + await baz() + + +async def baz(): + await leaf() + + +async def leaf(): + await asyncio.sleep(1) # imagine you don't know this + + +async def work(): + await asyncio.gather(..., job()) +``` + +Now that code is stuck and and you want to know why. + +#### Python built-in +```py +Stack for <Task pending coro=<job() …> wait_for=<Future pending cb=[<TaskWakeupMethWrapper …>()]> cb=[…]> (most recent call last): + File "test/test_stack.py", line 34, in job + await foo() +``` + +#### This library +```py +Stack for <Task pending coro=<job() …> wait_for=<Future pending cb=[<TaskWakeupMethWrapper …>()]> cb=[…]> (most recent call last): + File "test/test_stack.py", line 34, in job + await foo() + File "test/test_stack.py", line 38, in foo + await bar() + File "test/test_stack.py", line 42, in bar + await baz() + File "test/test_stack.py", line 46, in baz + await leaf() + File "test/test_stack.py", line 50, in leaf + await asyncio.sleep(1) + File "/…/asyncio/tasks.py", line 568, in sleep + return await future + File "<Sentinel>", line 0, in <_asyncio.FutureIter object at 0x7fb6981690d8>: … +``` + +### Dependency Graph + +<img src="https://raw.github.com/dimaqq/awaitwhat/master/doc/test_future.svg?sanitize=true"> + +### References + +https://mail.python.org/archives/list/async-sig@python.org/thread/6E2LRVLKYSMGEAZ7OYOYR3PMZUUYSS3K/ + +> Hi group, +> +> I'm recently debugging a long-running asyncio program that appears to get stuck about once a week. +> +> The tools I've discovered so far are: +> * high level: `asyncio.all_tasks()` + `asyncio.Task.get_stack()` +> * low level: `loop._selector._fd_to_key` +> +> What's missing is the middle level, i.e. stack-like linkage of what is waiting for what. For a practical example, consider: +> +> ```py +> async def leaf(): await somesocket.recv() +> async def baz(): await leaf() +> async def bar(): await baz() +> async def foo(): await bar() +> async def job(): await foo() +> async def work(): await asyncio.gather(..., job()) +> async def main(): asyncio.run(work()) +> ``` +> +> The task stack will contain: +> * main and body of work with line number +> * job task with line number pointing to foo +> +> The file descriptor mapping, socket fd, `loop._recv()` and a `Future`. +> +> What's missing are connections `foo->bar->baz->leaf`. +> That is, I can't tell which task is waiting for what terminal `Future`. +> +> Is this problem solved in some way that I'm not aware of? +> Is there a library or external tool for this already? +> +> Perhaps, if I could get a list of all pending coroutines, I could figure out what's wrong. +> +> If no such API exists, I'm thinking of the following: +> +> ```py +> async def foo(): +> await bar() +> +> In [37]: dis.dis(foo) +> 1 0 LOAD_GLOBAL 0 (bar) +> 2 CALL_FUNCTION 0 +> 4 GET_AWAITABLE +> 6 LOAD_CONST 0 (None) +> 8 YIELD_FROM +> 10 POP_TOP +> 12 LOAD_CONST 0 (None) +> 14 RETURN_VALUE +> ``` +> +> Starting from a pending task, I'd get it's coroutine and: +> +> Get the coroutine frame, and if current instruction is `YIELD_FROM`, then the reference to the awaitable should be on the top of the stack. +> If that reference points to a pending coroutine, I'd add that to the "forward trace" and repeat. +> +> At some point I'd reach an awaitable that's not a pending coroutine, which may be: another `Task` (I already got those), a low-level `Future` (can be looked up in event loop), an `Event` (tough luck, shoulda logged all `Event`'s on creation) or a dozen other corner cases. +> +> What do y'all think of this approach? +> +> Thanks, +> D. + + +%package -n python3-awaitwhat +Summary: async/await introspection +Provides: python-awaitwhat +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: python3-pip +%description -n python3-awaitwhat +# Await, What? + +Tells you what waits for what in an `async/await` program. + +### Python 3.10.0a1 + +It seems the API was changed in 3.10 and the C extension doesn't compile. +I'll investigate... + +### Alpine + +You'll need `apk add build-base openssl-dev libffi-dev` + +## 2019 Sprint Setup + +Comms: https://gitter.im/awaitwhat/community + +* Python 3.9, Python 3.8 (preferred) or Python 3.7 +* Your platform dev tools (compiler, etc). +* Ensure that `python` is 3.9 or 3.8 or 3.7 +* Install `poetry` +* Install `graphviz` +* Clone this repository +* Look at [tests](https://github.com/dimaqq/awaitwhat/tree/master/test) +* Look at [issues](https://github.com/dimaqq/awaitwhat/issues) + +```console +> python --version +Python 3.9.0b4 #🧡 +Python 3.8.4 #👌 + +> dot -V +dot - graphviz version 2.40.1 + +> curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python +# add ~/.poetry/bin to your PATH + +> git clone git@github.com:dimaqq/awaitwhat.git +> cd awaitwhat +~/awaitwhat (dev|✔) > poetry shell # creates a venv and drops you in it + +(awaitwhat-x-py3.9) ~/awaitwhat (dev|✔) > poetry install # installs projects dependencies in a venv +(awaitwhat-x-py3.9) ~/awaitwhat (dev|✔) > poetry build # builds a C extension in this project + +(awaitwhat-x-py3.9) ~/awaitwhat (dev|✔) > env PYTHONPATH=. python examples/test_shield.py | tee graph.dot +(awaitwhat-x-py3.9) ~/awaitwhat (dev|✔) > dot -Tsvg graph.dot -o graph.svg +(awaitwhat-x-py3.9) ~/awaitwhat (dev|✔) > open graph.svg # or load it in a browser +``` + +### TL;DR + +Say you have this code: +```py + +async def job(): + await foo() + + +async def foo(): + await bar() + + +async def bar(): + await baz() + + +async def baz(): + await leaf() + + +async def leaf(): + await asyncio.sleep(1) # imagine you don't know this + + +async def work(): + await asyncio.gather(..., job()) +``` + +Now that code is stuck and and you want to know why. + +#### Python built-in +```py +Stack for <Task pending coro=<job() …> wait_for=<Future pending cb=[<TaskWakeupMethWrapper …>()]> cb=[…]> (most recent call last): + File "test/test_stack.py", line 34, in job + await foo() +``` + +#### This library +```py +Stack for <Task pending coro=<job() …> wait_for=<Future pending cb=[<TaskWakeupMethWrapper …>()]> cb=[…]> (most recent call last): + File "test/test_stack.py", line 34, in job + await foo() + File "test/test_stack.py", line 38, in foo + await bar() + File "test/test_stack.py", line 42, in bar + await baz() + File "test/test_stack.py", line 46, in baz + await leaf() + File "test/test_stack.py", line 50, in leaf + await asyncio.sleep(1) + File "/…/asyncio/tasks.py", line 568, in sleep + return await future + File "<Sentinel>", line 0, in <_asyncio.FutureIter object at 0x7fb6981690d8>: … +``` + +### Dependency Graph + +<img src="https://raw.github.com/dimaqq/awaitwhat/master/doc/test_future.svg?sanitize=true"> + +### References + +https://mail.python.org/archives/list/async-sig@python.org/thread/6E2LRVLKYSMGEAZ7OYOYR3PMZUUYSS3K/ + +> Hi group, +> +> I'm recently debugging a long-running asyncio program that appears to get stuck about once a week. +> +> The tools I've discovered so far are: +> * high level: `asyncio.all_tasks()` + `asyncio.Task.get_stack()` +> * low level: `loop._selector._fd_to_key` +> +> What's missing is the middle level, i.e. stack-like linkage of what is waiting for what. For a practical example, consider: +> +> ```py +> async def leaf(): await somesocket.recv() +> async def baz(): await leaf() +> async def bar(): await baz() +> async def foo(): await bar() +> async def job(): await foo() +> async def work(): await asyncio.gather(..., job()) +> async def main(): asyncio.run(work()) +> ``` +> +> The task stack will contain: +> * main and body of work with line number +> * job task with line number pointing to foo +> +> The file descriptor mapping, socket fd, `loop._recv()` and a `Future`. +> +> What's missing are connections `foo->bar->baz->leaf`. +> That is, I can't tell which task is waiting for what terminal `Future`. +> +> Is this problem solved in some way that I'm not aware of? +> Is there a library or external tool for this already? +> +> Perhaps, if I could get a list of all pending coroutines, I could figure out what's wrong. +> +> If no such API exists, I'm thinking of the following: +> +> ```py +> async def foo(): +> await bar() +> +> In [37]: dis.dis(foo) +> 1 0 LOAD_GLOBAL 0 (bar) +> 2 CALL_FUNCTION 0 +> 4 GET_AWAITABLE +> 6 LOAD_CONST 0 (None) +> 8 YIELD_FROM +> 10 POP_TOP +> 12 LOAD_CONST 0 (None) +> 14 RETURN_VALUE +> ``` +> +> Starting from a pending task, I'd get it's coroutine and: +> +> Get the coroutine frame, and if current instruction is `YIELD_FROM`, then the reference to the awaitable should be on the top of the stack. +> If that reference points to a pending coroutine, I'd add that to the "forward trace" and repeat. +> +> At some point I'd reach an awaitable that's not a pending coroutine, which may be: another `Task` (I already got those), a low-level `Future` (can be looked up in event loop), an `Event` (tough luck, shoulda logged all `Event`'s on creation) or a dozen other corner cases. +> +> What do y'all think of this approach? +> +> Thanks, +> D. + + +%package help +Summary: Development documents and examples for awaitwhat +Provides: python3-awaitwhat-doc +%description help +# Await, What? + +Tells you what waits for what in an `async/await` program. + +### Python 3.10.0a1 + +It seems the API was changed in 3.10 and the C extension doesn't compile. +I'll investigate... + +### Alpine + +You'll need `apk add build-base openssl-dev libffi-dev` + +## 2019 Sprint Setup + +Comms: https://gitter.im/awaitwhat/community + +* Python 3.9, Python 3.8 (preferred) or Python 3.7 +* Your platform dev tools (compiler, etc). +* Ensure that `python` is 3.9 or 3.8 or 3.7 +* Install `poetry` +* Install `graphviz` +* Clone this repository +* Look at [tests](https://github.com/dimaqq/awaitwhat/tree/master/test) +* Look at [issues](https://github.com/dimaqq/awaitwhat/issues) + +```console +> python --version +Python 3.9.0b4 #🧡 +Python 3.8.4 #👌 + +> dot -V +dot - graphviz version 2.40.1 + +> curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python +# add ~/.poetry/bin to your PATH + +> git clone git@github.com:dimaqq/awaitwhat.git +> cd awaitwhat +~/awaitwhat (dev|✔) > poetry shell # creates a venv and drops you in it + +(awaitwhat-x-py3.9) ~/awaitwhat (dev|✔) > poetry install # installs projects dependencies in a venv +(awaitwhat-x-py3.9) ~/awaitwhat (dev|✔) > poetry build # builds a C extension in this project + +(awaitwhat-x-py3.9) ~/awaitwhat (dev|✔) > env PYTHONPATH=. python examples/test_shield.py | tee graph.dot +(awaitwhat-x-py3.9) ~/awaitwhat (dev|✔) > dot -Tsvg graph.dot -o graph.svg +(awaitwhat-x-py3.9) ~/awaitwhat (dev|✔) > open graph.svg # or load it in a browser +``` + +### TL;DR + +Say you have this code: +```py + +async def job(): + await foo() + + +async def foo(): + await bar() + + +async def bar(): + await baz() + + +async def baz(): + await leaf() + + +async def leaf(): + await asyncio.sleep(1) # imagine you don't know this + + +async def work(): + await asyncio.gather(..., job()) +``` + +Now that code is stuck and and you want to know why. + +#### Python built-in +```py +Stack for <Task pending coro=<job() …> wait_for=<Future pending cb=[<TaskWakeupMethWrapper …>()]> cb=[…]> (most recent call last): + File "test/test_stack.py", line 34, in job + await foo() +``` + +#### This library +```py +Stack for <Task pending coro=<job() …> wait_for=<Future pending cb=[<TaskWakeupMethWrapper …>()]> cb=[…]> (most recent call last): + File "test/test_stack.py", line 34, in job + await foo() + File "test/test_stack.py", line 38, in foo + await bar() + File "test/test_stack.py", line 42, in bar + await baz() + File "test/test_stack.py", line 46, in baz + await leaf() + File "test/test_stack.py", line 50, in leaf + await asyncio.sleep(1) + File "/…/asyncio/tasks.py", line 568, in sleep + return await future + File "<Sentinel>", line 0, in <_asyncio.FutureIter object at 0x7fb6981690d8>: … +``` + +### Dependency Graph + +<img src="https://raw.github.com/dimaqq/awaitwhat/master/doc/test_future.svg?sanitize=true"> + +### References + +https://mail.python.org/archives/list/async-sig@python.org/thread/6E2LRVLKYSMGEAZ7OYOYR3PMZUUYSS3K/ + +> Hi group, +> +> I'm recently debugging a long-running asyncio program that appears to get stuck about once a week. +> +> The tools I've discovered so far are: +> * high level: `asyncio.all_tasks()` + `asyncio.Task.get_stack()` +> * low level: `loop._selector._fd_to_key` +> +> What's missing is the middle level, i.e. stack-like linkage of what is waiting for what. For a practical example, consider: +> +> ```py +> async def leaf(): await somesocket.recv() +> async def baz(): await leaf() +> async def bar(): await baz() +> async def foo(): await bar() +> async def job(): await foo() +> async def work(): await asyncio.gather(..., job()) +> async def main(): asyncio.run(work()) +> ``` +> +> The task stack will contain: +> * main and body of work with line number +> * job task with line number pointing to foo +> +> The file descriptor mapping, socket fd, `loop._recv()` and a `Future`. +> +> What's missing are connections `foo->bar->baz->leaf`. +> That is, I can't tell which task is waiting for what terminal `Future`. +> +> Is this problem solved in some way that I'm not aware of? +> Is there a library or external tool for this already? +> +> Perhaps, if I could get a list of all pending coroutines, I could figure out what's wrong. +> +> If no such API exists, I'm thinking of the following: +> +> ```py +> async def foo(): +> await bar() +> +> In [37]: dis.dis(foo) +> 1 0 LOAD_GLOBAL 0 (bar) +> 2 CALL_FUNCTION 0 +> 4 GET_AWAITABLE +> 6 LOAD_CONST 0 (None) +> 8 YIELD_FROM +> 10 POP_TOP +> 12 LOAD_CONST 0 (None) +> 14 RETURN_VALUE +> ``` +> +> Starting from a pending task, I'd get it's coroutine and: +> +> Get the coroutine frame, and if current instruction is `YIELD_FROM`, then the reference to the awaitable should be on the top of the stack. +> If that reference points to a pending coroutine, I'd add that to the "forward trace" and repeat. +> +> At some point I'd reach an awaitable that's not a pending coroutine, which may be: another `Task` (I already got those), a low-level `Future` (can be looked up in event loop), an `Event` (tough luck, shoulda logged all `Event`'s on creation) or a dozen other corner cases. +> +> What do y'all think of this approach? +> +> Thanks, +> D. + + +%prep +%autosetup -n awaitwhat-21.1 + +%build +%py3_build + +%install +%py3_install +install -d -m755 %{buildroot}/%{_pkgdocdir} +if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi +if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi +if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi +if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi +pushd %{buildroot} +if [ -d usr/lib ]; then + find usr/lib -type f -printf "\"/%h/%f\"\n" >> filelist.lst +fi +if [ -d usr/lib64 ]; then + find usr/lib64 -type f -printf "\"/%h/%f\"\n" >> filelist.lst +fi +if [ -d usr/bin ]; then + find usr/bin -type f -printf "\"/%h/%f\"\n" >> filelist.lst +fi +if [ -d usr/sbin ]; then + find usr/sbin -type f -printf "\"/%h/%f\"\n" >> filelist.lst +fi +touch doclist.lst +if [ -d usr/share/man ]; then + find usr/share/man -type f -printf "\"/%h/%f.gz\"\n" >> doclist.lst +fi +popd +mv %{buildroot}/filelist.lst . +mv %{buildroot}/doclist.lst . + +%files -n python3-awaitwhat -f filelist.lst +%dir %{python3_sitelib}/* + +%files help -f doclist.lst +%{_docdir}/* + +%changelog +* Tue Jun 20 2023 Python_Bot <Python_Bot@openeuler.org> - 21.1-1 +- Package Spec generated @@ -0,0 +1 @@ +97a21d53e67f573eb70fa29d0312eda5 awaitwhat-21.1.tar.gz |