How can I automate/make flexible the generation of parametrization fields?

Hello,

(VIKTOR connector v5.22.2 / VIKTOR SDK v14.3.0 / Python version 3.11))

I am working on parametrization with several comparable fields. They differ only by a simple pattern (e.g. a counter). Instead of writing them all by hand and having to update them that way, I would like to know how to automate this.

The fields look like this (example):

    configurator.Archetypes.complex_typeKeuze_x001 = OptionField("Archetype 001", name="P_ATconfig_Keuze_x001", options=COMPLEX_OPTIONS, default=COMPLEX_OPTIONS[(1)-1])
    configurator.Archetypes.complex_typeKeuze_x001_aantal = NumberField("Aantal", name="P_ATconfig_Keuze_x001_aantal", default=1, num_decimals=0, step=1, min=0)
    configurator.Archetypes.lb00001 = LineBreak()

I’ve tried building a loop that contains an ‘eval()’ command that runs over a counter ‘nn’ for instance such that all the relevant values (and Fieldname) change accordingly. It is my hope that this loop can substitute all the individual declarations of the fields and is more flexible in terms of total amount of fields etc.

    for nn in range(1,16):
     eval('configurator.Archetypes.complex_typeKeuze_x' + str(nn).zfill(3) + ' = OptionField("Archetype '+ str(nn).zfill(3) + '"), name="P_ATconfig_Keuze_x'+ str(nn).zfill(3) +'", options=COMPLEX_OPTIONS, default=COMPLEX_OPTIONS[('+ str(nn) +') - 1]')
     eval('configurator.Archetypes.complex_typeKeuze_x' + str(nn).zfill(3) + '_aantal = NumberField("Aantal", name="P_ATconfig_Keuze_x' + str(nn).zfill(3) + '"_aantal", default=' + str(default_nn) + ', num_decimals=0, step=1, min=0)')
     eval('configurator.Archetypes.lb' + str(nn).zfill(5) + ' = LineBreak()')

However, this does not seem to be allowed: I get the error ‘invalid syntax’ pointing at the ‘=’ declaration, e.g. in the last line:

eval('configurator.Archetypes.lb' + str(nn).zfill(5) + ' = LineBreak()')

Is this a correct approach in which I made a simple mistake, or is this not allowed at all? My main question is: “How can I automate/make flexible the generation of parametrization fields?

Cheers!
Boudewijn.

Hi Boudewijn,

you can use setattr() for this. I would also recommend to not use eval in your code, it is risky from a security point of view.

Happy coding,
Wichard

2 Likes

To make it a bit easier here is an example code snippet:

for _index in range(1,16):
    setattr(
       configurator.Archetypes, # the object to add the attribute to
       f"complex_typeKeuze{_index:03}", # the name of the attribute
       OptionField(f"Archetype {_index:03}", name=f"P_ATconfig_Keuze_x{_index:03}", options=COMPLEX_OPTIONS, default=COMPLEX_OPTIONS[(1)-1])) # the value
2 Likes

Thanks for the example. However it seems that I cannot execute a for-loop within the Designparametrization class? I keep getting the error

'int' object has no attribute '_generate_entity_type'

Even if I try an empty for-loop like:

for index in range(10):
print("\n"+str(index))

It will prompt 0,1,2,…9 and then the error.
But when I try a loop outside the class, it cannot relate to the objects as in this example configurator.Archetypes.

Am I missing something here?

Cheers!

You can fix that by prefixing the loop variable with an underscore. E.g. ‘_index’. I will edit the example.

Cheers

thanks! I suppose that the index needs to be replaced by _index everywhere and now it works!

Dear Wichard,

I have a follow-up question: how can i build Tabs with setatrr()? in other words what should I pass as first argument x in setattr(x,'y',v) in that case?

Never tried it. But in essence you are creating class attributes. You could try to use the class name so: setattr(DesignParametrization, 'y', v). But i would expect an issue that DesignParametrization is not defined, which is as expected. So I’m affraid that won’t work.

I’ve been pondering this a bit more, purely because I enjoy a good challenge. There is indeed a way to accomplish this. I must admit, though, I’m not entirely certain whether you should desire it. But if you truly wish to proceed, here’s the method:

class DesignParametrization(Parametrization):
    for _index in range(10):
        vars()[f"option_{_index}"] = Tab(f"Tab {_index}")
        vars()[f"option_{_index}"].number = NumberField(f"Number {_index}")

Thanks. I think the generation of tabs is indeed a step too far. I don’t want to make the parametrization any more complex than it already is.
The generation with setattr() works very well.
I have a number of fields and they generate a nice and interactive tool.
However after a few minutes of working with my tool, VIKTOR is not responding. In the cmd I get the WARNING StopJob sent, while there is no job. I cannot find where this happens and what the solution might be. How should I address this?

Cheers,
Boudewijn.