Computation job could not be created (details: This request is not allowed from apps.)

I am trying to use the ‘compute’ method from a child entity, but it raises an error. This is my code:

        api = vkt.api_v1.API()
        children = api.get_entity_children(entity_id, include_params=True)
        for child in children:
            result = child.compute(
                "my_method", params=child.last_saved_params
            )

and this is the error:

  File "viktor\\api_v1.pyx", line 655, in viktor.api_v1.Entity.compute
  File "viktor\\api_v1.pyx", line 1319, in viktor.api_v1._API.entity_compute
  File "viktor\\api_v1.pyx", line 1855, in viktor.api_v1._API._create_entity_job
viktor.errors.ComputeError: Computation job could not be created (details: This request is not allowed from apps.)

Have I misunderstood the purpose of the method or what is going on here?

Hi!

Cool to see you trying to use this more advanced way of running computations!

It’s a bit difficult to say more about this without seeing more code so let’s start with: what type of method is my_method? Currently only view and button methods are callable over the api. Meaning: only methods that generate a view (e.g. a tableview) or methods connected to a button (e.g. a method connected to a downloadbutton) are callable).

I checked with backend engineer and the error message explains it:

This request is not allowed from apps.

Currently you cannot call the compute endpoint from an app. This limitation has been implemented to prevent recursion and buildup of app jobs. Furthermore, a flow like this will not work in your development workspace because there is only a single python process that can accept jobs (and that one is waiting for the result).

We can imagine this is something that we can change btw, since there are valuable usecases that this would unlock. Could you contribute by sharing what you want to achieve?

Some extra background: when you use the API class without explicit token, you use the app-job token which is generated by the platform when the user triggers a job. This token is limited to not be able to use the compute endpoint. Personal access tokens on the other hand are capable of using the compute endpoint, which is why you could trigger an app job from an external script.

Oh I completely missed that part of the error, but indeed, as Matthijs points out you can’t call the compute over api from within an app.

Not sure what you are trying to build, but i can imagine it’s something like having a parent and a child entity, and that you want to perform a batch calculation of all the child entities, correct?

If so, that is possible to do from within an app, and you don’ t even need the compute-over-API.

Say you have a child entity with a calculation of some sort, e.g.:

class Controller(vkt.Controller):
    label = 'My Entity Type'
    parametrization = Parametrization

    @vkt.TableView("Student Grades")
    def table_view(self, params, **kwargs):
        data = [
            ["John", 6.9],
            ["Jane", 8.1],
            ["Mike", 7.5],
        ]

        return vkt.TableResult(data, column_headers=[
            "Name",
            vkt.TableHeader("Grade", num_decimals=0)
        ])

You could write a method on your parent entity to loop over all children and call that tablemethod. In this example I dump those results into a file but of course you can use the results any way you want. In the parent entity you can do this by importing the childentity controller, and then calling in a loop over all children like this:

import viktor as vkt
from ..my_entity_type.controller import Controller as ChildEntityType


class Parametrization(vkt.Parametrization):
    btn = vkt.DownloadButton('Click to download child table results', method='download_child_results')


class Controller(vkt.Controller):
    label = 'My Folder'
    children = ['MyEntityType']
    show_children_as = 'Table'
    parametrization = Parametrization

    def download_child_results(self, params, entity_id, **kwargs):
        api = vkt.api_v1.API()
        entity = api.get_entity(entity_id)

        zipped_file_dict = {}

        for child in entity.children():
            table_result = ChildEntityType().table_view(ChildEntityType(), params=child.last_saved_params)

            # Extract data from child result and store it in a file in the dict
            zipped_file_dict[f'{child.name}.txt'] = vkt.File.from_data(str(table_result.data))
            
        return vkt.DownloadResult(zipped_files=zipped_file_dict, file_name="all_child_tables.zip")

It looks a bit different, but we import ChildEntityType, and then call it in the loop by creating it and accessing the table_view which takes self (hence we give ChildEntityType() as the first argument) and then the params.

Hope that helps!

1 Like

Thank you for your answers. That is exactly what I want to do Roeland. However, the children is not the same entity type, but they alle have a method with the same name.

I refactored my code to make it work without the api :slight_smile:

1 Like