Skip to content
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

refactor(api): Make sure command implementations return something compatible with the command's result type #15051

Merged
merged 3 commits into from
Apr 30, 2024

Conversation

SyntaxColoring
Copy link
Contributor

@SyntaxColoring SyntaxColoring commented Apr 30, 2024

Overview

This is a step towards EXEC-427.

Every command declares a result type, e.g Aspirate has AspirateResult. But it turns out that nothing enforces that the command's implementation returns that type—AspirateImplementation could return a DispenseResult. This has been okay in practice so far because each implementation only returns one thing, and it's not easy for them to fall out of sync. But you can imagine how it will get messy when we start introducing more structured error types. My rough plan is for execute() -> AspirateResult to become execute() -> AspirateResult | AspirateErrorA | AspirateErrorB | ..., and we will want to enforce that AspirateErrorA | AspirateErrorB matches the type of the Aspirate.error field.

Changelog

See my inline notes.

Test plan

  • Make sure CI keeps passing.
  • Make sure the "new field" doesn't show up in robot-server's HTTP API documentation.

Review requests

Does this make sense?

Risk assessment

Very low.

Comment on lines +172 to +176
_ImplementationCls: Union[
Type[AbstractCommandImpl[_ParamsT, _ResultT]],
Type[AbstractCommandWithPrivateResultImpl[_ParamsT, _ResultT, object]],
]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By convention, each command links itself to its implementation via an _ImplementationCls class attribute.

Here, I'm declaring that attribute on the base class. This enforces that each command's ._ImplementationCls matches its .params and .result. In the near future, this will also make sure it matches its .error.

Comment on lines -173 to +180
Generic[CommandParamsT, CommandResultT],
Generic[_ParamsT_contra, _ResultT_co],
Copy link
Contributor Author

@SyntaxColoring SyntaxColoring Apr 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In English:

  • An implementation that accepts a broader parameter type can be placed in a variable where it's annotated to accept a narrower parameter type. It's contravariant in its parameters.
  • An implementation that returns a narrower result type can be placed in a variable where it's annotated to return a broader parameter type. It's covariant in its result.

This is the usual behavior for callables, which is basically what a command implementation is. I think we need to spell it out manually because we're going through a wrapper class; the type-checker would understand this automatically if, e.g., the AspirateImplementation.execute() method were just a free-standing execute() function.

Comment on lines +172 to +176
_ImplementationCls: Union[
Type[AbstractCommandImpl[_ParamsT, _ResultT]],
Type[AbstractCommandWithPrivateResultImpl[_ParamsT, _ResultT, object]],
]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're using VS Code or another editor with Pyright integration, you'll get a red squiggly on every command's override of _ImplementationCls. (Mypy does not complain.)

I think it has to do with the fact that _ImplementationCls looks writable, so it's unsound for a subclass to have a more restrictive type than the base class. It looks like commandType has this problem, too. I don't have a solution right now. Maybe it'll get easier with Pydantic v2.

@SyntaxColoring SyntaxColoring marked this pull request as ready for review April 30, 2024 18:26
@SyntaxColoring SyntaxColoring requested a review from a team as a code owner April 30, 2024 18:26
Copy link
Contributor

@jbleon95 jbleon95 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes make sense to me.

@SyntaxColoring SyntaxColoring merged commit e182bb9 into edge Apr 30, 2024
26 checks passed
@SyntaxColoring SyntaxColoring deleted the se_tie_impl_return_to_result_type branch April 30, 2024 18:47
Carlos-fernandez pushed a commit that referenced this pull request May 20, 2024
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.

None yet

2 participants