arcavios / scooze

A flexible data layer for applications working with Magic: the Gathering cards, decks, and tournaments.
Other
12 stars 1 forks source link

Scooze fails in Jupyter notebooks with `Runner.run() cannot be called from a running event loop` #195

Closed smerrill closed 12 months ago

smerrill commented 1 year ago

Describe the bug If you try to use Scooze in a Jupyter notebook, it fails with RuntimeError: Runner.run() cannot be called from a running event loop

To Reproduce Steps to reproduce the behavior:

  1. Install a local venv with current dev branch (commit 239fef38dce61c5bbd6d882fb78cd8cf3a90672d) so that load-cards works
  2. pip install jupyter && jupyter notebook
  3. Try running the sample .py file in a cell
  4. Get this error:
    
    ---------------------------------------------------------------------------
    RuntimeError                              Traceback (most recent call last)
    Cell In[2], line 1
    ----> 1 with ScoozeApi() as s:
      2   # get 10 arbitrary green cards
      3   green_cards = s.get_cards_by("colors", [Color.GREEN], paginated=True, page_size=10)
      4   # get _all_ green cards

File ~/Projects/scooze/src/scooze/api/init.py:46, in ScoozeApi.enter(self) 44 self.safe_context = True 45 self.runner = asyncio.Runner() ---> 46 self.runner.run(mongo.mongo_connect()) 48 return self

File /opt/homebrew/Cellar/python@3.11/3.11.4_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/runners.py:93, in Runner.run(self, coro, context) 89 raise ValueError("a coroutine was expected, got {!r}".format(coro)) 91 if events._get_running_loop() is not None: 92 # fail fast with short traceback ---> 93 raise RuntimeError( 94 "Runner.run() cannot be called from a running event loop") 96 self._lazy_init() 98 if context is None:

RuntimeError: Runner.run() cannot be called from a running event loop


**Expected behavior**
Scooze works and gives me card data!

**Screenshots**
<img width="1229" alt="image" src="https://github.com/arcavios/scooze/assets/156815/151b8b4b-8670-48d1-a999-c6a4794776da">

**Additional context**
It appears that we will have to grab the existing event loop rather than making a new one in order to work inside of Jupyter notebooks.
https://saturncloud.io/blog/how-to-fix-asynciorun-cannot-be-called-from-a-running-event-loop-error-in-jupyter-notebook/

`python` version string:

Python 3.11.4 (main, Jul 25 2023, 17:36:13) [Clang 14.0.3 (clang-1403.0.22.14.1)] on darwin


`pip freeze` output:
(I added Jupyter and a ton of data science libraries to my venv)

