adafruit / Adafruit_CircuitPython_HTTPServer

Simple HTTP Server for CircuitPython
MIT License
46 stars 30 forks source link

"ImportError: no module named 'hashlib'" on the WIZnet W5500-EVB-Pico #73

Closed Akkiesoft closed 11 months ago

Akkiesoft commented 11 months ago

Hi.

When I import the adafruit_httpserver on the WIZnet W5500-EVB-Pico, I got following error.

Adafruit CircuitPython 8.2.9 on 2023-12-06; W5500-EVB-Pico with rp2040
>>> from adafruit_httpserver import Server, Request, Response, MIMEType
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "adafruit_httpserver/__init__.py", line 56, in <module>
  File "adafruit_httpserver/response.py", line 20, in <module>
ImportError: no module named 'hashlib'

The error does not occur in the version I downloaded around May. I seem to import hashlib was added at the commit of 1e1ad58d1712c0ce25c02f629f7d95de4bbbc44c .

How can I solve this problem?

Akkiesoft commented 11 months ago

I replaced import hashlib line in the adafruit_httpserver/response.py with following code and it workaround works for me. However I just want to run web server, so I haven't tested about the WebSocket functions (sorry...).

try:
    import hashlib
except ImportError:
    import adafruit_hashlib as hashlib
anecdata commented 11 months ago

hashlib seems to be used for web sockets. If you're not using web sockets, I think you could comment it out.

edit: ah, I see you did it :-)

Raspberry Pi Pico W has hashlib, so it may just be a build config that could be changed to include hashlib in the builds for the WIZnet Pico boards (5100S, 5500, 6100).

edit: looks like a one-line addition needed in the circuitpython repo in each board's mpconfigboard.mk file: CIRCUITPY_HASHLIB = 1

edit 2: This library should probably adopt your change. The websocket example in this repo expects native wifi, not sure offhand if it works on Ethernet. If it does, the core change noted above could be made.

michalpokusa commented 11 months ago

@Akkiesoft Could you please check if the websocket example works WIZnet Pico boards you have?

@anecdata Do you think adding the try/except to import si the way to go, or should it be solved using by adding hashlib during build to boards that do not have it now?

FoamyGuy commented 11 months ago

I think it's worth adding the try/except even if we can enable hashlib on the currently remaining devices that don't have it. We have adafruit_hashlib as a python level lib so in the event that any boards are released that actually don't (or can't) support the native hashlib it'll be nice to have this as a fallback.

michalpokusa commented 11 months ago

I think it's worth adding the try/except even if we can enable hashlib on the currently remaining devices that don't have it. We have adafruit_hashlib as a python level lib so in the event that any boards are released that actually don't (or can't) support the native hashlib it'll be nice to have this as a fallback.

Makes sense. I will make a PR later in the day.

If I am correct, hashlib is only used for Websockets, so maybe it both hashlib and adafruit_hashlib are not present, we could print a warning that Websockets will not work and not require everyone to install it, it they are only using the standard HTTP communication.

So maybe something like this:

try:
    import hashlib
except ImportError:
    try:
        import adafruit_hashlib as hashlib
    except ImportError:
        print("Warning...")

What do you think?

anecdata commented 11 months ago

I agree it makes sense to import flexibly here. It's even conceivable that this library is used with a main board without hashlib with an ethernet feathering (or other compatible ethernet peripheral).

I started a PR for the core changes, but didn't have all the pieces to test it on an EVB-Pico. I can put it through and leave testing open.

There's about an order of magnitude improvement with the core module over the library:

EXPAND... ```py import time GUID = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11" ITERATIONS = 10_000 def hashme(): key = "dGhlIHNhbXBsZSBub25jZQ==" start = time.monotonic_ns() for _ in range(0, ITERATIONS): response_key = hashlib.new("sha1", key.encode()) response_key.update(GUID) return time.monotonic_ns() - start import hashlib duration = hashme() print(f"{ITERATIONS} iterations in {duration} ns - hashlib") import adafruit_hashlib as hashlib duration = hashme() print(f"{ITERATIONS} iterations in {duration} ns - adafruit_hashlib") ```
10000 iterations in 500976562 ns - hashlib
10000 iterations in 6370117187 ns - adafruit_hashlib

Addendum: circuitpython PR https://github.com/adafruit/circuitpython/pull/8719 but there's not enough space on some language builds and there are no other optional modules to remove to make space, I'll see if one of the core devs has an idea

Addendum 2: it wasn't a space issue, seems more like a build dependency issue from using mbedtls for hashlib, details in the PR

anecdata commented 11 months ago

There's a native solution at this core PR: https://github.com/adafruit/circuitpython/pull/8749 If someone is set up to test, please comment there.