Skip to main content
Version: 12

Upgrades

This document lists all current deprecations, with upgrade steps and planned removal. When the deprecation is removed with a major update, it will be moved under its corresponding header.

This version

U75 - Remove name and filename from params

  • deprecated since: v12.12.0
  • planned removal: v13
  • automated code fix available: partly

Current behaviour + reason for change

Up to now you might have noticed a name property that was always present in the params of an entity, even though you had not specified a field referring to that position in the database. The entity name has been added to the signature of each controller method or can be obtained by using the API (e.g. Entity.name), which makes the name property redundant and will be removed. In case of file-upload entities, a filename property can be observed which will also be removed.

Furthermore, the name and filename keys will become reserved for internal use and can no longer be used as name argument in parametrization fields.

In order to simulate the removal of these params, you can use the viktor_name_filename_in_params controller flag:

class Controller(ViktorController):
viktor_name_filename_in_params = False

This upgrade affects the following parts:

  • Parametrization + params
  • Entity mutations
    • Entity.create_child() / API.create_child_entity()
    • Entity.set_params() / API.set_entity_params()

New behaviour

Both name and filename will no longer be present in the params, and cannot be used as name argument of parametrization fields.

Conversion

Add a viktor_name_filename_in_params class attribute on the Controller and set it to False. This can be done automatically by using the CLI command viktor-cli fix -u 75:

class Controller(ViktorController):
+ viktor_name_filename_in_params = False
caution

Unfortunately we cannot automatically fix your app logic. The following sections will guide you through the manual conversion of the affected code.

Parametrization + params

There are two ways for a field to be positioned on the name (or filename) key in the database:

  1. using name as toplevel field name
- name = NumberField(...)
  1. using name="name" as field input argument
- tab.field = NumberField(..., name='name')

Also make sure to update all parts of the code where name (or filename) is obtained from the params. Instead, the entity name can be obtained from the signature:

- def func(params, **kwargs):
+ def func(params, entity_name, **kwargs):
- entity_name = params.name
...

This also holds in case the property is taken from the last_saved_params of a different entity:

- entity_name = entity.last_saved_params['name'] 
+ entity_name = entity.name
Entity mutations

In functions that involve entity mutation, the name of the entity could have been stored in the params. This should be added as explicit name argument:

  entity_name = "my_entity"
- params = {"name": entity_name, ...}
+ params = {...}
entity.create_child(..., name=entity_name, params=params)

U74 - Store table OptionField value in params

  • deprecated since: v12.12.0
  • planned removal: v13
  • automated code fix available: partly

Current behaviour + reason for change

When an OptionField is used within a table, it is not possible to show the label of the options in the dropdown menu, while using the value of the selected option in the params. This functionality will become available in the future, creating consistency between regular option fields and option fields used within tables.

New behaviour

By setting the controller flag viktor_store_table_option_field_value to True, the label of options will be shown in the interface, and the value of the selected option will be returned in the params. This flag will be True by default in the future.

Conversion

Add a viktor_store_table_option_field_value class attribute on the Controller. This can be done automatically by using the CLI command viktor-cli fix -u 74:

class MyController(ViktorController):
+ viktor_store_table_option_field_value = True
caution

Unfortunately we cannot automatically fix your app logic in case your app already defines both a value and label in options within a table dropdown (i.e. you ignored the warning). In that case you should update your code manually:

class MyParametrization(Parametrization):
...
table.option = OptionField(..., options=[OptionListElement('a', 'Option A'), OptionListElement('b', 'Option B')])


class MyController(ViktorController):
...
+ viktor_store_table_option_field_value = True

def func(params):
- if params.table.option == 'Option A':
+ if params.table.option == 'a':
...

U73 - GeometryResult visualization_group parameter renamed to geometry

  • deprecated since: v12.12.0
  • planned removal: v13
  • automated code fix available: yes

Current behaviour + reason for change

