def get_process_instance_variable(self, process_instance_id: str,
                                      variable_name: str):
        """
        Returns the variable with the given name from the process instance with
        the given process_instance_id.

        Parameters:
            - ``process_instance_id``: ID of the target process instance
            - ``variable_name``: name of the variable to read

        == Example ==
        | ${variable} | Get Process Instance Variable |
        | ...         | process_instance_id=fcab43bc-b970-11eb-be75-0242ac110002 |
        | ...         | variable_name=foo |

        See also:
        https://docs.camunda.org/manual/7.5/reference/rest/process-instance/variables/get-single-variable/
        """
        with self._shared_resources.api_client as api_client:
            api_instance: ProcessInstanceApi = openapi_client.ProcessInstanceApi(
                api_client)

            try:
                response = api_instance.get_process_instance_variable(
                    id=process_instance_id, var_name=variable_name)
            except ApiException as e:
                logger.error(f'Failed to get variable {variable_name} from '
                             f'process instance {process_instance_id}:\n{e}')
        return response
    def download_file_from_variable(self, variable_name: str) -> str:
        """
        For performance reasons, files are not retrieved automatically during `fetch workload`. If your task requires
        a file that is attached to a process instance, you need to download the file explicitly.

        Example:
            | ${variables} | *fetch workload* | _first_task_in_demo_ |
            | | *Dictionary Should Contain Key* | _${variables}_ | _my_file_ |
            | ${file} | *Download File From Variable* | ${variables}[my_file] | |
        """
        if not self.FETCH_RESPONSE:
            logger.warn(
                'Could not download file for variable. Maybe you did not fetch and lock a workitem before?'
            )
        else:
            with self._shared_resources.api_client as api_client:
                api_instance = openapi_client.ProcessInstanceApi(api_client)

                try:
                    response = api_instance.get_process_instance_variable_binary(
                        id=self.FETCH_RESPONSE.process_instance_id,
                        var_name=variable_name)
                    logger.debug(response)
                except ApiException as e:
                    raise ApiException(
                        f"Exception when calling ExternalTaskApi->get_process_instance_variable_binary: {e}\n"
                    )
                return response
    def delete_process_instance(self, process_instance_id):
        """
        USE WITH CARE: Deletes a process instance by id. All data in this process instance will be lost.
        """
        with self._shared_resources.api_client as api_client:
            api_instance = openapi_client.ProcessInstanceApi(api_client)

            try:
                api_instance.delete_process_instance(id=process_instance_id)
            except ApiException as e:
                logger.error(
                    f'Failed to delete process instance {process_instance_id}:\n{e}'
                )
                raise e
    def download_file_from_variable(self, variable_name: str) -> str:
        if not self.FETCH_RESPONSE:
            logger.warn(
                'Could not download file for variable. Maybe you did not fetch and lock a workitem before?'
            )
        else:
            with self._shared_resources.api_client as api_client:
                api_instance = openapi_client.ProcessInstanceApi(api_client)

                try:
                    response = api_instance.get_process_instance_variable_binary(
                        id=self.FETCH_RESPONSE.process_instance_id,
                        var_name=variable_name)
                    logger.debug(response)
                except ApiException as e:
                    logger.error(
                        f"Exception when calling ExternalTaskApi->get_process_instance_variable_binary: {e}\n"
                    )
                return response
    def get_activity_instance(self, **kwargs):
        """
        Returns an Activity Instance (Tree) for a given process instance.

        == Example ==
        | ${tree} | Get Activity Instance | id=fcab43bc-b970-11eb-be75-0242ac110002 |

        https://docs.camunda.org/manual/7.5/reference/rest/process-instance/get-activity-instances/
        """
        with self._shared_resources.api_client as api_client:
            api_instance: ProcessInstanceApi = openapi_client.ProcessInstanceApi(
                api_client)

            try:
                response = api_instance.get_activity_instance_tree(**kwargs)
            except ApiException as e:
                logger.error(
                    f'failed to get activity tree for process instance {kwargs}:\n{e}'
                )
        return response
    def get_all_process_instances(self, process_definition_key):
        """
        Returns a list of process instances that are active for a certain process definition identified by key.
        """
        with self._shared_resources.api_client as api_client:
            api_instance: ProcessInstanceApi = openapi_client.ProcessInstanceApi(
                api_client)

            try:
                response: List[
                    ProcessInstanceDto] = api_instance.get_process_instances(
                        process_definition_key=process_definition_key,
                        active='true')
            except ApiException as e:
                logger.error(
                    f'Failed to get process instances of process {process_definition_key}:\n{e}'
                )
                raise e

        return [process_instance.to_dict() for process_instance in response]
    def get_process_instance_variable(self,
                                      process_instance_id: str,
                                      variable_name: str,
                                      auto_type_conversion: bool = True):
        """
        Returns the variable with the given name from the process instance with
        the given process_instance_id.

        Parameters:
            - ``process_instance_id``: ID of the target process instance
            - ``variable_name``: name of the variable to read
            - ``auto_type_conversion``: Converts JSON structures automatically in to python data structures. Default: True. When False, values are not retrieved for JSON variables, but metadata is. Only useful when you want to verify that Camunda holds certain data types.%

        == Example ==
        | ${variable} | Get Process Instance Variable |
        | ...         | process_instance_id=fcab43bc-b970-11eb-be75-0242ac110002 |
        | ...         | variable_name=foo |

        See also:
        https://docs.camunda.org/manual/latest/reference/rest/process-instance/variables/get-single-variable/
        """
        with self._shared_resources.api_client as api_client:
            api_instance: ProcessInstanceApi = openapi_client.ProcessInstanceApi(
                api_client)

            try:
                response = api_instance.get_process_instance_variable(
                    id=process_instance_id,
                    var_name=variable_name,
                    deserialize_value=not auto_type_conversion)
            except ApiException as e:
                raise ApiException(
                    f'Failed to get variable {variable_name} from '
                    f'process instance {process_instance_id}:\n{e}')
        if auto_type_conversion:
            return CamundaResources.convert_variable_dto(response)
        return response
    def get_process_instances(self, **kwargs):
        """
        Queries Camunda for process instances that match certain criteria.

        *Be aware, that boolean value must be strings either 'true' or 'false'*

        == Arguments ==
        | async_req | execute request asynchronously | 
        | sort_by | Sort the results lexicographically by a given criterion. Must be used in conjunction with the sortOrder parameter. | 
        | sort_order | Sort the results in a given order. Values may be asc for ascending order or desc for descending order. Must be used in conjunction with the sortBy parameter. | 
        | first_result | Pagination of results. Specifies the index of the first result to return. | 
        | max_results | Pagination of results. Specifies the maximum number of results to return. Will return less results if there are no more results left. | 
        | process_instance_ids | Filter by a comma-separated list of process instance ids. | 
        | business_key | Filter by process instance business key. | 
        | business_key_like | Filter by process instance business key that the parameter is a substring of. | 
        | case_instance_id | Filter by case instance id. | 
        | process_definition_id | Filter by the deployment the id belongs to. | 
        | process_definition_key | Filter by the key of the process definition the instances run on. | 
        | process_definition_key_in | Filter by a comma-separated list of process definition keys. A process instance must have one of the given process definition keys. | 
        | process_definition_key_not_in | Exclude instances by a comma-separated list of process definition keys. A process instance must not have one of the given process definition keys. | 
        | deployment_id | Filter by the deployment the id belongs to. | 
        | super_process_instance | Restrict query to all process instances that are sub process instances of the given process instance. Takes a process instance id. | 
        | sub_process_instance | Restrict query to all process instances that have the given process instance as a sub process instance. Takes a process instance id. | 
        | super_case_instance | Restrict query to all process instances that are sub process instances of the given case instance. Takes a case instance id. | 
        | sub_case_instance | Restrict query to all process instances that have the given case instance as a sub case instance. Takes a case instance id. | 
        | active | Only include active process instances. Value may only be true, as false is the default behavior. | 
        | suspended | Only include suspended process instances. Value may only be true, as false is the default behavior. | 
        | with_incident | Filter by presence of incidents. Selects only process instances that have an incident. | 
        | incident_id | Filter by the incident id. | 
        | incident_type | Filter by the incident type. See the [User Guide](https://docs.camunda.org/manual/latest/user-guide/process-engine/incidents/#incident-types) for a list of incident types. | 
        | incident_message | Filter by the incident message. Exact match. | 
        | incident_message_like | Filter by the incident message that the parameter is a substring of. | 
        | tenant_id_in | Filter by a comma-separated list of tenant ids. A process instance must have one of the given tenant ids. | 
        | without_tenant_id | Only include process instances which belong to no tenant. | 
        | process_definition_without_tenant_id | Only include process instances which process definition has no tenant id. | 
        | activity_id_in | Filter by a comma-separated list of activity ids. A process instance must currently wait in a leaf activity with one of the given activity ids. | 
        | root_process_instances | Restrict the query to all process instances that are top level process instances. | 
        | leaf_process_instances | Restrict the query to all process instances that are leaf instances. (i.e. don't have any sub instances). | 
        | variables | Only include process instances that have variables with certain values. Variable filtering expressions are comma-separated and are structured as follows:  A valid parameter value has the form `key_operator_value`. `key` is the variable name, `operator` is the comparison operator to be used and `value` the variable value.  **Note**: Values are always treated as String objects on server side.  Valid `operator` values are: `eq` - equal to; `neq` - not equal to; `gt` - greater than; `gteq` - greater than or equal to; `lt` - lower than; `lteq` - lower than or equal to; `like`. `key` and `value` may not contain underscore or comma characters. | 
        | variable_names_ignore_case | Match all variable names in this query case-insensitively. If set to true variableName and variablename are treated as equal. | 
        | variable_values_ignore_case | Match all variable values in this query case-insensitively. If set to true variableValue and variablevalue are treated as equal. | 
        | _preload_content | if False, the urllib3.HTTPResponse object will
                                 be returned without reading/decoding response
                                 data. Default is True. | 
        | _request_timeout | timeout setting for this request. If one
                                 number provided, it will be total request
                                 timeout. It can also be a pair (tuple) of
                                 (connection, read) timeouts. | 
        """
        with self._shared_resources.api_client as api_client:
            api_instance: ProcessInstanceApi = openapi_client.ProcessInstanceApi(
                api_client)

            try:
                response: List[
                    ProcessInstanceDto] = api_instance.get_process_instances(
                        **kwargs)
            except ApiException as e:
                raise ApiException(
                    f'Failed to get process instances of process:\n{e}')

        return [process_instance.to_dict() for process_instance in response]