[Blender Error] AttributeError: ‘_RestrictContext’ object has no attribute ‘view_layer’

Error Detail

When I activate my addon that uses operations with bpy.ops in register() function, the error “AttributeError: ‘_RestrictContext’ object has no attribute ‘view_layer’ ” occurred.

myAddon.py

bl_info = {
    "name": "Add cubes addon",
    "author": "Nako",
    "version": (1, 0),
    "blender": (2, 83, 0),
    "location": "",
    "description": "Adds Cube Objects",
    "warning": "",
    "doc_url": "",
    "category": "Add Mesh",
}

import bpy
def add_cubes(num):
    for i in range(num):
        bpy.ops.mesh.primitive_cube_add(size=1,location=(0, 0, 2+1.5*i))
def register():
    print("register")
    add_cubes(4)
def unregister():
    print("unregister")
if __name__ == "__main__":
    register()

The following is the error details.

Exception in module register(): C:\Users\<USER_NAMWE>\AppData\Roaming\Blender Foundation\Blender\2.83\scripts\addons\myAddon.py
Traceback (most recent call last):
  File "C:\Program Files\Blender Foundation\Blender 2.83\2.83\scripts\modules\addon_utils.py", line 382, in enable
    mod.register()
  File "C:\Users\<USER_NAMWE>\AppData\Roaming\Blender Foundation\Blender\2.83\scripts\addons\myAddon.py", line 19, in register
    add_cubes(4)
  File "C:\Users\<USER_NAMWE>\AppData\Roaming\Blender Foundation\Blender\2.83\scripts\addons\myAddon.py", line 16, in add_cubes
    bpy.ops.mesh.primitive_cube_add(size=1,location=(0, 0, 2+1.5*i))
  File "C:\Program Files\Blender Foundation\Blender 2.83\2.83\scripts\modules\bpy\ops.py", line 195, in __call__
    BPyOpsSubModOp._view_layer_update(context)
  File "C:\Program Files\Blender Foundation\Blender 2.83\2.83\scripts\modules\bpy\ops.py", line 157, in _view_layer_update
    view_layer = context.view_layer
AttributeError: '_RestrictContext' object has no attribute 'view_layer'

Cause

That’s because Blender restricts access to bpy.context and bpy.data.

To avoid errors on accessing blend-file data while addons register() / unregister(), Blender now restricts access to bpy.context and bpy.data.


This is done because there is no assurance that the data loaded when the addon is registered will be active or even exist when the user accesses operators the addon defines.

“Restricted Context” in archived version of the Blender Developer Wiki.

Solution

Run functions manually after Blender loading.

myAddonUI.py

bl_info = {
    "name": "Add cubes addon",
    "author": "Nako",
    "version": (1, 0),
    "blender": (2, 83, 0),
    "location": "",
    "description": "Adds Cube Objects",
    "warning": "",
    "doc_url": "",
    "category": "Add Mesh",
}

import bpy

def add_cubes(num):
    for i in range(num):
        bpy.ops.mesh.primitive_cube_add(size=1,location=(0, 0, 2+1.5*i))

class MYADDON_OT_add_cubes(bpy.types.Operator):
    """Create 4 cubes"""
    bl_idname = "myaddon.add_cubes"
    bl_label = "Add Cubes"
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):
        add_cubes(4)
        return {'FINISHED'}

class MUADDON_OT_MyPanel(bpy.types.Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "MyAddon"
    bl_label = "AddCubesPanel"
    def draw(self, context):
        layout = self.layout
        layout.operator(MYADDON_OT_add_cubes.bl_idname, text="Add Cubes")

classes = [MYADDON_OT_add_cubes, MUADDON_OT_MyPanel]

def register():
    for c in classes:
        bpy.utils.register_class(c)
def unregister():
    for c in classes:
        bpy.utils.unregister_class(c)
if __name__ == "__main__":
    register()

The function add_cubes(4) is called when the operator “MYADDON_OT_add_cubes” is executed.

The panel and button is displayed in 3D view. Click the button to generate 4 cubes.

Use handler

myAddonHandler.py

bl_info = {
    "name": "Add cubes addon",
    "author": "Nako",
    "version": (1, 0),
    "blender": (2, 83, 0),
    "location": "",
    "description": "Adds Cube Objects",
    "warning": "",
    "doc_url": "",
    "category": "Add Mesh",
}

import bpy
from bpy.app.handlers import persistent

@persistent
def add_cubes(dummy):
    num = 4
    for i in range(num):
        bpy.ops.mesh.primitive_cube_add(size=1,location=(0, 0, 2+1.5*i))
def register():
    print("register1")
    bpy.app.handlers.load_post.append(add_cubes)
def unregister():
    print("unregister1")
if __name__ == "__main__":
    register()

The startup scene is as follows.

Check “How To Run Python Script When Blender Starts” for details about how to start blender running python script.