GeometryResult and GeometryAndDataResult accept the geometry to be visualized through a visualization_group parameter. Since not only a Group but all sorts of geometry (any (list of) TransformableObject(s) or GLB file) can be passed, the naming of this parameter is outdated.

New behaviour

GeometryResult visualization_group parameter has been renamed to geometry.

Conversion

The following conversion has to be performed, which can be done automatically by using the CLI command viktor-cli fix -u 73:

- GeometryResult(visualization_group=...)
- GeometryAndDataResult(visualization_group=...)
+ GeometryResult(geometry=...)
+ GeometryAndDataResult(geometry=...)

U72 - Remove viktor.api module

  • deprecated since: v12.11.0
  • planned removal: v13
  • automated code fix available: no

Current behaviour + reason for change

The viktor.api module consists of (outdated) functions and classes that are superseded by the entity option fields and functions from the viktor.api_v1 module, or provide insignificant value such that it's better to replace them with simple app code.

New behaviour

All (useful) functionalities from the viktor.api module can be mimicked by using the entity option fields and/or functions from the viktor.api_v1 module. The viktor.api module will be removed completely in the future.

Conversion

get_database_value_from_entity_id / get_entity_id_from_database_value / get_entity_option_list_for_designer

If the entities are all children/siblings, the OptionField can be replaced with a Child/SiblingEntityOptionField (or similar for its multi-select counterpart):

- options = get_entity_option_list_for_designer(entities)
- field = OptionField("...", options=options)
+ field = ChildEntityOptionField("...") # or similar field
...
- entity_id = get_entity_id_from_database_value(params['field'])
+ entity = params['field'] # obtain its id with entity.id if desired

API, Entity & EntityType

The classes API, Entity and EntityType and all of its (useful) functionalities from the viktor.api module have a counterpart with equal or similar functionalities in the viktor.api_v1 module. Below are the main differences:

- from viktor.api import API
+ from viktor.api_v1 import API
...
api = API()
...
- API.verify_status_code(response, allowed=200) # check the response.status_code yourself
+ if response.status_code != 200:
+ ... # handle not allowed status code(s)
- entity = API().entity(entity_id)  # from viktor.api
+ entity = API().get_entity(entity_id) # from viktor.api_v1
...
- entity_dict = entity.get()
+ entity_params = entity.last_saved_params # or any other attribute
...
- root_entities = entity.root_entities() # or entity.list()
+ root_entities = API().get_root_entities()
...
- parent_entity_dict = entity.parents()[0]
- parent_id = entity_parent_ids()[0]
+ parent_entity = entity.parent()
...
- entity.create_child(entity_dict)
+ entity.create_child(entity_type_name, name, params=params)
...
- entity.post_properties(new_params)
+ entity.set_params(new_params)
...
- entity.update_properties(new_params_subset)
+ params = entity.last_saved_params
+ params.update(new_params_subset)
+ entity.set_params(params)
...
- file_content = entity.download()
+ file = entity.get_file() # file.getvalue_binary() to obtain the binary content
- entity_type = API().entity_type(entity_type_id)
- entity_type.entities()
+ API().get_entities_by_type(entity_type_name)

Apps already using (unsupported!) code to create a file-type child entity using the viktor.api module can make use of the function generate_upload_url to fully switch to the viktor.api_v1 module. This method should not be introduced in an app other than for above-mentioned reason:

- result = requests.post(f".../entity_types/{entity_type_id}/upload/", headers=...).json()
+ result = API().generate_upload_url(entity_type_name)
- entity_properties = {"name": entity_name, "filename": result['fields']['key']}
- entity.create_child({"properties": entity_properties, "entity_type": entity_type_id})
+ entity.create_child(entity_type_name, name=entity_name, filename=result['fields']['key'], params={})
requests.post(result['url'], data=result['fields'], files={'file': ...})
caution

