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

Type annotations for gates, quilatom, and quilbase modules #999

Merged
merged 25 commits into from
Oct 31, 2019

Conversation

appleby
Copy link
Contributor

@appleby appleby commented Sep 16, 2019

Description

This PR adds type annotations for the pyquil.gates, pyquil.quilatom, and pyquil.quilbase modules.

This is still a WIP, but is ready for review. Since I'm new-ish to pyQuil, I probably got the types wrong in several places. See the TODOs in the diff for places I'm particularly unsure about. Any hints from reviewers on these are greatly appreciated.

So far, these pass muster when running mypy like so:

mypy --ignore-missing-imports --follow-imports=silent pyquil/quilatom.py
mypy --ignore-missing-imports --follow-imports=silent pyquil/quilbase.py
mypy --ignore-missing-imports --follow-imports=silent pyquil/gates.py

Resolves #988

TODO:

  • Address remaining TODO:(appleby)s in the source
  • Check rigetti/quil, ensure types agree with spec
  • Turn on mypy's --strict flag and fix any errors reported
  • Run mypy on full source tree, attempt to pick out the relevant errors drowning in the sea of breakage
  • Update docstring types
  • Update the changelog

Checklist

  • The above description motivates these changes.
  • There is a unit test that covers these changes.
  • All new and existing tests pass locally and on Semaphore.
  • Parameters have type hints with PEP 484 syntax.
  • Functions and classes have useful sphinx-style docstrings.
  • (New Feature) The docs have been updated accordingly.
  • (Bugfix) The associated issue is referenced above using
    auto-close keywords.
  • The changelog is updated,
    including author and PR number (@username, gh-xxx).

