aio-libs / aio-libs/aiohttp

Support Pyodide (Jupyterlite)

未关闭
#7,253 12 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
enhancement
主要语言
Python
星标
16.5k
派生
2.4k
平均合并
17 小时 22 分钟
30 天内合并 PR
212

描述

### Is your feature request related to a problem?

I'm a contributor to [Panel](https://panel.holoviz.org/) which can run on many platforms including [Panelite](https://panelite.holoviz.org/lab/index.html) (~Jupyterlite). We would like to be able to use Jupyterlite to provide an easy to use platform to showcase our framework and help our users learn how to use it.

I believe this is a general trend in Python that frameworks and users start moving to the browser powered by Pyodide, PyScript and Jupyterlite for education and for lighter data analytics.

One of Panels reference notebooks shows how to use Panel with async and `aiohttp`. The problem is that I cannot import `aiohttp` with piplite.

You can **reproduce** as described below

- Open Jupyterlite https://jupyterlite.readthedocs.io/en/latest/_static/lab/index.html
- Open a Pyodide notebook
- Run the code below

```python
import piplite
await piplite.install(['aiohttp'])
```

![image](https://user-images.githubusercontent.com/42288570/232121140-d0a0d803-7a29-4174-8dc8-1ef7b7760bcb.png)

```python
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[1], line 2
1 import piplite
----> 2 await piplite.install(['aiohttp'])

File /lib/python3.11/site-packages/piplite/piplite.py:103, in _install(requirements, keep_going, deps, credentials, pre)
101 """Invoke micropip.install with a patch to get data from local indexes"""
102 with patch("micropip._micropip._get_pypi_json", _get_pypi_json):
--> 103 return await _micropip.install(
104 requirements=requirements,
105 keep_going=keep_going,
106 deps=deps,
107 credentials=credentials,
108 pre=pre,
109 )

File /lib/python3.11/site-packages/micropip/_micropip.py:576, in install(requirements, keep_going, deps, credentials, pre)
566 wheel_base = Path(getsitepackages()[0])
568 transaction = Transaction(
569 ctx=ctx,
570 ctx_extras=[],
(...)
574 fetch_kwargs=fetch_kwargs,
575 )
--> 576 await transaction.gather_requirements(requirements)
578 if transaction.failed:
579 failed_requirements = ", ".join([f"'{req}'" for req in transaction.failed])

File /lib/python3.11/site-packages/micropip/_micropip.py:342, in Transaction.gather_requirements(self, requirements)
339 for requirement in requirements:
340 requirement_promises.append(self.add_requirement(requirement))
--> 342 await gather(*requirement_promises)

File /lib/python3.11/site-packages/micropip/_micropip.py:349, in Transaction.add_requirement(self, req)
346 return await self.add_requirement_inner(req)
348 if not urlparse(req).path.endswith(".whl"):
--> 349 return await self.add_requirement_inner(Requirement(req))
351 # custom download location
352 wheel = WheelInfo.from_url(req)

File /lib/python3.11/site-packages/micropip/_micropip.py:457, in Transaction.add_requirement_inner(self, req)
452 if self.check_version_satisfied(req):
453 # Maybe while we were downloading pypi_json some other branch
454 # installed the wheel?
455 return
--> 457 await self.add_wheel(wheel, req.extras)

File /lib/python3.11/site-packages/micropip/_micropip.py:472, in Transaction.add_wheel(self, wheel, extras)
470 await wheel.download(self.fetch_kwargs)
471 if self.deps:
--> 472 await self.gather_requirements(wheel.requires(extras))
474 self.wheels.append(wheel)

File /lib/python3.11/site-packages/micropip/_micropip.py:342, in Transaction.gather_requirements(self, requirements)
339 for requirement in requirements:
340 requirement_promises.append(self.add_requirement(requirement))
--> 342 await gather(*requirement_promises)

File /lib/python3.11/site-packages/micropip/_micropip.py:346, in Transaction.add_requirement(self, req)
344 async def add_requirement(self, req: str | Requirement) -> None:
345 if isinstance(req, Requirement):
--> 346 return await self.add_requirement_inner(req)
348 if not urlparse(req).path.endswith(".whl"):
349 return await self.add_requirement_inner(Requirement(req))

File /lib/python3.11/site-packages/micropip/_micropip.py:444, in Transaction.add_requirement_inner(self, req)
441 metadata = await _get_pypi_json(req.name, self.fetch_kwargs)
443 try:
--> 444 wheel = find_wheel(metadata, req)
445 except ValueError:
446 self.failed.append(req)

File /lib/python3.11/site-packages/micropip/_micropip.py:312, in find_wheel(metadata, req)
309 if best_wheel is not None:
310 return wheel
--> 312 raise ValueError(
313 f"Can't find a pure Python 3 wheel for '{req}'.\n"
314 f"See: {FAQ_URLS['cant_find_wheel']}\n"
315 "You can use `micropip.install(..., keep_going=True)`"
316 "to get a list of all packages with missing wheels."
317 )

ValueError: Can't find a pure Python 3 wheel for 'multidict<5.0,>=4.5'.
See: https://pyodide.org/en/stable/usage/faq.html#micropip-can-t-find-a-pure-python-wheel
You can use `micropip.install(..., keep_going=True)`to get a list of all packages with missing wheels.
```

### Describe the solution you'd like

That I can import **and use** `aiohttp` in Pyodide and Jupyterlite.

### Describe alternatives you've considered

Removing the `aiohttp` notebook from the Panelite example notebooks.

### Related component

Client

### Additional context

When the import problem has been solved there is probably a lot more to solve to get aiohttp working.

The code we are using is

```python
async def get_img(index):
async with aiohttp.ClientSession() as session:
async with session.get(f"https://picsum.photos/800/300?image={index}") as resp:
return await resp.read()
```

I can see that `multidict` can be imported by it self. Its the version pinned that is the import problem.

### Code of Conduct

- [X] I agree to follow the aio-libs Code of Conduct

贡献指南

打开贡献指南

评估

这个 Issue 还没有评估数据。

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。