2.80 Cheat Sheet for updating add-ons

This is a cheat sheet I originally made for myself to keep track of the Python API changes between 2.79 and 2.80. My goal was was to have a “CTRL F” quick reference I could use to avoid having to dig through API docs and add-on updates every time I wasn’t sure on what code changes were needed for 2.80.

Note: if discourse captures your “CTRL F” input for it’s custom search thing, you should be able to get your browser’s page search back by pressing “CTRL F” again (this worked for me in Firefox and Chrome).

Please read the note at the top related to the ‘???’ and ‘***’ markers throughout the cheat sheet before using this. A large part of this cheat sheet was pulled from git diff reports, so the syntax may not be correct in all cases.

See also

Blender 2.80 add-on update cheat sheet
??? = not verified or not correct in many cases, but may work
*** = verified to work in most or all cases

???  alpha needed
-mat.diffuse_color = (red_v, grn_v, blu_v)  # viewport color
+mat.diffuse_color = (red_v, grn_v, blu_v, alpha_v)  # viewport color

???  viewnumpad
-col.operator("view3d.viewnumpad", text="View Camera", icon='CAMERA_DATA').type = 'CAMERA'
+col.operator("view3d.view_camera", text="View Camera", icon='CAMERA_DATA')

???  viewnumpad
-bpy.ops.view3d.viewnumpad(type='BOTTOM')
+bpy.ops.view3d.view_axis(type='BOTTOM')

???  get_rna
-properties = op.get_rna().bl_rna.properties.items()
+properties = op.get_rna_type().properties.items()

???  viewport_shade
-pie.prop(context.space_data, "viewport_shade", expand=True)
+pie.prop(context.space_data.shading, "type", expand=True)
-if context.space_data.viewport_shade == 'RENDERED':
+if context.space_data.shading.type == 'RENDERED':

???  TOOLS
-bl_region_type = "TOOLS"
+bl_region_type = "UI"

???  View
-bl_region_type = 'View'
-bl_category = 'Tools'
+bl_region_type = 'UI'
+bl_category = 'View'
otherwise...
RuntimeError: Error: Registering panel class: 'view3d.blah' has category 'View'

???  Lamp
-"OUTPUT_LAMP"
-"ShaderNodeOutputLamp"
+"OUTPUT_LIGHT"
+"ShaderNodeOutputLight"

???  lamps
-bpy.data.lamps
+bpy.data.lights

***  select (only changed for objects, not verts/edges/faces)
-obj.select = False
+obj.select_set(False)
otherwise...
AttributeError: 'Object' object has no attribute 'select'
possible regex:
find: (\.select\s*=\s*)(True|False)
repl: .select_set\(\2\)

***  select (only changed for objects)
-if o.select:
+if o.select_get():
-if not obj.select:
+if not obj.select_get():
-if o.select is True:
+if o.select_get() is True:
possible regex:
find: (\.select)(\s*)(is|==)(\s*)(True|False)
repl: .select_get\(\)(\2)(\3)(\4)(\5)

???  backdrop_x / backdrop_y
-context.space_data.backdrop_x = 0
-context.space_data.backdrop_y = 0
+context.space_data.backdrop_offset[0] = 0
+context.space_data.backdrop_offset[1] = 0

???  ops.delete context
-bmesh.ops.delete(bm, geom=edges, context=1)
-bmesh.ops.delete(bm, geom=edges, context=2)
-bmesh.ops.delete(bm, geom=edges, context=3)
+bmesh.ops.delete(bm, geom=edges, context="VERTS")
+bmesh.ops.delete(bm, geom=edges, context="EDGES")
+bmesh.ops.delete(bm, geom=edges, context="FACES")
otherwise...
TypeError: delete: keyword "context" expected a string, not int

???  tessface
-bmesh.update_edit_mesh(object.data, tessface=True, destructive=True)
+bmesh.update_edit_mesh(object.data, loop_triangles=True, destructive=True)

???  to_mesh
 ob = bpy.context.active_object
 depsgraph = bpy.context.evaluated_depsgraph_get()
-mesh = ob.evaluated_get(depsgraph).to_mesh()
+ob_eval = ob.evaluated_get(depsgraph)
+mesh = ob_eval.to_mesh()

???  to_mesh (2)
 obj = bpy.context.active_object
-mesh = obj.to_mesh(context.scene, True, 'PREVIEW')
+depsgraph = context.evaluated_depsgraph_get()
+mesh = obj.evaluated_get(depsgraph).to_mesh()

