Skip to content

feat: multi-input multi-resource type operators - #1248

Draft
michael-johnston wants to merge 38 commits into
mainfrom
maj_generalize_operators
Draft

feat: multi-input multi-resource type operators#1248
michael-johnston wants to merge 38 commits into
mainfrom
maj_generalize_operators

Conversation

@michael-johnston

@michael-johnston michael-johnston commented Jul 21, 2026

Copy link
Copy Markdown
Member

This PR introduces multi-input multi-resource type operators. It also enforces passing of operator parameters by instances of the operator parameter model (answers #647) e.g.

def operator_function(my_param_one: OperatorInputType, 
                 another_resource_param: OperatorInputType, 
                 operationInfo: FunctionOperationInfo=None, 
                 parameters:GenericOperatorParameters= GenericOperatorParameters())
  ...

Note: Here we use OperatorInputType to denote the allowed input types e.g. DiscoverySpace (see more below) and GenericOperatorParameters as a placeholder for the specific parameter model of the operator

Prior to this PR operators could only work on a single input resource, which had to be of type DiscoverySpace and named discoverySpace. Further the parameters for the operator were passed as keyword args i.e.

operator_fn(discoverySpace:DiscoverySpace, operationInfo:FunctionOperationInfo=None, **kwargs)

Operator Input Types

ADO resources that can be operated on are now associated with a "rich" type that will be passed to the operator. In the PR we have two resources that can be operated on

  • DiscoverySpaceResource -> DiscoverySpace (rich type) <- As it is now
  • DataContainerResource -> DataContainerResource (rich type) <- New resource type and associated rich type

Note: Its a particular property of DataContainerResource that it can be its own rich type.

Setting inputs in operation.yaml

The PR removes the DiscoveryOperationConfiguration spaces field and introduce the more general input field.

before

spaces:  # A list of resource ids
    - space_id_one
    - space_id_two # Note: technically you could have more than one id, but nothing could use it

now, for an operator with two DiscoverySpace input params called space_one and space_two

inputs: 
    space_one: 
          identifier: space_id_one
          kind: DiscoverySpace
    space_two:
          identifier: space_id_two
           kind: DiscoverySpace

In practice kind can be inferred when the YAML is read so users can omit it

Non-breaking changes

  • The spaces field is kept as a computed field, so any code relying on querying it in metastore does not need to be changed
  • All older operation resources are updated to have the new input field if read. Not breaking
  • All existing operators resource parameters i.e. discoverySpace: DiscoverySpace, is supported out-of-box. No change needed

Breaking changes

  • The parameters field of all operators has been updated to be an instance of the operator class not keyword args. Old operators (pre this change) cannot be used with this change. Scripts or operators calling operator functions directly also must be updated.

Code Changes

The code changes fall into three groups:

  1. Updates to allow operators to have multiple resource inputs of multiple types and for operations to store them (new input field, models for that field, validators are parsers for operator signature etc.)
  2. Updates in orchestration flow to handle multiple inputs (instead of just looking for spaces[0[), including storing relationships, and handling cases where rich type does provide access to the metastore
  3. Updates due to change to use Operators parameter class and introduction of GenerericOperatorConfiguration (changing signatures, changing plugin versions etc).

- ADOResourceReference - this is a model that refers to a resource in the metastore i.e. an id and a kind. The model is not frozen, and kind can be None, allowing kind to be deduced after model instantion.
- ADOResourcePropertyDescriptor - this is a model that says a identifier (str) has a particular type. The model is frozen, kind must be given. The use of this is to carry information about the type of an ado operator function parameter.
Prior to this change only a single DiscoverySpace could be specified as an ADOResource input to an operation.

This change allows any number of resources of any kind to be passed

DiscoveryOperationResourceConfiguration:

- New "input" field allows specifying, for named operator input parameters, the ADO resource in the metadstore that should be used to pass a value to that parameter.
- validation: the input field can (conditionally via a context) be validated against the operator i.e. check the parameters named exist, check the kind of the resource referenced matches the parameters type. Also if the kind in reference is None, this sets it with the correct kind.

OperatorMetadata:

New field required_resource_inputs for holding the operator parameters that required ADO resources, and the kind of resource. Used to do the validation above.
In preflight check for operation ids
- Defines rich types for ado resources (DataContainer and DiscoverySpace for now)
- Converts a resource reference (resource id + kind) to the rich type instance
Prior to this there was a single rule for all operators types - only 1 discovery space alloed.

The module expresses the expanded rules for resource inputs for each operator type e.g. fuse must have 2+ discovery spaces.

It also provides a function validate_resource_inputs_for_operation_type to validate if a set of resource inputs are valid for a given operation type
Previously we had strict function signature defined in a protocol. Now operators can have more general signature new validation is required

- validate_operator_call_shape: Checks the operator function has some number of resource inputs, followed by operationInfo, followed by keyword args
- validate_resource_input_types: Checks that a set of proposed inputs to an operator match what it wants
- validate_operator_registration: Combines the three checks (two above + validate_resource_inputs_for_operation_type)
Also add new collections for compare and fuse operators
Also
- pass metastore explicitly
- use GenericOptionaParameters not dict
Also use orchestrate_core interface
Also use GenericOperatorParameters
Also use GenericOperatorParameters
Previously wrappers took and passed a dump of the operators parameters. Now it takes and passes the actual object.

In addition with multiple inputs its not guaranteed the metastore can be accessed (previously was always available as only discoveryspace's could be passed). Now retrieve the context to use via FunctionOperationInfo or use active context if that isn't available. Create metastore from this.
So it can be retrieved in other places in the code. However this will not work in multi-process jobs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant