Is this a supported method for altering an existing `parametrization` class?

For an app we want to reuse the code for an existing entity (in our codebase), but want to add an extra field in the parametrization. I noticed that regular inheritance doesn’t work

# Pseudo code
from viktor.parametrization import Text
from codebase.entity_x import EntityXParametrization

# This does not work
class ExtendedParametrization(EntityXParametrization):
    extra_field = Text("Hello world")

Directly modifying the original class doesn’t seem to work either.

# Pseudo code
from viktor.parametrization import Text
from codebase.entity_x import EntityXParametrization

# This does not work
EntityXParametrization.extra_field = Text("Hello world")

After some tinkering I found out that the class variables actually do get inherited, but Viktor doesn’t recognize it correctly. I discovered that editing the __fields__ fixes that though.

# Pseudo code
from viktor.parametrization import Text
from codebase.entity_x import EntityXParametrization

EntityXParametrization.extra_field = Text("Hello world")

# This makes it work if you want to add it to the end
EntityXParametrization.__fields__ += ["extra_field"]

# This makes it work if you want to add it to the beginning
EntityXParametrization.__fields__ = (
    [field for field in EntityXParametrization.__fields__ if field.startswith("__")]
    + ["extra_field"]
    + [field for field in EntityXParametrization.__fields__ if not field.startswith("__")]
)

Is this a supported way of altering existing parametrization classes?

We see this usecase in more of our app, so it would be nice if we can actually implement it like this.

Hi,

We do not officially support directly altering the __fields__ attribute, so please be careful with it. But I must admin I admire your creativity!

We also agree that something like inheritance should be preferred, or perhaps some construction like below:

class Extended(ViktorParametrization):
    extra_field = ...
    _ = AnotherParametrization()
    another_field = ...

We still need to investigate whether this is possible.

1 Like

Another approach is by breaking the source parametrization in smaller pieces and re-use them. This has the benefit of easier composability and more explicit data keys (you don’t have to go to the source parametrization to find the correct data key)

class IntroStep(Step):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.text1 = Text("""
# 👋 Welcome to the demo app! 
""")


class ReportStep(Step):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.your_name = TextField("Please enter your name")
        self.your_score = NumberField("Give yourself a score", variant='slider', min=1, max=10, default=10)


class Parametrization(ViktorParametrization):

    intro = IntroStep("Intro", views='image_view')

    report_step = ReportStep("Report", views='create_report')
    report_step.extra_field = NumberField("This field is extra")
1 Like

That’s a nice and clean way Matthijs. It’s also a nice way to reuse Steps/Sections in other entities (although exact re-use may not be desirable from a UX design perspective).

The disadvantage of this, however, is that during the original parameterization you have to take into account the possibilities of how it could be adjusted in other apps. I was looking for a way to adjust an existing parameterization, without the existing parameterization knowing or needing to know about it.

But hopefully we can include it in new developments to be future-proof.

That would a nice solution Kevin! That ways it’s also possible to add extra fields either before of after the existing fields.

However, I do wonder if someone would not also like to have the option to insert something between the existing parameters. Maybe that’s possible now by reordering __fields__ (but haven’t tested that), but modifying that isn’t really desirable as you stated.