Add-on Development Setup¶
Developing add-ons for Blender doesn't have any technical requirements besides Blender itself and can be done using any text editor, including Blender's built-in text editor. While everything written below is a recommendation, having a correct development setup, and environment that is more suited for medium or large-sized projects can massively help in the development process.
Installing Python¶
Blender add-ons are written entirely in Python. Any Blender installation comes with built-in Python (and scripts are only executed by Blender itself). Therefore, having Python installed in the system isn't required by Blender, but it's required by IDEs where you will be writing code.
- On Windows, it is recommended to download and install Python from the official website. It's also important that during installation Python is added in system PATH and
pylauncher is also installed. - On Mac, install it from Homebrew or download installer from the official website.
- On Linux, any distro will likely already have Python installed, but it might not be the correct version. Install/update it with your choice of package manager.
Which Python version?¶
Each Blender version comes with the Python version recommended by VFX Reference Platform for the year of its release. It is likely that it will not be the latest version. However, installing the latest version of Python is OK in most cases, as long as you don't use features not available in Blender's Python version. Blender will execute all scripts in its own Python environment, so the Python version used by IDE is mostly relevant only for syntax highlighting, and language support tools, which do not change drastically between versions.
In rare, complex cases the Python version used by Blender may also be required, and should be installed as well. That might be the case if, for example, an add-on uses wheels that need testing and/or debugging outside Blender.
Setting Up Development Environment¶
Any IDE or just a programming-oriented text editor can be used for add-on development, but some IDEs have become more popular in Blender's large add-on development community and offer more benefits, such as community-made extensions and larger support groups.
- The most popular choice, as well as most supported, is Visual Studio Code, but it requires some manual setup. See full guide on VS Code setup for add-on development
Code Completion¶
When importing and using bpy in Python scripts, Pylance will raise an unresolved import error. VS Code will also not be able to offer any code completion for bpy API. Installing bpy module will not solve this issue, because it doesn't come with stub files that are necessary for IDEs to offer the intelligence tools.
However, there are community projects that offer code completion. Most popular among the Blender community is fake-bpy-module, developed by long-time Blender contributors. This module provides code completion not only for the bpy module, but also for other Blender libraries, like gpu and mathutils, as well as Blender's internal Python directories & scripts.
fake-bpy-module is a Python library and can be installed with pip from any terminal:
Setting Up Project¶
To be able to run, test, and use your add-on in Blender, you'll need to install it as an extension, meaning its directory must be placed inside one of the extension repositories. However, developing in the same directory that is read by Blender however is dangerous and can result in lost or corrupted files.
To work around this, you can set up your development directory anywhere, and then create a symbolic link (AKA symlink) to it inside a local extensions repository.
It's recommended that you create a new local repository from Blender's preferences specifically for in-development add-ons. It is also strongly recommended that you do not put this local repository inside any directories created by Blender itself, since those can be overwritten or duplicated by new versions.
Blender expects extensions to have blender_manifest.toml and __init__.py files in the root directory. If the root of your project doesn't have those files, you need to symlink the subdirectory that does.
A symlink can be created from a terminal:
- On Windows (documentation):
mklink /d "/path_to_local_repository/addon_name" "/path_to_project_directory/" - On Mac and Linux (documentation):
ln -s "/path_to_project_directory/" "/path_to_local_repository/addon_name"
Warning
This set-up will allow you to test uninstalling add-ons from Blender preferences (which is recommended before distributing add-ons), but be aware that in some cases, especially on Windows, uninstalling from Blender can result in the loss of the development directory as well, i.e. symlink target. Make sure you back everything up before you uninstall.
Reloading Scripts¶
To reflect changes made in add-on code live Blender needs to unregister and re-register that add-on. This is automatically done when you close and open Blender, but during active testing this can become difficult. To make things easier, Blender has "Reload Scripts" operator (in Blender -> System. Blender menu refers to Blender logo in the top-left), but it can only reload scripts & add-ons that are set up for this.
To support reloading, add-on must have a clear import structure. Importing is a complicated topic, and can look very different in projects depending on their size, goal, and style but the general idea conveyed by the example script below is the same. Main __init__.py file needs to check whether bpy is in locals (in this case meaning "the module was loaded before"). If not, everything needs to be imported so Blender can register the add-on, otherwise it just needs to reload those modules with Python's importlib library.
_needs_reload = "bpy" in locals()
import bpy
from . import (
module1,
module2,
module3,
)
if _needs_reload:
import importlib
module1 = importlib.reload(module1)
module2 = importlib.reload(module2)
module3 = importlib.reload(module3)
print("Add-on Reloaded")
This is only necessary in main __init__.py file, but if you are importing subdirectories as modules you need to set up similar import structure in the __init__.py files of those subdirectories as well.