Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"no module named 'usocket'" on Raspberry Pico W #35

Open
noinskit opened this issue Nov 20, 2022 · 30 comments
Open

"no module named 'usocket'" on Raspberry Pico W #35

noinskit opened this issue Nov 20, 2022 · 30 comments

Comments

@noinskit
Copy link

Hi,

I'm trying to use this package in order to run an HTTP Server (Microdot) concurrently with other tasks on Raspberry Pico W.
It's failing for me with:

Traceback (most recent call last):
  File "<stdin>", line 42, in <module>
  File "microdot_asyncio.py", line 320, in run
  File "asyncio/core.py", line 297, in run
  File "asyncio/core.py", line 261, in run_until_complete
  File "asyncio/core.py", line 246, in run_until_complete
  File "microdot_asyncio.py", line 278, in start_server
  File "asyncio/stream.py", line 226, in start_server
ImportError: no module named 'usocket'

Am I doing something totally unsupported yet, like maybe only some subset of CircuitPython devices have usocket?

I know that sockets generally work if I use socketpool for screating sockets, so maybe I'm really looking after #4 ?

I'd appreciate any pointers!

@dhalbert
Copy link
Contributor

CircuitPython doesn't have usocket, but you can use socketpool. It looks like the microdot server is written for MicroPython, not CircuitPython, but you could modify it.

@noinskit
Copy link
Author

I believe that usocket is called from within Adafruit_CircuitPython_asyncio directly.

From what I can see microdot server is only using asyncio and its start_server method, which doesn't sound like depending on MicroPython.

This is my attempt at minimal repro without using Microdot:

import asyncio

async def main():
    async def serve(reader, writer):
        pass
    
    await asyncio.start_server(serve, "0.0.0.0", 80)

asyncio.run(main())

Note that I'm not really initializing wifi in my example, but since I would not be able to pass the initialized socket pool to asyncio anyway, it wouldn't help.

The result:

Traceback (most recent call last):
  File "<stdin>", line 9, in <module>
  File "asyncio/core.py", line 297, in run
  File "asyncio/core.py", line 261, in run_until_complete
  File "asyncio/core.py", line 246, in run_until_complete
  File "<stdin>", line 7, in main
  File "asyncio/stream.py", line 226, in start_server
ImportError: no module named 'usocket'

I'll admit that in the meantime I also tried to make a socketpool.SocketPool object pretend to be the usocket module for the sake of asyncio, but it's currently failing for me onsocket objects from there not having a setsockopt method.

@dhalbert
Copy link
Contributor

You're right, we should change this line:

import usocket as socket

@noinskit
Copy link
Author

Also true, but in my case I think it's about the server part:

import usocket as socket

@chrismurf
Copy link

This bit me tonight with the AdaFruit ESP32 Feather V2 as well, so for anybody new and googling - it's not specific to the Raspberry Pico W at all.

I believe this will also affect open_connection calls.

@jordonsc
Copy link

jordonsc commented Sep 25, 2023

The same applies to the uerrno import on the line above.

@byzantic
Copy link

byzantic commented Jan 30, 2024

I'm having the same issue here, except that I am trying to use the Wiznet W5500-EVB-Pico.

Now, interestingly, this does have a socket implementation already (adafruit_wiznet5k.adafruit_wiznet5k_socket) .. but how would I set up asyncio to use that instead?

@mcarlson
Copy link

This bit me also, which is too bad because the official circuitpython story for not supporing interrupts/multithreading (which I get!) is to use asyncio for applications where you need to do more than one thing at a time. For me, that means going back to micropython as I'm building 'headless' apps that rely on microdot/being able to run an async server.

Not super stoked because the story for not having interrupts in circuitpython is is 'use asyncio' per https://learn.adafruit.com/cooperative-multitasking-in-circuitpython-with-asyncio/overview

But, the circuitpython asyncio doesn't work with microdot because they don't implement start_server. So I'm blocked... Please fix this!

@sjev
Copy link

sjev commented May 8, 2024

.... this issue is still relevant and affects probably all ports. I was making a switch from Micropython to Circuitpython, but tripped on:

asyncio.create_task(asyncio.start_server(serve_client, "0.0.0.0", 80))

crashes with

Traceback (most recent call last):
  File "asyncio/core.py", line 261, in run_until_complete
  File "asyncio/stream.py", line 225, in start_server
ImportError: no module named 'usocket'

Major bummer 😞 , given that according to docs start_server should be supported. Shouldn't this be in test coverage?

@mcarlson
Copy link

mcarlson commented May 8, 2024 via email

@mattytrentini
Copy link

mattytrentini commented May 9, 2024

I believe it really should be fixed. For me, I wasn’t able to continue with micropython because of it.

