Repository: rigetti/qcs-sdk-rust (language: python)

Issue:
Add type hints to Python package
The Python package currently doesn't provide any type hints. While we expect the API to change, it would be good to have the `.pyi` file setup and distributed so it is easy to update as we make those changes.

Per the pyo3 docs, [a manually maintained `.pyi` file is currently the best way to add hints](https://pyo3.rs/v0.16.4/python_typing_hints.html).


Discussion / hints:

Fix patch:
diff --git a/crates/python/poetry.lock b/crates/python/poetry.lock
index 57ad83ad3..5ab7fc93b 100644
--- a/crates/python/poetry.lock
+++ b/crates/python/poetry.lock
@@ -1,47 +1,6 @@
-[[package]]
-name = "black"
-version = "22.8.0"
-description = "The uncompromising code formatter."
-category = "dev"
-optional = false
-python-versions = ">=3.6.2"
-
-[package.dependencies]
-click = ">=8.0.0"
-mypy-extensions = ">=0.4.3"
-pathspec = ">=0.9.0"
-platformdirs = ">=2"
-tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""}
-typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}
-
-[package.extras]
-colorama = ["colorama (>=0.4.3)"]
-d = ["aiohttp (>=3.7.4)"]
-jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
-uvloop = ["uvloop (>=0.15.2)"]
-
-[[package]]
-name = "click"
-version = "8.1.3"
-description = "Composable command line interface toolkit"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-colorama = {version = "*", markers = "platform_system == \"Windows\""}
-
-[[package]]
-name = "colorama"
-version = "0.4.5"
-description = "Cross-platform colored terminal text."
-category = "dev"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-
 [[package]]
 name = "maturin"
-version = "0.13.2"
+version = "0.13.3"
 description = "Build and publish crates with pyo3, rust-cpython and cffi bindings as well as rust binaries as python packages"
 category = "dev"
 optional = false
@@ -54,34 +13,6 @@ tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
 zig = ["ziglang (>=0.9.0,<0.10.0)"]
 patchelf = ["patchelf"]
 
-[[package]]
-name = "mypy-extensions"
-version = "0.4.3"
-description = "Experimental type system extensions for programs checked with the mypy typechecker."
-category = "dev"
-optional = false
-python-versions = "*"
-
-[[package]]
-name = "pathspec"
-version = "0.10.0"
-description = "Utility library for gitignore style pattern matching of file paths."
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[[package]]
-name = "platformdirs"
-version = "2.5.2"
-description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.extras]
-docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"]
-test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"]
-
 [[package]]
 name = "tomli"
 version = "2.0.1"
@@ -90,85 +21,28 @@ category = "dev"
 optional = false
 python-versions = ">=3.7"
 
-[[package]]
-name = "typing-extensions"
-version = "4.3.0"
-description = "Backported and Experimental Type Hints for Python 3.7+"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
 [metadata]
 lock-version = "1.1"
-python-versions = ">=3.8<3.10"
-content-hash = "e08cfb07ab22776bdaa7d25bd2277cca6672b6a5f60882473a0e1c7d75424bca"
+python-versions = "^3.7"
+content-hash = "775bd1ad820ad84bbcd5a2ea6687822eeba631d1f88cf6710bb8d8e5881e6630"
 
 [metadata.files]
