summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--python-awaitwhat.spec597
-rw-r--r--sources1
3 files changed, 599 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e69de29..c3da580 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
diff --git a/sources b/sources
new file mode 100644
index 0000000..2560c1e
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+97a21d53e67f573eb70fa29d0312eda5 awaitwhat-21.1.tar.gz