???  meshes.remove
-bpy.data.meshes.remove(mesh)
+ob_eval.to_mesh_clear()

???  active
-plane = context.scene.objects.active
+plane = context.active_object

???  active
-bpy.context.scene.objects.active = obj
+bpy.context.view_layer.objects.active = obj
otherwise...
AttributeError: bpy_prop_collection: attribute "active" not found
#bpy.context.view_layer.objects.active = bpy.data.objects['Light'] ??
#bpy.context.view_layer.objects.active = None ??
#bpy.context.active_object ?

???  object_bases
-context.scene.object_bases
+obj = context.view_layer.objects.active  ??? 

???  frame_set subframe
-context.scene.frame_set(int(frame[1]), frame[0])
+context.scene.frame_set(int(frame[1]), subframe=frame[0])

???  prop text
-row.prop(self, "filter_auto_focus", "", icon='VIEWZOOM')
+row.prop(self, "filter_auto_focus", text="", icon='VIEWZOOM')

???  text (label)
-row.label(context.object.name)
+row.label(text=context.object.name)
-box.label("From curve")
+box.label(text="From curve")

???  show_x_ray
-col.prop(context.active_object, 'show_x_ray', toggle=False, text='X Ray')
+col.prop(context.active_object, 'show_in_front', toggle=False, text='X Ray')

???  popup_menu title
-context.window_manager.popup_menu(self.menu, "Icon Viewer")
+context.window_manager.popup_menu(self.menu, title="Icon Viewer")

???  operator text
-row.operator(IV_OT_panel_menu_call.bl_idname, "", icon='COLLAPSEMENU')
+row.operator(IV_OT_panel_menu_call.bl_idname, text="", icon='COLLAPSEMENU')

***  operator text
-row.operator("wm.url_open", "Google", icon='SOLO_ON'
-            ).url = "https://www.google.com"
+row.operator("wm.url_open", text="Google", icon='SOLO_ON'
+            ).url = "https://www.google.com"

***  label text
-col.label("Sharpness")
+col.label(text="Sharpness")
otherwise...
TypeError: UILayout.label(): required parameter "text" to be a keyword argument!

***  prop text
-row.prop(self, "ctrl", "Ctrl", toggle=True)
+row.prop(self, "ctrl", text="Ctrl", toggle=True)

***  prop text
-col.prop(self.overlay, "alignment", "")
+col.prop(self.overlay, "alignment", text="")

???  hide
-bpy.context.object.hide
+bpy.context.object.hide_viewport

???  Group
-bpy.types.Group()
+bpy.types.Collection()

???  groups
-bpy.data.groups
+bpy.data.collections

???  dupli_group
-context.active_object.dupli_group
+context.active_object.instance_collection

???  link
-scene.objects.link(newCurve)
+coll = context.view_layer.active_layer_collection.collection
+coll.objects.link(newCurve)

???  link
-bpy.context.scene.objects.link(newCurve)
+bpy.context.collection.objects.link(newCurve)
otherwise...
AttributeError: 'bpy_prop_collection' object has no attribute 'link'

???  unlink
-bpy.context.scene.objects.unlink(obj)
+bpy.context.collection.objects.unlink(obj)

???  draw_type
-bpy.context.object.data.draw_type = 'BBONE'
+bpy.context.object.data.display_type = 'BBONE'

???  draw_size
-bpy.data.cameras[cam_data_name].draw_size = 1.0
+bpy.data.cameras[cam_data_name].display_size = 1.0

???  uv_textures name
-me.uv_textures.new("Leaves")
+me.uv_layers.new(name="Leaves")

???  transform_apply location rotation scale
-bpy.ops.object.transform_apply(rotation=True, scale=True)
+bpy.ops.object.transform_apply(location=False, rotation=True, scale=True)

???  ops _add layers
-bpy.ops.mesh.primitive_cube_add(view_align=False, enter_editmode=False, 
-    location=(0.0, 0.0, 0.0), rotation=(0.0, 0.0, 0.0), layers=current_layers)
+bpy.ops.mesh.primitive_cube_add(view_align=False, enter_editmode=False, 
+    location=(0.0, 0.0, 0.0), rotation=(0.0, 0.0, 0.0))

???  view_align
 bpy.ops.curve.primitive_nurbs_path_add(
-  view_align=False, enter_editmode=False, location=(0, 0, 0)
+  align='WORLD', enter_editmode=False, location=(0, 0, 0)
 )

