holoviz / datashader

Quickly and accurately render even the largest data.
http://datashader.org
BSD 3-Clause "New" or "Revised" License
3.26k stars 363 forks source link

Make datashader work in Jupyterlite/ Panelite #1200

Open MarcSkovMadsen opened 1 year ago

MarcSkovMadsen commented 1 year ago

When running the notebook gallery/simple/clifford_interact.ipynb in Panelite v 0.14.4 I can see its not working because Datashader cannot be imported due to a dependency on datashape.

Please make datashader work in Panelite :-)

image

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

File /lib/python3.10/asyncio/futures.py:284, in Future.__await__(self)
    282 if not self.done():
    283     self._asyncio_future_blocking = True
--> 284     yield self  # This tells Task to wait for completion.
    285 if not self.done():
    286     raise RuntimeError("await wasn't used with future")

File /lib/python3.10/asyncio/tasks.py:304, in Task.__wakeup(self, future)
    302 def __wakeup(self, future):
    303     try:
--> 304         future.result()
    305     except BaseException as exc:
    306         # This may also be a cancellation.
    307         self.__step(exc)

File /lib/python3.10/asyncio/futures.py:201, in Future.result(self)
    199 self.__log_traceback = False
    200 if self._exception is not None:
--> 201     raise self._exception
    202 return self._result

File /lib/python3.10/asyncio/tasks.py:234, in Task.__step(***failed resolving arguments***)
    232         result = coro.send(None)
    233     else:
--> 234         result = coro.throw(exc)
    235 except StopIteration as exc:
    236     if self._must_cancel:
    237         # Task is cancelled right before coro stops.

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

File /lib/python3.10/site-packages/micropip/_micropip.py:573, in install(requirements, keep_going, deps, credentials, pre)
    563 wheel_base = Path(getsitepackages()[0])
    565 transaction = Transaction(
    566     ctx=ctx,
    567     ctx_extras=[],
   (...)
    571     fetch_kwargs=fetch_kwargs,
    572 )
--> 573 await transaction.gather_requirements(requirements)
    575 if transaction.failed:
    576     failed_requirements = ", ".join([f"'{req}'" for req in transaction.failed])

File /lib/python3.10/site-packages/micropip/_micropip.py:333, in Transaction.gather_requirements(self, requirements)
    330 for requirement in requirements:
    331     requirement_promises.append(self.add_requirement(requirement))
--> 333 await gather(*requirement_promises)

File /lib/python3.10/asyncio/futures.py:284, in Future.__await__(self)
    282 if not self.done():
    283     self._asyncio_future_blocking = True
--> 284     yield self  # This tells Task to wait for completion.
    285 if not self.done():
    286     raise RuntimeError("await wasn't used with future")

File /lib/python3.10/asyncio/tasks.py:304, in Task.__wakeup(self, future)
    302 def __wakeup(self, future):
    303     try:
--> 304         future.result()
    305     except BaseException as exc:
    306         # This may also be a cancellation.
    307         self.__step(exc)

File /lib/python3.10/asyncio/futures.py:201, in Future.result(self)
    199 self.__log_traceback = False
    200 if self._exception is not None:
--> 201     raise self._exception
    202 return self._result

File /lib/python3.10/asyncio/tasks.py:234, in Task.__step(***failed resolving arguments***)
    232         result = coro.send(None)
    233     else:
--> 234         result = coro.throw(exc)
    235 except StopIteration as exc:
    236     if self._must_cancel:
    237         # Task is cancelled right before coro stops.

File /lib/python3.10/site-packages/micropip/_micropip.py:340, in Transaction.add_requirement(self, req)
    337     return await self.add_requirement_inner(req)
    339 if not urlparse(req).path.endswith(".whl"):
--> 340     return await self.add_requirement_inner(Requirement(req))
    342 # custom download location
    343 wheel = WheelInfo.from_url(req)

File /lib/python3.10/site-packages/micropip/_micropip.py:448, in Transaction.add_requirement_inner(self, req)
    443 if self.check_version_satisfied(req):
    444     # Maybe while we were downloading pypi_json some other branch
    445     # installed the wheel?
    446     return
--> 448 await self.add_wheel(wheel, req.extras)

File /lib/python3.10/site-packages/micropip/_micropip.py:463, in Transaction.add_wheel(self, wheel, extras)
    461 await wheel.download(self.fetch_kwargs)
    462 if self.deps:
--> 463     await self.gather_requirements(wheel.requires(extras))
    465 self.wheels.append(wheel)

File /lib/python3.10/site-packages/micropip/_micropip.py:333, in Transaction.gather_requirements(self, requirements)
    330 for requirement in requirements:
    331     requirement_promises.append(self.add_requirement(requirement))