An unused import of the viktor.api module does not trigger any deprecation warning, but will crash the app when the module is deleted in v13. Be sure to remove all such imports.

U71 - Remove manifest key background_image

  • deprecated since: v12.11.0
  • automated code fix available: yes

Current behaviour + reason for change

The background image of a single app was customizable using the manifest metadata key background_image. This custom background image is frozen since the migration of workspaces to a single organization environment, and can now be changed through the administrator panel per workspace.

New behaviour

The background image can be customized per workspace through the administrator panel. This makes the background_image manifest key redundant.

Conversion

Remove the background_image metadata key from the manifest, which can be done automatically by using the CLI command viktor-cli fix -u 71:

  metadata:
welcome_text: file_path.txt
- background_image: file_path.jpg
- metadata:
- background_image: file_path.jpg

U70 - Removed Polyline.from_dict()

  • deprecated since: v12.10.0
  • planned removal: v13
  • automated code fix available: no

Current behaviour + reason for change

A Polyline can be instantiated using the class method from_dict, however this should not be part of the public api.

New behaviour

The class method will be removed.

Conversion

  polyline_points = [...]  # list of dictionaries
- polyline = Polyline.from_dict(polyline_points)
+ polyline = Polyline([Point(p['x'], p['y']) for p in polyline_points])

U69 - Autoselect single option in OptionField

  • deprecated since: v12.10.0
  • planned removal: v13
  • automated code fix available: yes

Current behaviour + reason for change

The list of available options in an OptionField may consist of a single entry. This can either be achieved by providing a static list of options, or when the options are created dynamically. In the latter case, a single option will automatically be selected in the interface (without user interaction). However, this could lead to unintended behavior. In the following example, the selected option is automatically changed without the user being aware of it:

ActionOptions
enter the editor⚪ A, ⚪ B, ⚪ C
options dynamically change to single option A⚫ A
options dynamically change to multiple options⚫ A, ⚪ B, ⚪ C
options dynamically change to single option B (user might not be aware!)⚫ B
options dynamically change to multiple options, excluding the selected option⚪ A, ❌ B, ⚪ C (warning in interface)

New behaviour

In the future, the new default will be to not automatically select a single option within an OptionField. The autoselect_single_option flag has been added to explicitly set the behaviour of selecting a single option to True or False.

options = OptionField("Options", options=dynamic_options, autoselect_single_option=False)

In case you want to keep the current behavior, this flag can be set to True.

Conversion

The following conversion has to be performed, which can be done automatically by using the CLI command viktor-cli fix -u 69:

- options = OptionField("Options", options=dynamic_options)
+ options = OptionField("Options", options=dynamic_options, autoselect_single_option=True)

U68 - Remove require_all_fields on buttons

  • deprecated since: v12.9.0
  • planned removal: v13
  • automated code fix available: yes

Current behaviour + reason for change

The argument require_all_fields can be specified on an action button, however it is not implemented in the platform. This argument could cause confusion and makes the SDK reference less readable.

New behaviour

The require_all_fields argument will be removed. The following fields are affected:

  • DownloadButton
  • SetParamsButton
  • ActionButton (AnalyseButton)
  • OptimizationButton (OptimiseButton)

Conversion

The following conversion has to be performed, which can be done automatically by using the CLI command viktor-cli fix -u 68:

- download_button = DownloadButton("Download X", method="download_x", require_all_fields=True)
+ download_button = DownloadButton("Download X", method="download_x")

U67 - GEOLIB hosting by VIKTOR will be terminated

  • deprecated since: v12.9.0
  • automated code fix available: yes

Current behaviour + reason for change

Deltares' GEOLIB is currently hosted by VIKTOR to make it available for its clients. The GEOLIB (>= 0.1.6) has now become publicly available on pypi, removing the need to host it ourselves.

New behaviour

The GEOLIB can be installed directly from pypi by pointing to the correct package in the app's requirements.txt.

Conversion