???  radius
-bpy.ops.mesh.primitive_ico_sphere_add(radius=0.2)
+bpy.ops.mesh.primitive_ico_sphere_add(size=0.4)

???  space_data transform_orientation
-orientation = bpy.context.space_data.transform_orientation
-custom = bpy.context.space_data.current_orientation
-bpy.context.space_data.transform_orientation = 'GLOBAL'
+orient_slot = bpy.context.scene.transform_orientation_slots[0]
+custom = orient_slot.custom_orientation
+bpy.context.scene.transform_orientation_slots[0].type = 'GLOBAL'
otherwise...
AttributeError: 'SpaceView3D' object has no attribute 'transform_orientation'

???  show_manipulator
-bpy.context.space_data.show_manipulator = False
+bpy.context.space_data.show_gizmo = True
otherwise...
AttributeError: 'SpaceView3D' object has no attribute 'show_manipulator'

???
bpy.ops.transform.translate
-proportional='DISABLED'
+use_proportional_edit=False

???  constraint_orientation
-bpy.ops.transform.resize('INVOKE_DEFAULT', constraint_axis = axis, constraint_orientation = 'GLOBAL')
+bpy.ops.transform.resize('INVOKE_DEFAULT', constraint_axis = axis, orient_type = 'GLOBAL')

***  user_preferences
-addons = bpy.context.user_preferences.addons
+addons = bpy.context.preferences.addons

???  user_preferences
-bpy.context.user_preferences.system.use_weight_color_range
+bpy.context.preferences.view.use_weight_color_range
"input.active_keyconfig", "keymap.active_keyconfig"
"input.show_ui_keyconfig", "keymap.show_ui_keyconfig"
"system.author", "filepaths.author"
"system.color_picker_type", "view.color_picker_type"
"system.font_path_ui", "view.font_path_ui"
"system.font_path_ui_mono", "view.font_path_ui_mono"
"system.language", "view.language"
"system.text_hinting", "view.text_hinting"
"system.use_international_fonts", "view.use_international_fonts"
"system.use_scripts_auto_execute", "filepaths.use_scripts_auto_execute"
"system.use_tabs_as_spaces", "filepaths.use_tabs_as_spaces"
"system.use_text_antialiasing", "view.use_text_antialiasing"
"system.use_translate_interface", "view.use_translate_interface"
"system.use_translate_new_dataname", "view.use_translate_new_dataname"
"system.use_translate_tooltips", "view.use_translate_tooltips"
"system.use_weight_color_range", "view.use_weight_color_range"
"system.weight_color_range", "view.weight_color_range"
"view.use_auto_perspective", "input.use_auto_perspective"
"view.use_camera_lock_parent", "input.use_camera_lock_parent"
"view.use_cursor_lock_adjust", "input.use_cursor_lock_adjust"
"view.use_mouse_depth_cursor", "input.use_mouse_depth_cursor"
"view.use_mouse_depth_navigate", "input.use_mouse_depth_navigate"
"view.use_quit_dialog", "view.use_save_prompt"
"view.use_rotate_around_active", "input.use_rotate_around_active"
"view.use_zoom_to_mouse", "input.use_zoom_to_mouse"

???  wm.addon_enable
-bpy.ops.wm.addon_enable(module=module)
+bpy.ops.preferences.addon_enable(module=module)

