How to rotate a selected face in edit mode?

I want to be able to randomly rotate selected faces around their individual origins in edit mode. If I had say a maximum rotation of X=10 deg, Y=15 deg & Z=25 deg, how would I, (or indeed could I?), go about doing that?

I have a list of selected faces but it’s the rotation part that I am struggling to find anything on, most of the info on rotation seems to be based around objects and not faces / polys.

Constrained to X axis:

bpy.ops.transform.rotate(value=-0.371318, axis=(1, 0, 0), constraint_axis=(True, False, False), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1)

Unconstrained axes:

bpy.ops.transform.rotate(value=0.920738, axis=(-0.712349, 0.223128, -0.665412), constraint_axis=(False, False, False), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1)

Think the former would be easier to deal with, just do one axis at a time. For rand() I believe you can specify a range. There again per axis seems the way.

Edit:
On second thought if value=1 is set you can pass your rand() tuple directly to axis=(randX, randY, randZ). Think it’s in radians btw.

I ended up with this, not elegant, but it’s been a while since I did any coding. Ideally, it would be handy to have it as a proper script with input values for the angle limits but that’s not something I have got to learning python.



# Randomly Rotate Selected polygons 
# Bit of a workaround, get selected, deselect, 
# select & rotate each individually then deselect again.
# assuming the object is currently in Edit Mode.

import bpy
import bmesh
import math
import random

obj = bpy.context.edit_object
me = obj.data
bm = bmesh.from_edit_mesh(me)

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

max_xy = 15
max_z = 35

for f in selected_faces:
        f.select = False;

for f in selected_faces:
    f.select = True
    
    my_xy = random.randint(max_xy * -1,max_xy)
    my_z = random.randint(max_z * -1,max_z)
    ro_xy = math.radians(my_xy)
    ro_z = math.radians(my_z)

    bpy.ops.transform.rotate(value=ro_xy, axis=(True, False, False), proportional='DISABLED')            ## X Axis
    bpy.ops.transform.rotate(value=ro_xy, axis=(False, True, False), proportional='DISABLED')            ## Y Axis
    bpy.ops.transform.rotate(value=ro_z, axis=(False, False, True), proportional='DISABLED')            ## Z Axis        

    f.select = False

for f in selected_faces:
        f.select = True;            ## ReSelect the original polys

bmesh.update_edit_mesh(me, True)