pyquil/gates.py Outdated Show resolved Hide resolved
pyquil/gates.py Outdated Show resolved Hide resolved
pyquil/gates.py Outdated Show resolved Hide resolved
appleby added a commit that referenced this pull request Sep 17, 2019
@appleby appleby force-pushed the gimme-sum-types branch 2 times, most recently from 3684e8b to 25d86be Compare September 17, 2019 01:06
@@ -475,7 +484,7 @@ def RESET(qubit_index=None):
"""


def MEASURE(qubit, classical_reg):
def MEASURE(qubit: QubitDesignator, classical_reg: Optional[MemoryReferenceDesignator]) -> Measurement:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The classical_reg arg here can also be an int, but that is deprecated. The current type hint causes mypy to warn:

pyquil/tests/test_qvm.py:16: error: Argument 2 to "MEASURE" has incompatible type "int"; expected "Union[MemoryReference, Tuple[str, int], List[Any], str, None]"

This warning only pops up in the three places in test_qvm.py. We could update the type hint here to include the deprecated int type and get rid of the warnings, but it seems saner to leave it as advertising only non-deprecated types.

pyquil/quilatom.py Outdated Show resolved Hide resolved
@appleby appleby requested a review from a team September 18, 2019 15:44
@appleby
Copy link
Contributor Author

appleby commented Sep 18, 2019

This is ready for review. There is still a remaining TODO to update the docstrings, but I'd rather go through a round of review first to make sure the types look sane, then update the docstrings once at the end.

Copy link
Contributor

@notmgsk notmgsk left a comment

Choose a reason for hiding this comment

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

Small nits for your picking.

CHANGELOG.md Outdated Show resolved Hide resolved
CHANGELOG.md Outdated Show resolved Hide resolved
CHANGELOG.md Outdated Show resolved Hide resolved
pyquil/quilatom.py Show resolved Hide resolved
pyquil/quilatom.py Show resolved Hide resolved
pyquil/tests/test_gates.py Show resolved Hide resolved
Copy link
Contributor

@notmgsk notmgsk left a comment

Choose a reason for hiding this comment

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

Can't be the most exciting thing you've worked on! :D

@appleby
Copy link
Contributor Author

appleby commented Sep 18, 2019

Can't be the most exciting thing you've worked on! :D

It's a dirty job, but somebody gotta do it.

Copy link
Contributor

@karalekas karalekas left a comment

Choose a reason for hiding this comment

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

@appleby is there some way we can get around the init -> None thing? seems like Guido himself is not a fan python/mypy#604 (comment)

CHANGELOG.md Outdated Show resolved Hide resolved
@appleby
Copy link
Contributor Author

appleby commented Sep 18, 2019

@appleby is there some way we can get around the init -> None thing? seems like Guido himself is not a fan python/mypy#604 (comment)

I agree with Guido here, but sadly mypy seems to require them. I think we can drop the -> None from any __init__ methods that have at least one non-self argument which is typed. But as far as I understand it, the explicit -> None return type specifier is still required by mypy for __init__s with no annotated args when called from a type-checked context.

On the other hand, I think mypy only sees this as an error when run in --strict mode, so if we're ok with ignoring those for now, then I could nix them. Once we get around to adding to type hints for the quilbase module, practically all of the constructors there take arguments and therefore wouldn't needed an explicit return type annotation.

@ecpeterson
Copy link
Contributor

I have not read this PR line-by-line, but I approve of its spirit.

@appleby
Copy link
Contributor Author

appleby commented Sep 20, 2019

Here is a list of the new type aliases added in this PR:

pyquil/api/_quantum_computer.py
ExecutableDesignator = Union[BinaryExecutableResponse, PyQuilExecutableResponse]

pyquil/quilatom.py
QubitDesignator = Union[Qubit, QubitPlaceholder, int]
MemoryReferenceDesignator = Union['MemoryReference', Tuple[str, int], List[Any], str]
ParameterDesignator = Union['Expression', 'MemoryReference', np.int_, int, float, complex]
ExpressionValueDesignator = Union[int, float, complex]
ExpressionDesignator = Union['Expression', ExpressionValueDesignator]
ParamSubstitutionsMapDesignator = Mapping['Parameter', ExpressionValueDesignator]

A brief explanation for some of the less obvious types:

MemoryReferenceDesignator is used anywhere a memory reference is expected. This means the function in question accepts any of the listed types and hands the value off to unpack_classical_reg to turn it into a valid MemoryReference.

ExpressionValueDesignator captures the set of possible types for an evaluated Quil expression like i*sin(pi), e.g.

ParameterDesignator is used for gate parameters. There is an open question of whether this type hint should include complex or not. See e.g. #1009 and quil-lang/quilc#313.

ParamSubstitutionsMapDesignator is used in the _substitute methods of the various Expression subclasses to indicate the type of the substitutions dict argument, which maps a Parameter to the ExpressionValue that will replace it.

edit: updated with new type aliases from latest commit

appleby added a commit that referenced this pull request Sep 23, 2019
@appleby
Copy link
Contributor Author

appleby commented Sep 23, 2019

Last TODO of updating dosctrings is now done. Marking this ready for review.

I thought I was going to have to add explicit types to the docstring of every function that I added type hints for, hence why I was procrastinating on that thankless task. Finally started doing it, got annoyed and thought: "surely there is a sphinx plugin to figure this out from the type hints in the source", googled it and realized we are already using sphinx-autodoc-typehints (yay). So I ended up removing a handful of explicit references to argument and return types in the docstrings in order to allow sphinx-autodoc-typehints to take care of it and prevent the docstrings from going stale.

@appleby appleby marked this pull request as ready for review September 23, 2019 20:32
@karalekas karalekas added this to the v2.13 milestone Oct 1, 2019
@karalekas karalekas added the quality 🎨 Improve code quality. label Oct 1, 2019
- Replace GateParameter with ParameterDesignator everywhere

- Allow immediate floats as third arg in prepare_ternary_operands

- Allow immediate values as source arg for STORE and ClassicalStore

Fixes #815
Import quilatom.Expression in gates.py. Even though it isn't
referenced directly, it is indirectly used by
quilatom.ParameterDesignator, which causes sphinx to choke when
generating the docs.
Remove any explicit types from :param: and :rtype: sphinx docstrings,
and let sphinx-autodoc-typehints take care of it.
Sometimes code wants to iterate over instr.qubits, which has type
List[Union[Qubit, QubitPlaceholder]]. Ensure that Qubit and
QubitPlaceholder have matching interfaces to prevent mypy
warnings. Previously, code like [q.index for q in instr.qubits] would
cause mypy to complain because q might be a QubitPlaceholder, which
did not have an index attribute.
Also, restrict types of classical instr constructors in quilbase to
not allow MemoryReferenceDesignator. Desginators are only accepted in
the high-level interfaces found in the gates module.
These asserts are required to help mypy deduce that the types are
sufficiently constrained.
And use it as the return type for QuantumComputer.compile.
@karalekas karalekas changed the title Add type annotations for gates, quilatom, and quilbase modules Type annotations for gates, quilatom, and quilbase modules Oct 31, 2019
Copy link
Contributor

@karalekas karalekas left a comment

Choose a reason for hiding this comment

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

looks great!

@karalekas karalekas merged commit 4011664 into master Oct 31, 2019
@karalekas karalekas deleted the gimme-sum-types branch October 31, 2019 22:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
quality 🎨 Improve code quality.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Python 3 typing to the gates module
4 participants