Issues with extra python packages (evdev)

I’m building a simple ticket scanner iot device with a datalogic barcode scanner.

I wanted to use evdev to listen keyboard interrupts and I can sucessfuly install the package via SSH but when running the code (from App Lab APP) I get the following error:

Using CPython 3.13.9 interpreter at: /usr/local/bin/python
Creating virtual environment at: .cache/.venv
Activating python virtual environment
Traceback (most recent call last):
  File "/app/python/main.py", line 1, in <module>
    from evdev import InputDevice, categorize, ecodes
ModuleNotFoundError: No module named 'evdev'
Activating python virtual environment
Traceback (most recent call last):
  File "/app/python/main.py", line 1, in <module>
    from evdev import InputDevice, categorize, ecodes
ModuleNotFoundError: No module named 'evdev'
exited with code 1

The source code is simple

from evdev import InputDevice, categorize, ecodes

def main():
  dev = InputDevice('/dev/input/event2')
  
  scancodes = {
      2: "1", 3: "2", 4: "3", 5: "4", 6: "5",
      7: "6", 8: "7", 9: "8", 10: "9", 11: "0"
  }

  buffer = ""
  
  for event in dev.read_loop():
      if event.type == ecodes.EV_KEY:
          key = categorize(event)
          if key.keystate == key.key_down:
              code = key.scancode
              if code in scancodes:
                  buffer += scancodes[code]
              elif code == ecodes.KEY_ENTER:
                  print("Letto:", buffer)
                  buffer = ""



if __name__ == "__main__":
    main()

and running another script from ssh I’m able to find the device (so evdev works)

arduino@ccc-uno:~$ python3 - << 'EOF'
from evdev import list_devices, InputDevice
for path in list_devices():
    d = InputDevice(path)
    print(path, d.name)
EOF

/dev/input/event3 Arduino-Imola-HPH-LOUT Headset Jack
/dev/input/event2 Datalogic ADC, Inc. Handheld Barcode Scanner
/dev/input/event1 pm8941_pwrkey
/dev/input/event0 gpio-keys

The issue isn’t with evdev or your code
App Lab runs your Python script inside its own virtual environment so it can’t see the global packages you installed over SSH That’s why evdev works from SSH but not from the App Lab app

To fix it, you need to install evdev inside the App Lab virtual environment, not system-wide.

Thanks for your response.
How can I install it inside the venv? from App Lab there's no clear way of doing it.

I think the only way is to install it from SSH. App Lab doesn’t expose the venv directly, but it creates it inside your project folder. If I’m not mistaken, you can activate it manually like this:

cd /home/arduino/<your_app_name>
source .cache/.venv/bin/activate
pip install evdev

After installing it inside that environment, App Lab should be able to import evdev.
I’m not 100% sure, but this is the approach that usually works.

After installing pip I was able to run pip install evdev in my app directory but this is the output:

error: externally-managed-environment

× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
    python3-xyz, where xyz is the package you are trying to
    install.

    If you wish to install a non-Debian-packaged Python package,
    create a virtual environment using python3 -m venv path/to/venv.
    Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
    sure you have python3-full installed.

    If you wish to install a non-Debian packaged Python application,
    it may be easiest to use pipx install xyz, which will manage a
    virtual environment for you. Make sure you have pipx installed.

    See /usr/share/doc/python3.13/README.venv for more information.

note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages.
hint: See PEP 668 for the detailed specification.

Also running pip list seems installed correctly evdev 1.9.1

I did some more research on this, and I think I finally understand what’s going on.
The “externally-managed-environment” error almost always means pip is still using the system Python instead of the virtual environment that App Lab creates. That would also explain why evdev shows up in pip list, but App Lab still can’t import it.

So the important part is to make sure you’re actually inside the App Lab venv before installing anything.
Here’s the exact sequence that should work:

Go to your App Lab project directory

cd /home/arduino/<your_app_name>
  1. Activate the venv created by App Lab
source .cache/.venv/bin/activate

3.Make sure the activation really worked
Run:

which python
which pip

You should see something like:

/home/arduino/<your_app_name>/.cache/.venv/bin/python
/home/arduino/<your_app_name>/.cache/.venv/bin/pip

If it still shows /usr/bin/python3 or /usr/bin/pip3,
then the venv didn’t activate correctly — and pip will refuse to install anything.


4.Once pip is pointing to the venv, install evdev

pip install evdev

Now it should install cleanly inside the venv, not system-wide.

5.(Optional) Verify that evdev is installed inside the venv

pip list

You should see:

evdev   1.9.1

Inside the venv environment — which means App Lab can now import it.


