Official PyCharm / IntelliJ support for PyMCU — a compiler that turns a statically-typed subset of Python into bare-metal firmware for AVR, RP2040 / RP2350, PIC and RISC-V microcontrollers. No runtime, no interpreter, no VM.
The plugin is a thin layer over the pymcu CLI: everything it knows about your boards, your
sources and the language subset comes from the driver, so the two never drift.
- Build, flash and clean as run configurations, with
pymcucdiagnostics turned into clickablefile:line:collinks in the console.--verbose,--explainand--debugare checkboxes. - Porting assistant —
pymcu lintfindings appear as editor annotations as you type or save, each with a concrete rewrite, plus a navigable list in the PyMCU tool window. Paste MicroPython code and follow the squiggles until it compiles. - Resolution and completion for
pymcu.*, the MicroPython / CircuitPython compat layers (machine,board,digitalio, …) and the generatedboardmodule for your target — always to the source, never to a stub. Ctrl-clickpin.value(1)and you land on the code that toggles the register, not ondef value(...) -> int: .... - Navigation follows the compile-time dispatch. The HAL picks its implementation from
__CHIP__, so one name exists once per architecture and again once per chip. The plugin evaluates those conditions against your target, so Ctrl-click on an Arduino Uno project lands inhal/avr/gpio/atmega328p.pyand not in a Leonardo's or an RP2040's. The branches your target does not build are greyed out in the editor. - Project configuration dialog — board, clock, compat stdlib, programmer, serial port and AVR
fuses, written back to
[tool.pymcu]without disturbing your comments or formatting. The board list comes frompymcu boards --json, so it matches whatever backends you have installed. - Library manager — browse, install and remove PyMCU libraries in the tool window. The index records whether each library actually built for each chip, so an incompatible one says why instead of failing at build time.
pyproject.tomlinspection — the deprecatedchipkey, aboard/targetconflict, a missing target and an unknown board are flagged in the editor, each with the fix. Edits preserve your comments and formatting.- Get Started checklist — the path from empty project to flashed board, with every step computed from what is actually on disk. It doubles as the place to look when an import will not resolve.
- Status bar target indicator that opens that dialog, a serial-port picker on flash, and a
New Project wizard that scaffolds through
pymcu new— the same project the CLI would create, toolchain and programmer included, so it builds and flashes without further edits.
- PyCharm (Community or Professional) 2024.3 or newer, or IntelliJ IDEA with the Python plugin.
- The PyMCU CLI:
pipx install pymcu-compiler, or addpymcu-compilerto your project withuv. The plugin looks for.venv/bin/pymcufirst, thenPATH.
All under Tools | PyMCU, and on the PyMCU tool window's toolbar.
| Action | Runs |
|---|---|
| Build | pymcu build (⌃⇧B / Ctrl+Shift+B) |
| Flash | pymcu flash, asking which port when none is pinned |
| Clean | pymcu clean |
| Build and Explain | pymcu build --explain — reports the setup the compiler injected implicitly |
| Lint Project (Porting Assistant) | pymcu lint over the configured sources |
| Sync Project | dependency install, then pymcu sync and pymcu stubs |
| Export Type Stubs… | pymcu stubs, for type checkers outside the IDE |
| Serial Monitor | a console on the board's UART, at the project's stdout_baud |
| Configure Project… | the board / flash configuration dialog |
The tool window has three tabs: Get Started (setup checklist), Libraries (install and remove) and Porting (assistant findings).
Settings | Tools | PyMCU
| Setting | Default | Meaning |
|---|---|---|
| PyMCU executable | pymcu |
Empty or pymcu resolves .venv/bin/pymcu, then PATH |
| Package manager | uv |
Used by Sync: uv sync, pip install -e ., poetry install, pipenv install |
| Run porting assistant | onSave |
onSave, onType or off |
| Compat flavor | auto |
auto derives it from the project's stdlib setting |
| Report only hard blockers | off | Passes --errors-only to pymcu lint |
| Offer to sync on open | on | Offers a sync when generated files are missing; never syncs unasked |
- New Project | PyMCU, or open a folder whose
pyproject.tomlhas a[tool.pymcu]section. - Pick your board in Tools | PyMCU | Configure Project… — it shows in the status bar.
- Write Python, or paste MicroPython / CircuitPython code and follow the porting assistant.
- Build, then Flash.
Until the plugin is on the Marketplace, install it from a .zip:
PyCharm → Settings → Plugins → ⚙ → Install Plugin from Disk… → pick the zip → restart.
- Latest
main: thedevprerelease, rebuilt on every push. Direct link:https://github.com/PyMCU/jetbrains-pymcu/releases/download/dev/jetbrains-pymcu-dev.zip - Built yourself:
./gradlew buildPlugin→build/distributions/jetbrains-pymcu-<version>.zip
The target machine needs PyCharm 2024.3+ and the PyMCU CLI. It does not need a JDK or Gradle.
Work that is merged but not ready is off behind a registry key. To try one: Help → Find Action → Registry…, then search for the key.
| Key | Default | What it gates |
|---|---|---|
pymcu.debugger.enabled |
off | Emulator debugging. Not implemented yet — turning it on currently changes nothing. |
./gradlew buildPlugin # → build/distributions/jetbrains-pymcu-<version>.zip
./gradlew test # unit tests
./gradlew runIde # a sandboxed PyCharm with the plugin loaded
./gradlew verifyPlugin # JetBrains plugin verifier, as run in CIRequires JDK 21. Gradle finds it on PATH/JAVA_HOME automatically on most
setups; if you need to point at a specific JDK, set org.gradle.java.home in
your own ~/.gradle/gradle.properties rather than this project's (a
per-machine path here would break the build for everyone else).
Some features need a pymcu new enough to answer in JSON. Older CLIs degrade rather than break —
the affected panel says so and the rest keeps working.
| Feature | Needs |
|---|---|
| Board catalog | pymcu boards --json |
| Porting assistant | pymcu lint --json |
| Library manager | pymcu libraries --json, pymcu search --json |
PyMCU's claim is that the abstraction is free — pin.value(1) compiles to the same SBI a C
programmer would write by hand. That claim is only checkable if you can read the code, so the
plugin never resolves to a generated stub:
- Go to declaration on anything from
machine,digitalioorboardopens the real implementation, comments and@inlinedecorators included. - The sync does not generate
.pyifiles. An earlier version did, and it made the stdlib a black box for a little tidiness in the type hints — a bad trade for this project. - Types are not lost by it: annotations reference
pymcu.types, an installed package the interpreter resolves on its own, souint8reads asuint8rather than as a stubbedint. - Build and Explain (
pymcu build --explain) is the other half: it reports the setup the compiler injected implicitly — clock init, stdout UART, ISR vectors.
Export Type Stubs… still exists for mypy or pyright running outside the IDE. The editor ignores what it writes.
The two extensions target the same workflow and the same CLI surface. Where they differ, it is
because the host does: PyCharm gets run configurations and a Swing dialog where VS Code gets tasks
and a webview; VS Code writes python.analysis.extraPaths for Pylance where PyCharm gets an
AdditionalLibraryRootsProvider. Behaviour, settings names and defaults are kept in step.
MIT — see LICENSE.