???  wm.addon_userpref_show
-layout.operator("wm.addon_userpref_show",
+layout.operator("preferences.addon_show",

???  select_mouse
-mouse_right = context.user_preferences.inputs.select_mouse
+wm = context.window_manager
+keyconfig = wm.keyconfigs.active
+mouse_right = getattr(keyconfig.preferences, "select_mouse", "LEFT")

***  percentage
-split = row.split(percentage=0.10, align=True)
+split = row.split(factor=0.10, align=True)

***  row align
-row = col.row(True)
+row = col.row(align=True)
otherwise...
TypeError: UILayout.row(): required parameter "align" to be a keyword argument!

***  scene_update_pre
-bpy.app.handlers.scene_update_pre
+bpy.app.handlers.depsgraph_update_pre

***  scene_update_post
-bpy.app.handlers.scene_update_post.append(check_drivers)
+bpy.app.handlers.depsgraph_update_post.append(check_drivers)

???  scene.update
-bpy.context.scene.update()
+bpy.context.view_layer.update()

???  use_occlude_geometry
-space_data.use_occlude_geometry
+space_data.shading.show_xray
otherwise...
AttributeError: 'SpaceView3D' object has no attribute 'use_occlude_geometry'

???  Matrix Multiplication
-normal = rotation * mathutils.Vector((0.0, 0.0, 1.0))
+normal = rotation @ mathutils.Vector((0.0, 0.0, 1.0))

???  viewport_shade
-self.snap_face = context.space_data.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'}
-self.sctx.set_snap_mode(True, True, self.snap_face)
+shading = context.space_data.shading
+self.snap_face = not (snap_edge_and_vert and
+                     (shading.show_xray or shading.type == 'WIREFRAME'))

***  Property (annotations, class def only, not in methods)
-b_prop = bpy.props.BoolProperty(name="Prop Name", default=True)
+b_prop: bpy.props.BoolProperty(name="Prop Name", default=True)
"BoolProperty", "BoolVectorProperty", "CollectionProperty", 
"EnumProperty", "FloatProperty", "FloatVectorProperty",
"IntProperty", "IntVectorProperty",
"PointerProperty", "StringProperty"
otherwise...
Warning: class FOO_OT_bar contains a properties which should be an annotation!
make annotation: FOO_OT_bar.the_int_prop

???  .order
-for k in cls.order:
     if k.startswith(some_str):
-        func, data = getattr(cls, k)
+for k in cls.__annotations__:
     if k.startswith(some_str):
+        func, data = cls.__annotations__[k]
otherwise...
AttributeError: type object 'FOO_OT_bar' has no attribute 'the_int_prop'

???  time_step
-self.timer = wm.event_timer_add(0.05, bpy.context.window)
+self.timer = wm.event_timer_add(time_step=0.05, window=bpy.context.window)

???  subframe
-context.scene.frame_set(10, 0.25)
+context.scene.frame_set(10, subframe=0.25)

???  INFO_MT_
-box.menu("INFO_MT_file_import", icon='IMPORT')
+box.menu("TOPBAR_MT_file_import", icon='IMPORT')

???  _specials
-scene = context.scene.mat_specials
+scene = context.scene.mat_context_menu
-bpy.types.VIEW3D_MT_edit_mesh_specials.prepend(menu_func)
+bpy.types.VIEW3D_MT_edit_mesh_context_menu.prepend(menu_func)

???  tweak_threshold
-tt = context.preferences.inputs.tweak_threshold
+tt = context.preferences.inputs.drag_threshold
otherwise...
rna_uiItemR: property not found: PreferencesInput.tweak_threshold

???  cursor_location
-endvertex = bpy.context.scene.cursor_location
+endvertex = bpy.context.scene.cursor.location

???  snap_element
-bpy.context.tool_settings.snap_element = 'VERTEX'
+bpy.context.tool_settings.snap_elements = {'VERTEX'}
otherwise...
AttributeError: 'ToolSettings' object has no attribute 'snap_element'

???  pivot_point
-pivot = bpy.context.space_data.pivot_point
+pivot = bpy.context.tool_settings.transform_pivot_point
otherwise...
AttributeError: 'SpaceView3D' object has no attribute 'pivot_point'

???  proportional_edit
 ts = context.tool_settings
-ts.proportional_edit = 'ENABLED'
+ts.use_proportional_edit = True

???  resetting header_text_set
-bpy.context.area.header_text_set(text='')
+context.area.header_text_set(None)

???  register_module
-bpy.utils.register_module(__name__)
+for cls in classes:
+    bpy.utils.register_class(cls)

???  icon
-row.label(text="Use Properties panel", icon='CURSOR')
+row.label(text="Use Properties panel", icon='PIVOT_CURSOR')
"BUTS", "PROPERTIES"
"CURSOR", "PIVOT_CURSOR"
"FULLSCREEN", "WINDOW"
"IMAGE_COL", "IMAGE"
"IPO", "GRAPH"
"LAMP", "LIGHT"
"LAMP_AREA", "LIGHT_AREA"
"LAMP_DATA", "LIGHT_DATA"
"LAMP_HEMI", "LIGHT_HEMI"
"LAMP_POINT", "LIGHT_POINT"
"LAMP_SPOT", "LIGHT_SPOT"
"LAMP_SUN", "LIGHT_SUN"
"LINK",  #  (maybe use DOT, LAYER_ACTIVE or LAYER_USED)
"LINK_AREA", "LINKED"
"OOPS", "OUTLINER"
"ORTHO", "XRAY"
"OUTLINER_DATA_LAMP", "OUTLINER_DATA_LIGHT"
"OUTLINER_OB_LAMP", "OUTLINER_OB_LIGHT"
"PLUG", "PLUGIN"
"ROTACTIVE", "PIVOT_ACTIVE"
"ROTATECENTER", "PIVOT_MEDIAN"
"ROTATECOLLECTION", "PIVOT_INDIVIDUAL"
"SCRIPTWIN", "PREFERENCES"
"SMOOTH", "SHADING_RENDERED"
"SOLID", "SHADING_SOLID"
"WIRE", "SHADING_WIRE"

"ALIGN", ??
"BBOX", ??
"BORDER_LASSO", ??
"BORDER_RECT", ??
"DOTSDOWN", ??
"DOTSUP", ??
"EDIT", ??
"GAME", ??
"GO_LEFT", ??
"INLINK", ??
"MANIPUL", ??
"MAN_ROT", ??
"MAN_SCALE", ??
"MAN_TRANS", ??
"OOPS", ??
"OPEN_RECENT", ??
"ORTHO", ??
"RADIO", ??
"RECOVER_AUTO", ??
"RENDER_REGION", ??
"ROTACTIVE", ??
"ROTATE", ??
"SAVE_AS", ??
"SAVE_COPY", ??
"SNAP_SURFACE", ??
"SPACE2", ??
"TEMPERATURE", ??
28 Likes

Placeholder post.

Placeholder post 2

Thanks very much, these are very helpful

The first 3 posts in this thread are now editable, thanks mods!

Make sure to do a search before doing any edits to avoid adding something that is already there.

2 Likes

Great idea…

  1. 2.8 API introduces new way of class registration. Instead of module registration now one has to register classes directly.
  2. The redesigned interfaces has some window’ names changed. For instance, INFO_MT_file_import has became TOPBAR_MT_file_import.
  3. bpy.context.user_preferences -> bpy.context.preferences
  4. bpy.ops.wm.addon_enable -> bpy.ops.preferences.addon_enable
  5. bpy.context.scene.objects.active = obj now became bpy.context.view_layer.objects.active = obj
  6. obj.select = True now became obj.select_set(state = True)

Thanks, didn’t have this one in the list.

Nice little list you have created, thanks for posting it!


Recently I have been updating my own legacy code while attempting to maintain support for both versions in a single file.

I have declared LEGACY_MODE as the switch that toggles between the two command sets based on the version tuple provided by bpy.app.version.

Example:

LEGACY_MODE = bpy.app.version < (2, 80, 0) #Switch based on version for Blender 2.8+ or legacy support.
...

...
o = byp.data.object[0]
if LEGACY_MODE:
    o.hide = False #unhide object using legacy commands
else:
    o.hide_viewport = 0 #unhide object using modern commands

Anyways, just felt like sharing something :slight_smile:

1 Like

I do that in a similar way too, but it is very tedious :frowning: I now maintain a huge module just for that.

This is especially a big issue with annotations inside classes. I am for now pretending that I do not get those messages.

The World Blender Meetup had a presentation dedicated to this as well. It looked interesting, but I haven’t tried this with my own add-ons. Just getting them running in 2.80 has been enough of job, maybe once the release candidate is out I might give this a try.

Thanks for the link. Useful presentation. He has a dedicated page about it.

Looks like he and I had a very similar approach! I remember theDuckCow from some years ago, back when I programmed Blender/Python as a piano playing robot. He gave compliments to the project.

Thanks for the link!

This broke a few addons, including built-in ones.

RNA: error on register when classes use invalid identifiers
https://developer.blender.org/rBb24a255ca67841ff2d6121327791e933ce8e3602

So classes without PT, MT, HT, UL , etc, on their name will fail to load the addon.

Thanks @CansecoGPC
It sucked early this morning after building Blender but it was an easy fix. :slight_smile:

Hi spydurhank, sorry i Know very little about codeing…many addons show this “doesn’t contain ‘MT’ with prefix & suffix” or PT where & how should i add this…thanks

1 Like

Hey chickpea,
I matched my bl idname with my class name.

For a panel:

Class A_PT_panel(bpy.types.Panel):
bl_idname = ‘A_PT_panel’

It’s convention to have the same name for the class and id_name ?

ok i`ll give it a try… thankyou…i really must study the code a bit so as not to feel so helpless!!