I’m not 100% certain because I can’t see your filesystem,
but based on everything I found, this seems to be the correct way to install packages that App Lab will actually see.

If you want, you can paste the output of which python after activation, and I can confirm immediately whether you're in the right environment.

I think you should go get help from AI because I might have missed something or if you have any other questions, I'd be happy to help you.

I was reading this earlier:

So i tried creating a requirements.txt and adding evdev inside, but when building the app I get this error now:

$ arduino-app-cli app logs user:usb-scanner

[main]
[main]               By 2026-Feb-18, you need to update your project and remove
[main]       deprecated calls
[main]               or your builds will no longer be supported.
[main]
[main]               See
[main]       https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#license
[main]       for details.
[main]
[main]       ********************************************************************************
[main]
[main]       !!
[main]         corresp(dist, value, root_dir)
[main]       /app/.cache/uv/builds-v0/.tmpsEfKY8/lib/python3.13/site-packages/setuptools/config/_apply_pyprojecttoml.py:61:
[main]       SetuptoolsDeprecationWarning: License classifiers are deprecated.
[main]       !!
[main]
[main]
[main]       ********************************************************************************
[main]               Please consider removing the following classifiers in favor of a
[main]       SPDX license expression:
[main]
[main]               License :: OSI Approved :: BSD License
[main]
[main]               See
[main]       https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#license
[main]       for details.
[main]
[main]       ********************************************************************************
[main]
[main]       !!
[main]         dist._finalize_license_expression()
[main]       /app/.cache/uv/builds-v0/.tmpsEfKY8/lib/python3.13/site-packages/setuptools/dist.py:759:
[main]       SetuptoolsDeprecationWarning: License classifiers are deprecated.
[main]       !!
[main]
[main]
[main]       ********************************************************************************
[main]               Please consider removing the following classifiers in favor of a
[main]       SPDX license expression:
[main]
[main]               License :: OSI Approved :: BSD License
[main]
[main]               See
[main]       https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#license
[main]       for details.
[main]
[main]       ********************************************************************************
[main]
[main]       !!
[main]         self._finalize_license_expression()
[main]       warning: no previously-included files found matching
[main]       'src/evdev/ecodes.c'
[main]       The 'linux/input.h' and 'linux/input-event-codes.h' include files
[main]       are missing. You will have to install the kernel header files in
[main]       order to continue:
[main]
[main]           dnf install kernel-headers-$(uname -r)
[main]           apt-get install linux-headers-$(uname -r)
[main]           emerge sys-kernel/linux-headers
[main]           pacman -S kernel-headers
[main]
[main]       In case they are installed in a non-standard location, you may use
[main]       the '--evdev-headers' option to specify one or more colon-separated
[main]       paths. For example:
[main]
[main]           python setup.py \
[main]             build \
[main]             build_ecodes --evdev-headers path/input.h:path/input-event-codes.h
[main]       \
[main]             build_ext --include-dirs path/ \
[main]             install
[main]
[main]       If you want to avoid building this package from source, then please
[main]       consider
[main]       installing the `evdev-binary` package instead. Keep in mind that it may
[main]       not be
[main]       fully compatible with, or support all the features of your current
[main]       kernel.
[main]
[main]       hint: This usually indicates a problem with the package or the build
[main]       environment.
[main] Clearing cache at: .cache/uv
[main] Removed 573 files (4.9MiB)
[main] Traceback (most recent call last):
[main]   File "/app/python/main.py", line 1, in <module>
[main]     from evdev import InputDevice, categorize, ecodes
[main] ModuleNotFoundError: No module named 'evdev'
[main] Activating python virtual environment
[main] No cache found at: .cache/uv
[main] Traceback (most recent call last):
[main]   File "/app/python/main.py", line 1, in <module>
[main]     from evdev import InputDevice, categorize, ecodes
[main] ModuleNotFoundError: No module named 'evdev'
[main] Activating python virtual environment
[main] No cache found at: .cache/uv
[main] Traceback (most recent call last):
[main]   File "/app/python/main.py", line 1, in <module>
[main]     from evdev import InputDevice, categorize, ecodes
[main] ModuleNotFoundError: No module named 'evdev'

I’m not completely sure but from what I can tell evdev probably can’t install on App Lab because it needs Linux kernel headers and App Lab doesn’t seem to have those That might be why pip the venv and even requirements.txt all fail the same way It doesn’t look like a configuration problem more like the environment just can’t build evdev You might need a pure-Python alternative instead

EDITE

If you want, you can check how your barcode scanner appears on the system. That will tell us which pure-Python library will work. You can try this in SSH:

ls /dev/input
ls /dev/tty*

