Materials out of range

I’m using the Partnet data set, where each part of the object has to be loaded in separately, and I’ve been trying to randomise the colours/materials per sub object.
For instance, I might want all the parts of a drawer to be the same colour. To do this, I’ve basically needed to create callbacks of varying name and so I’ve had to use monkey patching. (If there’s a better way, please do say. This is a recipie for many bugs!).

The core of the code I’ve got is basically

def randomiseColoursMaterialsByCategory(self, materials):
    num_colour_series = len(MAPPING_LABELS) + 1;
    colour_rand_series = [];
    for i in range(num_colour_series):
        appending = [];
        for j in range(self.num_iterations):
            appending.append((random.uniform(0,255), random.uniform(0,255), random.uniform(0,255)));
        colour_rand_series.append(appending);


    keys = list(MAPPING_LABELS.keys());
    keys.append(NOT_IN_MAPPING_LABEL);
    for i in range(len(keys)):

        func_name = "randomise_item_set_colours_{0}_{1}".format(str(self.uid), str(i));

        # self.internal_func_store.append(randomise_sub_obj_colour);
        print(keys[i]);
        print(type(keys[i]));
        evaluating = (
            "def {0}():" + 
            "\n\tfurniture_items = rep.get.prims(semantics=[( FURNITURE_PART, LABEL )]);" + 
            "\n\twith furniture_items:" + 
            "\n\t\trep.randomizer.materials(materials); "
            "\n\t\trep.randomizer.color(rep.distribution.sequence(colour_rand_series[i])); " + 
            "\n\treturn furniture_items.node;" + 
            # "\nprint(\"Func name:\", func_name);" + 
            "\nrep.randomizer.register({0});" + 
            "\nself.callbacks.append( lambda : rep.randomizer.{0}() );" + 
            "\nself.internal_func_store.append({0});").format(func_name);

        # print(evaluating);

        exec(
            evaluating, 
            {"rep":rep, "self":self, "materials":materials, 
            "FURNITURE_PART":FURNITURE_PART, "LABEL": MAPPING_LABELS[keys[i]] + "_" + str(self.uid),
            "colour_rand_series":colour_rand_series, "i":i});

When running this, all the arguments go in correctly, but I then get the error

2022-11-23 10:33:15 [554,635ms] [Error] [omni.graph.core.plugin] Assertion raised in compute - list index out of range
  File "/home/matthewmunks/.local/share/ov/pkg/deps/775e081cef5fe932262e6117bb022b51/extscache/omni.replicator.core-1.4.4+lx64.r.cp37/omni/replicator/core/ogn/python/_impl/nodes/OgnSampleOmniPBR.py", line 152, in compute
    mat_params.diffuse = tuple(diffuse_samples[idx])

This happens even if I randomise the materials in a separate callback function.
However it does not happen when not using the monkey-patch solution and I just randomise all the colours and materials.


EDIT:
A closed form example would be

import omni.replicator.core as rep

import random;

num_iterations = 5;

with rep.new_layer():
    materials = rep.create.material_omnipbr(diffuse=rep.distribution.uniform((0,0,0), (1,1,1)), count=30);


    camera = rep.create.camera(
        position=(50,50,50),
        look_at=(0,0,0),
        look_at_up_axis=(0,1,0));
    render_product = rep.create.render_product(camera, (640,480));

    def create_sphere_lights(num):
        lights = rep.create.light(light_type="Sphere", temperature=rep.distribution.normal(6500,500), intensity=rep.distribution.normal(5000,1000), position=rep.distribution.uniform((0,0,0),(50,50,50)), scale=rep.distribution.uniform(50,100), count=num);
        return lights.node;
    rep.randomizer.register(create_sphere_lights);

    # Overall setup. Lots of objects of multiple different clases being created.
    cones = rep.create.cone(count=100, position=rep.distribution.uniform((-100,-100,-100),(100,100,100)), scale=rep.distribution.uniform(1,5), semantics=[("class","cone")]);
    cubes = rep.create.cone(count=100, position=rep.distribution.uniform((-100,-100,-100),(100,100,100)),scale=rep.distribution.uniform(1,5),semantics=[("class","cube")]);

    CLASSES_OF_INTEREST = ["cone", "cube"];

    callbacks = [];

    num_colour_series = len(CLASSES_OF_INTEREST);
    colour_rand_series = [];
    for i in range(num_colour_series):
        appending = [];
        for j in range(num_iterations):
            appending.append((random.uniform(0,255), random.uniform(0,255), random.uniform(0,255)));
        colour_rand_series.append(appending);

    for i in range(len(CLASSES_OF_INTEREST)):

        func_name = "randomise_item_set_colours_{0}".format(str(i));

        evaluating = (
            "def {0}():" + 
            "\n\tfurniture_items = rep.get.prims(semantics=[( \"class\", LABEL )]);" + 
            "\n\twith furniture_items:" + 
            "\n\t\trep.randomizer.materials(materials); "
            "\n\t\trep.randomizer.color(rep.distribution.sequence(colour_rand_series[i])); " + 
            "\n\treturn furniture_items.node;" + 
            # "\nprint(\"Func name:\", func_name);" + 
            "\nrep.randomizer.register({0});" + 
            "\ncallbacks.append( lambda : rep.randomizer.{0}() );").format(func_name);


        exec(
            evaluating, 
            {"rep":rep, "materials":materials, 
            "LABEL": CLASSES_OF_INTEREST[i],
            "colour_rand_series":colour_rand_series, "i":i,
            "callbacks":callbacks});
    
    with rep.trigger.on_frame(num_frames=num_iterations):
        rep.randomizer.create_sphere_lights(1);
        for callback in callbacks:
            callback();

        # rep.randomizer.move_camera();

    writer = rep.WriterRegistry.get('BasicWriter');
    
    writer.initialize(output_dir="~/_output", rgb=True, bounding_box_2d_tight=True);
    writer.attach([render_product]);

rep.orchestrator.run();