Python API script, why does extruding verts behave in this way?
Use bmesh operators.

Here is an edit mode script that finds any face in the mesh that has an upward facing normal (locally) and extrudes.

Notice there is no element selection (e.select = True) required, it's done purely on face normal.  When  using bpy.ops operators in edit mode need to keep in mind, and set, select mode  (the issue above suggests vertex. Toggling modes flushes the selection, selecting the edges and face implied by your vert selection.  ie Even though you have all verts of a face selected, the face isn't yet.)

&gt;&gt;&gt; C.tool_settings.mesh_select_mode[:]
(False, False, True) #  vertex, edge, face


Recommend ditching edit mode bpy.ops whenever possible.

import bpy
import bmesh


ext = (0, 0, 2)
TOL = 1e-7

context = bpy.context
ob = context.object
me = ob.data
bm = bmesh.from_edit_mesh(me)
#  bm.normal_update()

# select the top face

faces = [f for f in bm.faces if f.normal.angle((0, 0, 1)) &lt; TOL]

if faces:  # 
    ret = bmesh.ops.extrude_discrete_faces(bm,
            faces=faces,
            )
    verts = list(set(v for f in ret['faces']
            for v in f.verts))

    bmesh.ops.translate(bm,
            verts = verts,
            vec = ext,
        )

    bmesh.update_edit_mesh(me)


I've used bmesh.ops.extrude_faces_discrete(...) however could also use

if faces:
    ret = bmesh.ops.extrude_face_region(bm,
            geom=faces,
            )
    verts = list(set(e for e in ret['geom']
            if isinstance(e, bmesh.types.BMVert)))

    bmesh.ops.translate(bm,
            verts = verts,
            vec = ext,
        )
    bmesh.ops.delete(bm,
            geom=faces,
            context='FACES')

    bmesh.update_edit_mesh(me)


when using edit mode bmesh, can often use the users selection

[f for f in bm.faces if f.select]


or 

f = bm.select_history.active 


and check that is of type bmesh.types.BMFace.