In case you are not using the GEOLIB in your app, no action is required. Otherwise, update requirements.txt which can be done automatically by using the CLI command viktor-cli fix -u 67:

  # viktor==X.X.X
- geolib==0.1.6
+ d-geolib==0.1.6
...
caution

GEOLIB is available on pypi from version >= 0.1.6. With the termination of the hosting by VIKTOR, older versions will become unavailable. If your app uses a version older than 0.1.6, please update your code accordingly.

U66 - NumberField.Variant replaced with str-type

  • deprecated since: v12.8.0
  • planned removal: v13
  • automated code fix available: yes

Current behaviour + reason for change

The variant of a NumberField is currently set with NumberField.Variant, which is of type Enum. To make the product easier to understand and use, also for starting programmers, this is updated to a simple str-type.

New behaviour

The variant of a NumberField can be set with a simple str-type ('slider', 'standard').

Conversion

The following conversion has to be performed, which can be done automatically by using the CLI command viktor-cli fix -u 66:

- NumberField("MyField", min=10, max=20, variant=NumberField.Variant.SLIDER)
+ NumberField("MyField", min=10, max=20, variant='slider')
- NumberField("MyField", variant=NumberField.Variant.STANDARD)
+ NumberField("MyField", variant='standard') # or just NumberField("MyField")

U65 - Entity selection fields return Entity object

  • deprecated since: v12.8.0
  • planned removal: v13
  • automated code fix available: partly

Current behaviour + reason for change

The value of the entity selection fields as returned in the params is of type integer. Returning objects in the params will become the standard behavior. This allows for already existing fields, such as the entity selection fields, to return more logical types.

New behaviour

Returned values in the params will be strictly of type Entity in the future. By defining viktor_convert_entity_field = True on a controller, this behavior can be simulated.

The following fields are affected:

  • ChildEntityOptionField
  • SiblingEntityOptionField
  • ChildEntityMultiSelectField
  • SiblingEntityMultiSelectField

Note that if viktor_convert_entity_field is defined, not only the params of the current controller are converted, but also the params obtained from API calls. In the example below, the params of an entity of EntityTypeA are converted when retrieved in an entity of EntityTypeB.

class ControllerA(ViktorController)  # EntityTypeA

viktor_convert_entity_field = False
...

def func(self, params, **kwargs):
entity = params['child_entity_option_field'] # of type int!


class ControllerB(ViktorController) # EntityTypeB

viktor_convert_entity_field = True
...

def func(self, params, **kwargs):
params_entity_a = ... # API call to retrieve params of EntityTypeA
entity = params_entity_a['child_entity_option_field'] # of type Entity!

Conversion

Add a viktor_convert_entity_field class attribute on the Controller. This can be done automatically by using the CLI command viktor-cli fix -u 65:

class MyController(ViktorController):

+ viktor_convert_entity_field = True
caution

Unfortunately we cannot automatically fix your app logic. Please update the affected code manually, for example:

entity = params.tab.section.child_entity
- entity = API().get_entity(entity)

An Entity is not serializable meaning that it cannot be used as input of a memoized function. In case you are passing the complete params as input, a conversion is required:

- memoized_func(params=params)
+ params_ = copy.deepcopy(params)
+ del params_['tab']['section']['child_entity']
+ memoized_func(params=params_)

U64 - Replace PrivilegedAPI by explicit privileged flag

  • deprecated since: v12.6.0
  • planned removal: v13
  • automated code fix available: no

Current behaviour + reason for change

Privileged API calls are done by using the PrivilegedAPI class. A danger of this approach is that the object may be instantiated well in advance of the actual API call, such that it is no longer transparent whether that call is privileged or not. Furthermore, PrivilegedAPI and the default API could be mixed within a method which can also result in unwanted privileged calls.

New behaviour