-black = [
-    {file = "black-22.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ce957f1d6b78a8a231b18e0dd2d94a33d2ba738cd88a7fe64f53f659eea49fdd"},
-    {file = "black-22.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5107ea36b2b61917956d018bd25129baf9ad1125e39324a9b18248d362156a27"},
-    {file = "black-22.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8166b7bfe5dcb56d325385bd1d1e0f635f24aae14b3ae437102dedc0c186747"},
-    {file = "black-22.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd82842bb272297503cbec1a2600b6bfb338dae017186f8f215c8958f8acf869"},
-    {file = "black-22.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d839150f61d09e7217f52917259831fe2b689f5c8e5e32611736351b89bb2a90"},
-    {file = "black-22.8.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a05da0430bd5ced89176db098567973be52ce175a55677436a271102d7eaa3fe"},
-    {file = "black-22.8.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a098a69a02596e1f2a58a2a1c8d5a05d5a74461af552b371e82f9fa4ada8342"},
-    {file = "black-22.8.0-cp36-cp36m-win_amd64.whl", hash = "sha256:5594efbdc35426e35a7defa1ea1a1cb97c7dbd34c0e49af7fb593a36bd45edab"},
-    {file = "black-22.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a983526af1bea1e4cf6768e649990f28ee4f4137266921c2c3cee8116ae42ec3"},
-    {file = "black-22.8.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b2c25f8dea5e8444bdc6788a2f543e1fb01494e144480bc17f806178378005e"},
-    {file = "black-22.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:78dd85caaab7c3153054756b9fe8c611efa63d9e7aecfa33e533060cb14b6d16"},
-    {file = "black-22.8.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:cea1b2542d4e2c02c332e83150e41e3ca80dc0fb8de20df3c5e98e242156222c"},
-    {file = "black-22.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5b879eb439094751185d1cfdca43023bc6786bd3c60372462b6f051efa6281a5"},
-    {file = "black-22.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0a12e4e1353819af41df998b02c6742643cfef58282915f781d0e4dd7a200411"},
-    {file = "black-22.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3a73f66b6d5ba7288cd5d6dad9b4c9b43f4e8a4b789a94bf5abfb878c663eb3"},
-    {file = "black-22.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:e981e20ec152dfb3e77418fb616077937378b322d7b26aa1ff87717fb18b4875"},
-    {file = "black-22.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8ce13ffed7e66dda0da3e0b2eb1bdfc83f5812f66e09aca2b0978593ed636b6c"},
-    {file = "black-22.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:32a4b17f644fc288c6ee2bafdf5e3b045f4eff84693ac069d87b1a347d861497"},
-    {file = "black-22.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ad827325a3a634bae88ae7747db1a395d5ee02cf05d9aa7a9bd77dfb10e940c"},
-    {file = "black-22.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53198e28a1fb865e9fe97f88220da2e44df6da82b18833b588b1883b16bb5d41"},
-    {file = "black-22.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:bc4d4123830a2d190e9cc42a2e43570f82ace35c3aeb26a512a2102bce5af7ec"},
-    {file = "black-22.8.0-py3-none-any.whl", hash = "sha256:d2c21d439b2baf7aa80d6dd4e3659259be64c6f49dfd0f32091063db0e006db4"},
-    {file = "black-22.8.0.tar.gz", hash = "sha256:792f7eb540ba9a17e8656538701d3eb1afcb134e3b45b71f20b25c77a8db7e6e"},
-]
-click = [
-    {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
-    {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
-]
-colorama = [
-    {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"},
-    {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"},
-]
 maturin = [
-    {file = "maturin-0.13.2-py3-none-linux_armv6l.whl", hash = "sha256:57a870a82715ddd84e2f5a59cbb313c7d39ebf8398b2a0c36ada9ff9d82056d7"},
-    {file = "maturin-0.13.2-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:cc69d4c2854daa16b91bcc8bc0680a188eb4e239bd627dbc721c7177d2082b16"},
-    {file = "maturin-0.13.2-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:ac51f99936dcbff9cbb8cef960c6b82203c7e4ea6cf2dc127df0c725ab1f73a6"},
-    {file = "maturin-0.13.2-py3-none-manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686.whl", hash = "sha256:ca3a3f2328a0da542323f75a725f38b8ebb575c5805b4bb5c9ba5dd046450239"},
-    {file = "maturin-0.13.2-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:5eb555636eb9fd4f54efc48e5891067f94c0b50f7f402a897c41644f817e70f4"},
-    {file = "maturin-0.13.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:93fef9c0ead64fb0741c18009dc0521181b91241d1c09b0eda5c9a5e06dfc6d0"},
-    {file = "maturin-0.13.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:0a37e30d71b24dfe6ca9eac639ef976bdbf6d1676605f7dd260b5e6e5f93d441"},
-    {file = "maturin-0.13.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl", hash = "sha256:6f2421b23d6699f5d1b408735b306648277ccd833ea9496139f888f95a53faa0"},
-    {file = "maturin-0.13.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ddc42d0b51a2537257a74791df8fbdaf204e72e8e7e2e0da9e02d1c46c6699c"},
-    {file = "maturin-0.13.2-py3-none-win32.whl", hash = "sha256:7caf8c85b8cf759eca31e4c4b36b58afb28be5db86cce951d9633d99a70c4af1"},
-    {file = "maturin-0.13.2-py3-none-win_amd64.whl", hash = "sha256:66a46de95e919be8c5db0b4bc604617a1d79f031373afddb389049c4bbe5b064"},
-    {file = "maturin-0.13.2-py3-none-win_arm64.whl", hash = "sha256:4ed0ad394e50f5b43e2b4a79d7f395b1d98f7cd5b48a527fe6aeb0d4da15b803"},
-    {file = "maturin-0.13.2.tar.gz", hash = "sha256:18882138e633d32e7a18d147ec38c71930db254817f3714e9fd70e01e379e255"},
-]
-mypy-extensions = [
-    {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
-    {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
-]
-pathspec = [
-    {file = "pathspec-0.10.0-py3-none-any.whl", hash = "sha256:aefa80ac32d5bf1f96139dca67cefb69a431beff4e6bf1168468f37d7ab87015"},
-    {file = "pathspec-0.10.0.tar.gz", hash = "sha256:01eecd304ba0e6eeed188ae5fa568e99ef10265af7fd9ab737d6412b4ee0ab85"},
-]
-platformdirs = [
-    {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"},
-    {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"},
+    {file = "maturin-0.13.3-py3-none-linux_armv6l.whl", hash = "sha256:4d1c443776a290b26054112bac77c370ffff89ac7b2d9a04ca0536c257f51016"},
+    {file = "maturin-0.13.3-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:5b3f1aa0817d30c450a46f6ef14f41e21f4f974cefd395181af9dec06a8b1d16"},
+    {file = "maturin-0.13.3-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:0b8c5653c31703523232c602f6e93b76c5aaaf5af66b672155d820702dc63f69"},
+    {file = "maturin-0.13.3-py3-none-manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686.whl", hash = "sha256:85abe7eaebd19e74a781a7512138e7dfae1504dc7cf291e7ad03234795c3c7cc"},
+    {file = "maturin-0.13.3-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:93e97cce6da48d9c8bd73d864d1ad04728ed28a5594b6b65f1322dfd1520c485"},
+    {file = "maturin-0.13.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:65cc3e06dd8b9b0dc9cb813f7b61e3bd5fd327a198deabc661a6afb852d4991a"},
+    {file = "maturin-0.13.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:d738fd84f661e181893625a609bb89c5c35f2038967aac0deff3a5602fd28058"},
+    {file = "maturin-0.13.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl", hash = "sha256:a0b93434668f868387ba67d6455fc887d502c3528733311c0b7fed612d72b33b"},
+    {file = "maturin-0.13.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04a6cb00f125a280a7f2227c3464243d8920ed83ff5523b13fa10220395c3363"},
+    {file = "maturin-0.13.3-py3-none-win32.whl", hash = "sha256:2d8a3e43790a96663a10aa53c100a26f05364d76fbd52daddd980f4c2949411f"},
+    {file = "maturin-0.13.3-py3-none-win_amd64.whl", hash = "sha256:06ed41bd4771674c6f8359e8ed4f261fbb23a371a1e4f833cc9af7f5e5904fc5"},
+    {file = "maturin-0.13.3-py3-none-win_arm64.whl", hash = "sha256:25eb48fc6178079c1399dff7b9ccd401747ecd174c043690f2c40425723b10c5"},
+    {file = "maturin-0.13.3.tar.gz", hash = "sha256:edeb8ecaa5cc6e6d2f50a32289798d7ca046c33481ac24f74805ff289af6afe4"},
 ]
 tomli = [
     {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
     {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
 ]
-typing-extensions = [
-    {file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"},
-    {file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"},
-]
diff --git a/crates/python/qcs_sdk.pyi b/crates/python/qcs_sdk.pyi
new file mode 100644
index 000000000..35473fc85
--- /dev/null
+++ b/crates/python/qcs_sdk.pyi
@@ -0,0 +1,159 @@
+"""
+The qcs_sdk module provides an interface to Rigetti Quantum Cloud Services. Allowing users to compile and run Quil programs on Rigetti quantum processors.
+"""
+from typing import Any, Awaitable, Dict, List, Optional, TypedDict
+from numbers import Number
+
+RecalculationTable = List[str]
+Memory = Dict[str, List[float]]
+PatchValues = Dict[str, List[float]]
+
+class RewriteArithmeticResults(TypedDict):
+    program: str
+    """
+    The resulting program where gate parameter arithmetic has been replaced with memory references. Before execution, the program memory should be updated using the `recalculation_table`.
+    """
+
+    recalculation_table: RecalculationTable
+    """ 
+    The recalculation table stores an ordered list of arithmetic expressions, which are to be used when updating the program memory before execution.
+    """
+
+class TranslationResult(TypedDict):
+    memory_descriptors: Optional[Dict[str, Any]]
+    """
+    A map from the name of memory (declared with `DECLARE`) to the size and type of that memory.
+    """
+
+    program: str
+    """
+    The compiled program binary.
+    """
+
+    ro_sources: Optional[List[List[str]]]
+    """
+    A mapping from the program's memory references to the key used to index the results map.
+    """
+
+    settings_timestamp: Optional[str]
+    """
+    The timestamp of the settings used during translation.
+    """
+
+class ExecutionResult(TypedDict):
+    shape: List[int]
+    """
+    The shape of the result data.
+    """
+
+    data: List[Number]
+    """
+    The result data.
+    """
+
+    dtype: str
+    """
+    The type of the result data (as a `numpy` `dtype`).
+    """
+
+class ExecutionResults(TypedDict):
+    buffers: Dict[str, ExecutionResult]
+    """
+    The readout results of execution, mapping a published filter node to its data.
+
+    See `TranslationResult.ro_sources` which provides the mapping from the filter node name to the name of the memory declaration in the source program.
+    """
+
+    execution_duration_microseconds: Optional[int]
+    """
+    The time spent executing the program.
+    """
+
+def compile(quil: str, target_device: str) -> Awaitable[str]:
+    """
+    Uses quilc to convert a quil program to native Quil.
+
+    Args:
+        quil: A Quil program.
+        target_device: A JSON encoded description of the Quantum Abstract Machine Architecture.
+
+    Returns:
+        An Awaitable that resolves to the native Quil program.
+    """
+    ...
+
+def rewrite_arithmetic(native_quil: str) -> Awaitable[RewriteArithmeticResults]:
+    """
+    Rewrites parametric arithmetic such that all gate parameters are only memory references
+    to a newly declared memory location (__SUBST).
+
+    Args:
+        native_quil: A Quil program.
+
+    Returns:
+        An Awaitable that resolves to a dictionary with the rewritten program and recalculation table (see `RewriteArithmeticResults`).
+    """
+    ...
+
+def build_patch_values(
+    recalculation_table: RecalculationTable, memory: Memory
+) -> Awaitable[PatchValues]:
+    """
+    Evaluate the expressions in recalculation_table using the numeric values
+    provided in memory.
+
+    Args:
+        recalculation_table: an ordered list of arithmetic expressions, which are to be used when updating the program memory before execution (see `rewrite_arithmetic`).
+        memory: A mapping of symbols to their values (e.g. `{"theta": [0.0]}`).
+
+    Returns:
+        An Awaitable that resolves to a mapping of each symbol to the value it should be patched with.
+    """
+    ...
+
+def translate(
+    native_quil: str, num_shots: int, quantum_processor_id: str
+) -> Awaitable[TranslationResult]:
+    """
+    Translates a native Quil program into an executable.
+
+    Args:
+        native_quil: A Quil program.
+        num_shots: The number of shots to perform.
+        quantum_processor_id: The ID of the quantum processor the executable will run on (e.g. "Aspen-M-2").
+
+    Returns:
+        An Awaitable that resolves to a dictionary with the compiled program, memory descriptors, and readout sources (see `TranslationResult`).
+    """
+    ...
+
+def submit(
+    program: str, patch_values: Dict[str, List[float]], quantum_processor_id: str
+) -> Awaitable[str]:
+    """
+    Submits an executable `program` to be run on the specified QPU.
+
+    Args:
+        program: An executable program (see `translate`).
+        patch_values: A mapping of symbols to their desired values (see `build_patch_values`).
+        quantum_processor_id: The ID of the quantum processor to run the executable on.
+
+    Returns:
+        An Awaitable that resolves to the ID of the submitted job.
+    """
+    ...
+
+def retrieve_results(
+    job_id: str, quantum_processor_id: str
+) -> Awaitable[ExecutionResults]:
+    """
+    Fetches results for the corresponding job ID.
+
+    Args:
+        job_id: The ID of the job to retrieve results for.
+        quantum_processor_id: The ID of the quanutum processor the job ran on.
+
+    Returns:
+        An Awaitable that resolves to a dictionary describing the results of the execution and its duration (see `ExecutionResults`).
+    """
+    ...


Test patch:
diff --git a/crates/python/test.py b/crates/python/test.py
deleted file mode 100644
index 8f891745f..000000000
--- a/crates/python/test.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import os
-import asyncio
-import numpy as np
-import qcs
-
-QPID = os.getenv("QPID", "Aspen-11")
-
-program = """
-DECLARE ro BIT
-DECLARE theta REAL
-RX(theta) 0
-MEASURE 0 ro[0]
-"""
-
-async def main():
-    print(f"Executing program on {QPID}.")
-    try:
-        native_quil = await qcs.compile(program, QPID)
-        translated = await qcs.translate(native_quil, 1, QPID)
-        print(translated)
-        job_id = await qcs.submit(translated['program'], {'theta': [np.pi]}, QPID)
-        print(job_id)
-        results = await qcs.retrieve_results(job_id, QPID)
-        print(results)
-    except Exception as e:
-        print(e)
-
-
-asyncio.run(main())