Create Circle with Inner Radius
Add new object mesh addon template



Quick little addon slapped together using text editor &gt; templates &gt; python &gt; Addon Add Object template.


Adds two circles, bridges the edge loops.
If ngon fill is chosen, splits one fill edge, dissolves the rest.


Test addon.

bl_info = {
    "name": "New 2D Ring",
    "author": "batFINGER",
    "version": (1, 0),
    "blender": (2, 80, 0),
    "location": "View3D &gt; Add &gt; Mesh &gt; New 2D Ring",
    "description": "Adds a 2D ring (circle with hole)",
    "warning": "",
    "wiki_url": "",
    "category": "Add Mesh",
}
import bpy
import bmesh

from bpy_extras.object_utils import AddObjectHelper, object_data_add


from bpy.props import (
        IntProperty,
        BoolProperty,
        FloatProperty,
)


class MESH_OT_primitive_ring_add(AddObjectHelper, bpy.types.Operator):
    """Add a 2D filled ring mesh"""
    bl_idname = "mesh.primitive_ring_add"
    bl_label = "Add 2D Filled Ring"
    bl_options = {'REGISTER', 'UNDO'}

    inner_radius: FloatProperty(
        name="Inner Radius",
        description="Inner Radius",
        min=0,
        default=1.0,
    )
    outer_radius: FloatProperty(
        name="Outer Radius",
        description="Outer Radius",
        min=0,
        default=2.0,
    )
    segments: IntProperty(
        name="Segments",
        description="Number of Segments",
        min=3,
        default=8,
    )
    ngon_fill: BoolProperty(
        name="Ngon Fill",
        description="Fill with ngon",
    )

    def draw(self, context):
        '''Generic Draw'''
        layout = self.layout
        # annnotated on this class
        for prop in self.__class__.__annotations__.keys():
            layout.prop(self, prop)
        # annotated on AddObjectHelper
        for prop in AddObjectHelper.__annotations__.keys():
            layout.prop(self, prop)

    def execute(self, context):

        me = bpy.data.meshes.new("CircleHole")

        bm = bmesh.new()
        bmesh.ops.create_circle(bm, radius=self.inner_radius, segments=self.segments)
        bmesh.ops.create_circle(bm, radius=self.outer_radius, segments=self.segments)

        ret = bmesh.ops.bridge_loops(bm, edges=bm.edges)
        if self.ngon_fill:
            edges = ret['edges']
            e = edges.pop()
            bmesh.ops.split_edges(bm, edges=[e])
            bmesh.ops.dissolve_edges(bm,
                                     edges=edges)
        bm.to_mesh(me)


        object_data_add(context, me, operator=self)

        return {'FINISHED'}


def menu_func(self, context):
    self.layout.operator(MESH_OT_primitive_ring_add.bl_idname, icon='MESH_CUBE')


def register():
    bpy.utils.register_class(MESH_OT_primitive_ring_add)

    bpy.types.VIEW3D_MT_mesh_add.append(menu_func)


def unregister():
    bpy.utils.unregister_class(MESH_OT_primitive_ring_add)
    bpy.types.VIEW3D_MT_mesh_add.remove(menu_func)


if __name__ == "__main__":
    register()

    # test call
    #bpy.ops.mesh.primitive_ring_add()


Add Cone Primitive



Though I would add that the functionality is very similar to add cone primitive, with no fill and no height (can scale totally to zero in z and apply)