The PrivilegedAPI class will be removed and privileged API calls should be done by adding an explicit privileged flag in the corresponding method (e.g. entity.children(privileged=True)). The following methods are affected:

  • API.get_entity()
  • API.get_entity_file()
  • API.get_root_entities()
  • Entity.parent()
  • Entity.children()
  • Entity.siblings()
caution

If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using the privileged flag:

  • Make sure the app's admin is aware that the code circumvents certain permissions at specific places.
  • Make sure to test the implementation thoroughly, to ensure no confidential data is leaked.

Conversion

- api = PrivilegedAPI()
- privileged_root_entities = api.get_root_entities()
+ api = API()
+ privileged_root_entities = api.get_root_entities(privileged=True)

U63 - Remove prefix and suffix on DateField

  • deprecated since: v12.5.0
  • planned removal: v13
  • automated code fix available: no

Current behaviour + reason for change

A prefix and / or suffix can be defined on a DateField, which is not relevant for this type of field. The attributes will therefore be removed.

New behaviour

It will not be possible to use prefix and suffix on a DateField.

Conversion

- DateField('Some date', suffix='XYZ')
+ DateField('Some date (XYZ)')

U62 - Renamed threejs_visualisation() to visualize_geometry()

  • deprecated since: v12.5.0
  • planned removal: v13
  • automated code fix available: yes

Current behaviour + reason for change

A SoilLayout2D or SoilLayer2D can be visualized by calling threejs_visualisation() on the corresponding object. The "threejs" part in this name is no longer relevant and might be unclear to the developer.

New behaviour

Both methods return the geometric representation of the object, which can be used in a GeometryView. Therefore the methods are renamed to visualize_geometry():

  • SoilLayout2D.threejs_visualisation() -> SoilLayout2D.visualize_geometry()
  • SoilLayer2D.threejs_visualisation() -> SoilLayer2D.visualize_geometry()

Conversion

The following conversion has to be performed, which can be done automatically by using the CLI command viktor-cli fix -u 62:

  layout = SoilLayout2D(...)
- geometry, labels = layout.threejs_visualisation(...)
+ geometry, labels = layout.visualize_geometry(...)

U61 - Move entity-type information from manifest to Controller

  • deprecated since: v12.3.0
  • planned removal: v13
  • automated code fix available: yes

Current behaviour + reason for change

The entity-type information is currently partly described in the corresponding Controller (parametrization / views / summary), but some data is defined in the manifest.yml (label, children, show_children_as). This manifest is a concept which is often hard to grasp for a starting developer. In order to improve the onboarding of new developers, as well as consistency of where to define entity-type information, we would like to get rid of the manifest completely.

The first step is to move the definition of the following keys to the corresponding controller:

  • label (required)
  • children (if present)
  • show_children_as (if present)

New behaviour

The keys will become simple class attributes, similar as parametrization and summary:

class EntityTypeController(ViktorController):
label = 'Label of the entity-type'
children = ['SomeType', 'AnotherType']
show_children_as = 'Cards' # or 'Table'

If they are still present in the manifest, you may expect the following warning:

Entity.label is present in manifest.yml but is overwritten by the app logic. Remove entry from manifest.

Note, when you are defining label on the Controller, the SDK will also try to get children + show_children_as or use the default of "no children" if not found. Therefore you cannot define label on the Controller, while keeping children and show_children_as in the manifest!

Conversion

The following conversion has to be performed, which can be done automatically by using the CLI command viktor-cli fix -u 61:

# manifest.yml
version: '1'
entity_types:
EntityTypeA:
- label: This is A
- show_children_as: Cards
- children:
- - EntityTypeB
...
EntityTypeB:
- label: This is B
...
# entity_type_a/controller.py
class EntityTypeAController(ViktorController):
+ label = 'This is A'
+ children = ['EntityTypeB']
+ show_children_as = 'Cards'

...

# entity_type_b/controller.py
class EntityTypeBController(ViktorController):
+ label = 'This is B'

...