Just to clarify @mcarlson, I think you mean CircuitPython here? I've been using microdot on MicroPython for years with no issue whatsoever...

@dhalbert
Copy link
Contributor

dhalbert commented May 9, 2024

Have any of you tried the source version and just fixed the import names? I started a PR to do that. There are only a few lines to change. It might still be the case that something doesn't work.

@mcarlson
Copy link

mcarlson commented May 9, 2024 via email

@sjev
Copy link

sjev commented May 9, 2024

@dhalbert

Have any of you tried the source version and just fixed the import names? I started a PR to do that. There are only a few lines to change. It might still be the case that something doesn't work.

You mean rebuilding CP? Could you please link to your PR?

@mcarlson
Copy link

mcarlson commented May 9, 2024 via email

@dhalbert
Copy link
Contributor

dhalbert commented May 9, 2024

You mean rebuilding CP? Could you please link to your PR?

I just mean changing the names in this library. Just get the Python (not .mpy) version of this library and edit it so the import names match. e.g. change import usocket as socket to import socketpool as socket, etc.

@sjev
Copy link

sjev commented May 9, 2024

@dhalbert - ... couple of hours further it does not seem that simple.

I replaced import usocket as socket in start_server by this:

import wifi
import socketpool

socket = socketpool.SocketPool(wifi.radio)

It helpled a bit - the server could be started. only to crash later with

Traceback (most recent call last):
  File "/lib/asyncio/core.py", line 261, in run_until_complete
  File "webserver.py", line 16, in serve_client
  File "/lib/asyncio/stream.py", line 100, in readline
AttributeError: 'Socket' object has no attribute 'readline'

BTW, there is more smelly stuff in stream.py , like

    from uerrno import EINPROGRESS  # there is no `uerrno` in circuitpython
    import socketpool as socket  # these are not equivalent. 

It does not not feel right to keep hacking further without proper test cases in place. That would not be trivial to do, because we'd need something like descent mocks first on a unix port.

@mcarlson
Copy link

mcarlson commented May 10, 2024 via email

@tannewt tannewt assigned tannewt and unassigned tannewt May 13, 2024
@sveinungkb
Copy link

Any path forward here?

@dhalbert
Copy link
Contributor

I think there are two things going on here:

  1. The u prefix needs to be removed in all places where it's used.
  2. microdot uses .readline() on a Socket, which is not standard in CPython and is not implemented in CircuitPython.

If your goal is to just have an HTTP server, then there is https://github.com/adafruit/Adafruit_CircuitPython_HTTPServer, but it is not async.

@dhalbert
Copy link
Contributor

We are just starting to merge MicroPython v1.21 through v1.23 into CircuitPython. A side effect of this will be updating this asyncio library from the version that is in https://github.com/micropython/micropython/tree/master/extmod/asyncio.

I talked with @tannewt briefly about this in discord. We need start_server() if we don't have it already.
See miguelgrinberg/microdot#214 as well.

@mcarlson
Copy link

mcarlson commented Jul 12, 2024 via email

@dhalbert
Copy link
Contributor

I need an embedded web server!

Have you looked at https://github.com/adafruit/Adafruit_CircuitPython_HTTPServer, or do you need the async support?

@mcarlson
Copy link

mcarlson commented Jul 12, 2024 via email

@sveinungkb
Copy link

I'm doing several tasks, for sensors etc, but anything more than a second or so between each check if the socket the web experience seems very bad.

There's async support in the socket itself in MP, but the same doesn't seem present in CP. See the socket callback registered here.

https://github.com/orgs/micropython/discussions/12219#discussioncomment-6713393

The code to register, check and invoke these subscriptions are not present in CP's socket.c as far as I can tell.

I'm getting an exception when trying to run the same code as this only expects integer or buffer as 3rd arguments.
Socket.c:346
If we could register a callback, we could queue the task to process the request was my angle.

@mattytrentini

This comment was marked as off-topic.

@mcarlson

This comment was marked as off-topic.

@mcarlson

This comment was marked as off-topic.

@tannewt

This comment was marked as off-topic.

@labilello12
Copy link

Any progress on this? Have others found a work around?

I attempted to create an async driven TCP server using the lower level aspects of pythons async IO. I was unsuccessful. As others have mentioned, not all CPython async functionality has been ported to CircuitPython/MicroPython.

I have custom python infrastructure around sensor gathering from various Weather Stations and indoor sensor "sites"

As a workaround, I'm going to code up a TCP Server with a timeout on socket.accept() when the timeout occurs I'll go poll the sensors (temp, humidity, etc) and then loop back to accept. It'll work just fine, but the async solution would have been nice and succinct.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests