Skip to content

Type Annotations in Function interfaces #2524

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
effigies opened this issue Apr 2, 2018 · 2 comments
Closed

Type Annotations in Function interfaces #2524

effigies opened this issue Apr 2, 2018 · 2 comments

Comments

@effigies
Copy link
Member

effigies commented Apr 2, 2018

Python 3 has added annotations, which are accessible via the inspect.getfullargspec function or the inspect.Signature API.

Using these could permit us to add type-checking to Function interfaces whose callables have type/trait annotations for their arguments and return values, and drastically reduce boilerplate for simple interfaces.

For example, suppose we want to have a function:

def split(in_list: list, index: int) -> {'out_left': list, 'out_right': list}:
    return in_list[:index], in_list[index:]

splitter = Function(split)

This would be equivalent to the current approach:

class SplitInputSpec(BaseInterfaceSpec):
    in_list = traits.List(mandatory=True)
    index = traits.Int(mandatory=True)

class SplitOutputSpec(TraitedSpec):
    out_left = traits.List()
    out_right = traits.List()

class Split(SimpleInterface):
    input_spec = SplitInputSpec
    output_spec = SplitOutputSpec

    def _run_interface(self, runtime):
        self._results['out_left'] = self.inputs.in_list[:self.inputs.index]
        self._results['out_right'] = self.inputs.in_list[self.inputs.index:]
        return runtime

splitter = Split()

For more complicated options, annotations could be fully-fledged traits:

def split(in_list: list,
          index: traits.Either('middle', traits.Int, usedefault=True)
          ) -> {'out_left': list, 'out_right': list}:
    if index == 'half':
        index = len(in_list) // 2
    return in_list[:index], in_list[index:]

The goal wouldn't be to replace the current approach for defining interfaces (although perhaps we could make spec-writing much simpler using similar approaches), and promiscuously typed Function interfaces should still be doable, but this could narrow the gap between full interfaces and Function interfaces substantially.

Conversation started in #2520.

Related: #2081 #2083 #2220

@satra
Copy link
Member

satra commented Apr 2, 2018

just a note that full support i believe is only Py 3.6+, but i'm all for reducing boilerplate. we can even introduce an interface decorator that one simply has to attach to the function.

@interface
def split(in_list: list, index: int) -> {'out_left': list, 'out_right': list}:
    return in_list[:index], in_list[index:]

where

def interface(some_function):
    def wrapper():
        ...
        return Function(some_function, ...)
    return wrapper

@effigies
Copy link
Member Author

This is in Pydra.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants