System designTroubleshooting

Python keyboard module has no is_pressed: fix the shadowed import

Why a Python example fails with module 'keyboard' has no attribute 'is_pressed', how to find the shadowing file, and the reinstall steps that fix it.

LumaSpec Vision9 min read Share on LinkedIn

On this page 11 sections
  1. 01What the error is telling you
  2. 02Find what Python actually imported
  3. 03Cause 1: a file named keyboard next to the script
  4. 04Cause 2: two installs, and the wrong one wins
  5. 05Cause 3: sudo runs a different Python
  6. 06The permission behind sudo, and the way to drop it
  7. 07Fix it in order
  8. 08When it still fails
  9. 09On the bench and on the machine
  10. 10Checks before you close the ticket
  11. 11Questions

You wire a keypress into a camera SDK's Python example so you can stop the grab loop by hand, and Python answers with AttributeError: module 'keyboard' has no attribute 'is_pressed'. The package is installed, the camera is detected, frames flow — only the key check dies, and the SDK then aborts with its own complaint about a reference it cannot clear. The import resolved the name keyboard to the wrong file: a stray script, a second install or the sudo environment picked it. This guide gives you the 60-second test that shows which file answered, the three causes in the order they usually strike, and the fix that ends with a clean exit by key.

What the error is telling you

The traceback line matters more than its position. AttributeError: module 'keyboard' has no attribute 'is_pressed' says the object your script reached through the name keyboard has no function called is_pressed. The key-hook package the example expects does provide is_pressed, so the name resolved either to a different file or to a half-loaded copy of the right one. Both are import problems, not a bug in the example's logic.

The second exception is a passenger. The AttributeError killed the process mid-acquisition, before the SDK released its camera handle and buffers, so its cleanup path raised its own error about something still holding a reference. Cure the import and this one disappears with it.

Everything before the crash was healthy: the SDK printed its library version, found the camera, set continuous acquisition and grabbed frames with the serial number read back. The grab loop and continuous camera acquisition mode for live image loops are not what broke — only the exit key. Attribute errors of this shape mean the imported name is not what the example author expected; the same family shows up as NumPy module has no attribute float: fix the removed alias.

Find what Python actually imported

Sixty seconds settle it. Run this in the example directory, as the same user, with the same sudo choice as the failing run:

python3 -c 'import keyboard; print(keyboard.__file__); print(hasattr(keyboard, "is_pressed"))'

A healthy run prints a site-packages or dist-packages path, then True. Read any other result against the three causes:

  • A path inside the example folder: a shadowing file won the import — Cause 1.
  • A site-packages path but False for is_pressed: the installed copy is old, broken or from another project — Cause 2.
  • The failure appears only when you prepend sudo: root is answering from a different environment — Cause 3.

python3 -m pip show keyboard adds Version and Location. Compare Location with the path file printed; disagreeing paths mean two copies exist.

Cause 1: a file named keyboard next to the script

Python searches the script's own directory first, ahead of every installed package: the script's folder is the first entry on sys.path, which is how the import system is defined to work. So a keyboard.py sitting in the examples folder — unpacked package files, a helper someone left behind, your own test — beats site-packages every time. A folder named keyboard with an init.py inside does the same.

Spot it from the example directory:

ls -1 | grep -i keyboard

A hit is your shadow. If your own file keyboard.py imports keyboard, you get the cousin message instead: partially initialized module 'keyboard'. Move or rename the file, then re-run the identity check. The compiled copy in pycache is only a cache; without its source file it never imports.

Cause 2: two installs, and the wrong one wins

pip keeps one distribution per environment, and a bench PC quietly accumulates environments: user site under ~/.local/lib/python3.8/site-packages, system dist-packages under /usr/lib/python3, a virtualenv from an earlier project. The copy that answers is whichever sits highest in the search order of the interpreter that runs the script, and an old or half-installed copy can lack is_pressed entirely.

Compare the two reports: the Location line from python3 -m pip show keyboard against the path file printed. Differing paths mean at least two installs.

Purge before you reinstall. Run python3 -m pip uninstall keyboard as your user until pip reports nothing installed; run the same command once with sudo if you have ever installed with sudo. Then install one clean copy into the interpreter that runs the example — the fix list below puts it all in order.

Cause 3: sudo runs a different Python

sudo python3 example.py starts root's interpreter with a reset environment. Your user-site folder is not on root's path, and PYTHONPATH from your session is dropped. A keyboard installed for your user becomes invisible; any old system-wide copy becomes the one that answers. That is why you can see AttributeError — found, but wrong — instead of the ModuleNotFoundError you might expect.

Pick one environment and stay in it:

  • Unprivileged: install with python3 -m pip install keyboard and grant key access the way the next section shows.
  • As root, consistently: sudo python3 -m pip install keyboard, and uninstall stray copies from both sides.

Mixing the two is what builds the duplicate-copy problem in the first place. The interpreter mismatch has a wider family: GenICam Python package not found: match your interpreter fails the same way when the install and the run use different Pythons.

The permission behind sudo, and the way to drop it

The keyboard package reads the raw event devices under /dev/input to hook keys globally without depending on a display server, and ordinary users cannot open those files. That is the only reason the example asks for sudo. You can grant just that access instead:

sudo usermod -aG input $USER

Log out and back in, then confirm groups lists input — on current Ubuntu releases the event devices under /dev/input are group-owned by input and readable by its members.

In a desktop session pynput is the no-root alternative: it listens through the X display server, so an X11 login works as your user, while Wayland restricts global key capture. Privilege errors around imaging tools are a family — on Windows the same class appears as GigE configurator tool admin rights: fix the Windows error.

Fix it in order

  1. Identify the import: run the one-liner from the section above and note the path and the True/False answer.
  2. Delete shadows in the example directory: any keyboard.py, any keyboard/ folder with an init.py.
  3. Purge copies: python3 -m pip uninstall keyboard as your user, then once with sudo if you ever used it, until pip reports nothing installed.
  4. Install once, into the interpreter that runs the example: python3 -m pip install keyboard. The -m form binds the install to that exact interpreter, so skip bare pip3. If the SDK example's README pins versions for keyboard and matplotlib, install exactly those.
  5. Verify: the one-liner from step 1 now prints a site-packages or dist-packages path and True.
  6. Grant key access: add yourself to the input group with sudo usermod -aG input $USER and log in again, or commit to running with sudo everywhere.
  7. Re-run the example: camera detected, serial printed, frames acquired — and the exit key closes it cleanly, because the abort that dragged the SDK cleanup error along is gone.

When it still fails

Right path, still False: the import was partial. Usually your own keyboard.py imports keyboard, or a PYTHONPATH entry carries another copy. Print the real search order with python3 -c 'import sys; print(sys.path)' and clear every entry ahead of site-packages that holds a keyboard file or a regular package.

Works at your desk, dies headless: a service or an unattended cell has no display and no one to press keys. Remove the key check entirely and trigger the loop from wiring instead — read camera GPIO input and output pins at the same time covers the pin side, and hardware trigger stops after one frame: check acquisition mode covers the trigger replacing the keyboard as the loop's clock.

Cleanup error on Ctrl-C persists: the release calls are not in a finally block, so an abrupt exit skips them. The same fail-fast discipline keeps a lost network link from hanging a session — see GigE camera disconnected detection: fail fast instead of freezing.

On the bench and on the machine

On the bench, any Linux PC with a free USB3 port runs SDK examples; the camera finder filters area scan cameras by interface, resolution and shutter. In the cell, the same loop runs unattended on a vision controller, where no keyboard is expected and the trigger does the timing.

The MV-VC2140-128G40-1T pairs an Intel N-series processor with 8 GB of memory, 3-4 LAN ports, 2 USB 3 ports and 4 built-in light channels. The MV-VC3301H-128G66 moves up to an Intel Core i3, still with 8 GB of memory, and carries 5+ LAN ports, 3-4 USB 3 ports, 4 built-in light channels and a bundled VM6200Pro license.

Vision controllersHikrobot MV-VC2140-128G40-1T VC2100 Vision Controller, N97, 8GB+128G SSD+ 1THDDMV-VC2140-128G40-1T
LAN ports
3-4 LAN ports
USB 3 ports
2 USB 3 ports
$1,679.00View part
Vision controllersHikrobot MV-VC3301H-128G66 I3-8100, 8GB+128G SSD, No PoE, PCIe expansion supported, Incl. VM6200Pro licenseMV-VC3301H-128G66
LAN ports
5+ LAN ports
USB 3 ports
3-4 USB 3 ports
$2,419.00View part

Deploy the fixed pattern, not the key: environment matched, permissions granted, release calls in a finally block.

Checks before you close the ticket

  • keyboard.__file__ ends in site-packages or dist-packages, not in the example folder.
  • hasattr(keyboard, 'is_pressed') prints True under the same user and privilege choice that runs the example.
  • python3 -m pip show keyboard shows one Version, and its Location matches file.
  • groups includes input, or you deliberately run with sudo everywhere.
  • The example exits by key with no SDK cleanup exception behind it.
  • The headless deployment has no key checks left: the loop starts on a trigger you wired.

More fixes for environment and driver trouble live on the systems topic page. If you are specifying the cell rather than fixing the bench, start at the camera step of the configurator or contact the applications team with the SDK, the OS and the traceback — the answer comes back with parts that fit it.

Questions

Why does the import only fail when I run the example with sudo?

sudo starts root's interpreter with a reset environment: the user site folder in your home (~/.local/lib/python3.8/site-packages on Python 3.8) is not searched, and PYTHONPATH from your session is dropped. Python then answers with whatever system-wide copy exists, and if that copy is old or from another project you get the AttributeError instead of a clean ModuleNotFoundError. Either install with sudo python3 -m pip install keyboard, or drop sudo and grant input-group access.

How do I check which file a module name was loaded from?

Import the name and print the module's __file__: python3 -c 'import keyboard; print(keyboard.__file__)'. A path under site-packages or dist-packages means the installed package answered; a path inside your example folder means a shadowing file won. The same one-liner audits any module, so check matplotlib or your SDK package before a bench session the same way.

Does the keyboard package need root on every Linux system?

It hooks global keys by reading the raw event devices under /dev/input, which ordinary users cannot open, so it needs root or input-group membership on current Ubuntu releases. Inside a desktop X11 session, pynput is the no-root alternative: it listens through the display server instead. Wayland restricts global key capture, so headless and Wayland setups fall back to GPIO triggers.

Why did the SDK report that something still holds a reference to the camera?

The AttributeError killed the example mid-acquisition, so the process tore down before the SDK released its handle and buffers; its cleanup then raised its own complaint. Fix the import and the error disappears. When you stop a grab loop by hand, put the release calls in a finally block so they run even on an exception or Ctrl-C.

Which versions of keyboard does a camera SDK example need?

Use the set the SDK example's README pins; it lists the tested dependencies, keyboard and matplotlib among them. Install them as one set into the interpreter that runs the example. Upgrading keyboard alone can swap behavior under the example, and the shadowing fix is independent of version: what matters is which file the name keyboard resolves to.