If it shows up under /dev/tty*, then pyserial will work.
If it shows up as a HID device, we can try hidapi or pyusb.
If it behaves like a keyboard, you can read from standard input without evdev.

Just let me know what your scanner shows, and I can point you to the right alternative.

The Python script of the App runs in a Docker container, isolated from the global Linux environment.

So the problem is that the environment of that container doesn't provide what is required by the evdev package.

Since the container is provided by Arduino App Lab, it is not wrong to refer to this as "App Lab", but it is also important to understand the nature of the problem at a lower level.

Thanks for the explanation that makes sense I wasn’t fully sure how isolated the App Lab container was, but if it’s running inside a minimal Docker image that doesn’t include kernel headers then yeah evdev won’t build even if it’s added to requirements.txt

Thanks for the response.

So since python runs in a container a lot of already-available libraries won't work without some kind of "hacking"?

I expect LLMs to be especially unreliable in these early days with the Uno Q. They will not have enough data and they will not distinguish between before and after bug fixes. Worse still the similarity of the board name with older boards will lead to wrong answers.

That’s a fair point new boards like the Uno Q change fast and AI doesn’t always have the latest details
I only mentioned it as an extra place to double-check things, not as a replacement for real debugging

Everything I wrote was based on how the venv and pip behave not AI guesses
If there’s something specific about App Lab’s environment I missed, I’m happy to adjust

I was reacting to the reliability of LLMs (especially with new stuff) and not anything else you said.
Really think that LLM should be considered simulated intelligence rather than artificial intelligence as they work like a extraordinary auto complete.

Hello all,

I think I found a workaround for downloading Python packages. I was wanting to use Redis and couldn’t figure out how to install it. Going the route of accessing the virtual environment didn’t work because I couldn’t get my pip to point to my virtual environment. Also, adding the “requirements.txt” didn’t work either; Arduino App Lab didn’t even consider it.

Here’s what worked for me. At the top of my Python file, I used these lines:

import subprocess
import sys

try:
    import redis
except ModuleNotFoundError:
    print("Installing redis package...")
    subprocess.check_call([sys.executable, "-m", "pip", "install", "redis", "--break-system-packages"])
    print("Redis package installed successfully!")
    import redis

This worked like a charm. Here are the logs:

Installing redis package...
Defaulting to user installation because normal site-packages is not writeable
Collecting redis
Downloading redis-7.2.0-py3-none-any.whl.metadata (12 kB)
Downloading redis-7.2.0-py3-none-any.whl (394 kB)
Installing collected packages: redis
Successfully installed redis-7.2.0
[notice] A new release of pip is available: 25.2 -> 26.0.1
[notice] To update, run: pip install --upgrade pip
Redis package installed successfully!

I hope this helps you all.

Nice, thank you! Will it persist in the container or will download every app start?

From the little time that I’ve spent with it, it looks like it will persist. So, I guess you can delete all those lines and leave “import redis” (though I haven’t tried this yet).

Thanks for this!!

Running some tests on my own, I have found that creating a requirements.txt file in the python folder, and adding the package name does the trick - AppLab installs them for me (as this post talked about - which I believe you had tried as well)

#requirements.txt

redis
pyserial
# main.py
from arduino.app_utils import App

import requests
print(requests.__version__)

import pandas as pd
print(pd.__version__)

import redis
print(redis.__version__)

import serial
print(serial.__version__)

App.run()

From Python console in AppLab:

Using CPython 3.13.9 interpreter at: /usr/local/bin/python
Creating virtual environment at: .cache/.venv
Activating python virtual environment
Using Python 3.13.9 environment at: .cache/.venv
Resolved 2 packages in 341ms
Prepared 2 packages in 188ms
Installed 2 packages in 24ms
+ pyserial==3.5
+ redis==7.2.1
Clearing cache at: .cache/uv
Removed 166 files (2.1MiB)
2.32.5
2.3.2
7.2.1
3.5
2026-03-05 20:16:24.015 INFO - [MainThread] App:  App started
======== App is starting ============================

If I stop and run the app again, it sees the requirements are already installed:

======== App is starting ============================
Activating python virtual environment
Requirements already installed.
Using Python 3.13.9 environment at: .cache/.venv
Audited 2 packages in 321ms
Clearing cache at: .cache/uv
Removed 6 files (1.1KiB)
2.32.5
2.3.2
7.2.1
3.5
======== App is starting ============================
2026-03-05 20:20:11.443 INFO - [MainThread] App:  App started

Just thought I would add this.

Great news. Thanks.

I tried this a while ago, and it didn’t work for me. Maybe this has been fixed in the newest version of Arduino App Lab.