annotated-types==0.5.0 anyio==3.7.1 appnope==0.1.3 argon2-cffi==23.1.0 argon2-cffi-bindings==21.2.0 arrow==1.3.0 asttokens==2.4.0 async-lru==2.0.4 attrs==23.1.0 Babel==2.13.0 backcall==0.2.0 beautifulsoup4==4.12.2 black==23.9.1 bleach==6.1.0 build==0.10.0 CacheControl==0.13.1 certifi==2023.7.22 cffi==1.16.0 charset-normalizer==3.3.0 cleo==2.0.1 click==8.1.7 comm==0.1.4 contourpy==1.1.1 crashtest==0.4.1 cycler==0.12.1 debugpy==1.8.0 decorator==5.1.1 defusedxml==0.7.1 distlib==0.3.7 dnspython==2.4.2 dulwich==0.21.6 executing==2.0.0 fastapi==0.103.2 fastjsonschema==2.18.1 filelock==3.12.4 fonttools==4.43.1 fqdn==1.5.1 frozendict==2.3.8 h11==0.14.0 httpcore==0.17.3 httptools==0.6.0 httpx==0.24.1 idna==3.4 ijson==3.2.3 importlib-metadata==6.8.0 iniconfig==2.0.0 installer==0.7.0 ipykernel==6.25.2 ipython==8.16.1 ipython-genutils==0.2.0 ipywidgets==8.1.1 isoduration==20.11.0 isort==5.12.0 jaraco.classes==3.3.0 jedi==0.19.1 Jinja2==3.1.2 joblib==1.3.2 json5==0.9.14 jsonpointer==2.4 jsonschema==4.19.1 jsonschema-specifications==2023.7.1 jupyter==1.0.0 jupyter-console==6.6.3 jupyter-events==0.7.0 jupyter-lsp==2.2.0 jupyter_client==8.3.1 jupyter_core==5.3.2 jupyter_server==2.7.3 jupyter_server_terminals==0.4.4 jupyterlab==4.0.6 jupyterlab-pygments==0.2.2 jupyterlab-widgets==3.0.9 jupyterlab_server==2.25.0 jupyterlab_vim==4.0.3 keyring==24.2.0 kiwisolver==1.4.5 MarkupSafe==2.1.3 matplotlib==3.8.0 matplotlib-inline==0.1.6 mistune==3.0.2 mongomock==4.1.2 more-itertools==10.1.0 motor==3.3.1 msgpack==1.0.7 mypy-extensions==1.0.0 nbclient==0.8.0 nbconvert==7.9.2 nbformat==5.9.2 nest-asyncio==1.5.8 notebook==7.0.4 notebook_shim==0.2.3 numpy==1.26.0 overrides==7.4.0 packaging==23.2 pandas==2.1.1 pandocfilters==1.5.0 parso==0.8.3 pathspec==0.11.2 pexpect==4.8.0 pickleshare==0.7.5 Pillow==10.0.1 pkginfo==1.9.6 platformdirs==3.11.0 pluggy==1.3.0 poetry==1.6.1 poetry-core==1.7.0 poetry-plugin-export==1.5.0 prometheus-client==0.17.1 prompt-toolkit==3.0.39 psutil==5.9.5 ptyprocess==0.7.0 pure-eval==0.2.2 pycparser==2.21 pydantic==2.4.2 pydantic_core==2.10.1 Pygments==2.16.1 pymongo==4.5.0 pyparsing==3.1.1 pyproject_hooks==1.0.0 pyrsistent==0.19.3 pytest==7.4.2 python-dateutil==2.8.2 python-dotenv==1.0.0 python-json-logger==2.0.7 pytz==2023.3.post1 PyYAML==6.0.1 pyzmq==25.1.1 qtconsole==5.4.4 QtPy==2.4.0 rapidfuzz==2.15.2 referencing==0.30.2 requests==2.31.0 requests-toolbelt==1.0.0 rfc3339-validator==0.1.4 rfc3986-validator==0.1.1 rpds-py==0.10.4 scikit-learn==1.3.1 scipy==1.11.3 -e git+ssh://git@github.com/arcavios/scooze.git@239fef38dce61c5bbd6d882fb78cd8cf3a90672d#egg=scooze seaborn==0.13.0 Send2Trash==1.8.2 sentinels==1.0.0 shellingham==1.5.3 six==1.16.0 sniffio==1.3.0 soupsieve==2.5 stack-data==0.6.3 starlette==0.27.0 terminado==0.17.1 threadpoolctl==3.2.0 tinycss2==1.2.1 tomlkit==0.12.1 tornado==6.3.3 traitlets==5.11.2 trove-classifiers==2023.9.19 types-python-dateutil==2.8.19.14 typing_extensions==4.8.0 tzdata==2023.3 uri-template==1.3.0 urllib3==2.0.6 uvicorn==0.23.2 uvloop==0.17.0 virtualenv==20.24.5 watchfiles==0.20.0 wcwidth==0.2.8 webcolors==1.13 webencodings==0.5.1 websocket-client==1.6.3 websockets==11.0.3 widgetsnbextension==4.0.9 xattr==0.10.1 zipp==3.17.0

iambroadband commented 1 year ago

I'll take a look at this tonight.

From the posted article:

One way to avoid the asyncio.run() error is to use asyncio.create_task() instead. asyncio.create_task() creates a new task in the current event loop, rather than creating a new event loop.

I'll explore this approach first. I did see you forked and created an AsyncScoozeApi which may be worth having on it's own merits anyway. Thanks for finding this one!

iambroadband commented 12 months ago

I think the solution we've settled on is to solve this with an async version of the ScoozeApi. This is implemented as part of #199

iambroadband commented 12 months ago

This should be finished with #199