--> 333 await gather(*requirement_promises)

File /lib/python3.10/asyncio/futures.py:284, in Future.__await__(self)
    282 if not self.done():
    283     self._asyncio_future_blocking = True
--> 284     yield self  # This tells Task to wait for completion.
    285 if not self.done():
    286     raise RuntimeError("await wasn't used with future")

File /lib/python3.10/asyncio/tasks.py:304, in Task.__wakeup(self, future)
    302 def __wakeup(self, future):
    303     try:
--> 304         future.result()
    305     except BaseException as exc:
    306         # This may also be a cancellation.
    307         self.__step(exc)

File /lib/python3.10/asyncio/futures.py:201, in Future.result(self)
    199 self.__log_traceback = False
    200 if self._exception is not None:
--> 201     raise self._exception
    202 return self._result

File /lib/python3.10/asyncio/tasks.py:232, in Task.__step(***failed resolving arguments***)
    228 try:
    229     if exc is None:
    230         # We use the `send` method directly, because coroutines
    231         # don't have `__iter__` and `__next__` methods.
--> 232         result = coro.send(None)
    233     else:
    234         result = coro.throw(exc)

File /lib/python3.10/site-packages/micropip/_micropip.py:337, in Transaction.add_requirement(self, req)
    335 async def add_requirement(self, req: str | Requirement) -> None:
    336     if isinstance(req, Requirement):
--> 337         return await self.add_requirement_inner(req)
    339     if not urlparse(req).path.endswith(".whl"):
    340         return await self.add_requirement_inner(Requirement(req))

File /lib/python3.10/site-packages/micropip/_micropip.py:435, in Transaction.add_requirement_inner(self, req)
    432 metadata = await _get_pypi_json(req.name, self.fetch_kwargs)
    434 try:
--> 435     wheel = find_wheel(metadata, req)
    436 except ValueError:
    437     self.failed.append(req)

File /lib/python3.10/site-packages/micropip/_micropip.py:303, in find_wheel(metadata, req)
    300     if best_wheel is not None:
    301         return wheel
--> 303 raise ValueError(
    304     f"Can't find a pure Python 3 wheel for '{req}'.\n"
    305     f"See: {FAQ_URLS['cant_find_wheel']}\n"
    306     "You can use `micropip.install(..., keep_going=True)`"
    307     "to get a list of all packages with missing wheels."
    308 )

ValueError: Can't find a pure Python 3 wheel for 'datashape'.
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.
MarcSkovMadsen commented 1 year ago

I can see that numba will also be a problem.

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[3], line 2
      1 import piplite
----> 2 await piplite.install(['panel', 'datashader', 'colorcet'], keep_going=True)

File /lib/python3.10/asyncio/futures.py:284, in Future.__await__(self)
    282 if not self.done():
    283     self._asyncio_future_blocking = True
--> 284     yield self  # This tells Task to wait for completion.
    285 if not self.done():
    286     raise RuntimeError("await wasn't used with future")

File /lib/python3.10/asyncio/tasks.py:304, in Task.__wakeup(self, future)
    302 def __wakeup(self, future):
    303     try:
--> 304         future.result()
    305     except BaseException as exc:
    306         # This may also be a cancellation.
    307         self.__step(exc)

File /lib/python3.10/asyncio/futures.py:201, in Future.result(self)
    199 self.__log_traceback = False
    200 if self._exception is not None:
--> 201     raise self._exception
    202 return self._result

File /lib/python3.10/asyncio/tasks.py:232, in Task.__step(***failed resolving arguments***)
    228 try:
    229     if exc is None:
    230         # We use the `send` method directly, because coroutines
    231         # don't have `__iter__` and `__next__` methods.
--> 232         result = coro.send(None)
    233     else:
    234         result = coro.throw(exc)

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

File /lib/python3.10/site-packages/micropip/_micropip.py:577, in install(requirements, keep_going, deps, credentials, pre)
    575 if transaction.failed:
    576     failed_requirements = ", ".join([f"'{req}'" for req in transaction.failed])
--> 577     raise ValueError(
    578         f"Can't find a pure Python 3 wheel for: {failed_requirements}\n"
    579         f"See: {FAQ_URLS['cant_find_wheel']}\n"
    580     )
    582 wheel_promises = []
    583 # Install built-in packages

ValueError: Can't find a pure Python 3 wheel for: 'numba>=0.51', 'datashape'
See: https://pyodide.org/en/stable/usage/faq.html#micropip-can-t-find-a-pure-python-wheel
jbednar commented 1 year ago

Right; datashape is the easy case. llvmlite is the real issue here: https://github.com/pyodide/pyodide/issues/621