From 8305e0620dd000be437d5089bb156d7977b97072 Mon Sep 17 00:00:00 2001 From: Ryan Shaffer <3620100+rmshaffer@users.noreply.github.com> Date: Thu, 12 Mar 2026 11:17:38 -0400 Subject: [PATCH 1/7] call ProgramContext.__init__ --- src/autoqasm/simulator/program_context.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/autoqasm/simulator/program_context.py b/src/autoqasm/simulator/program_context.py index f48bf2cb..bdcacfee 100644 --- a/src/autoqasm/simulator/program_context.py +++ b/src/autoqasm/simulator/program_context.py @@ -188,10 +188,9 @@ def __init__(self, circuit: Optional[Circuit] = None): circuit (Optional[Circuit]): A partially-built circuit to continue building with this context. Default: None. """ - super(ProgramContext, self).__init__() + super().__init__(circuit) self.qubit_mapping = QubitTable() self.outputs = {} - self._circuit = circuit or Circuit() def pop_instructions(self) -> list[GateOperation]: """Returns the list of instructions and removes them from the context. From a251d83d14c5d5b30577d37bd3dc8177361fbf0c Mon Sep 17 00:00:00 2001 From: Ryan Shaffer <3620100+rmshaffer@users.noreply.github.com> Date: Thu, 12 Mar 2026 11:20:41 -0400 Subject: [PATCH 2/7] bump version to 0.3.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index dcf7c66b..59fd8c4b 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ setup( name="autoqasm", - version="0.2.0", + version="0.3.0", license="Apache License 2.0", python_requires=">= 3.11", packages=find_namespace_packages(where="src", exclude=("test",)), From ec532fab2f3a4b080bcedc58a06a6eda1efdcd73 Mon Sep 17 00:00:00 2001 From: Ryan Shaffer <3620100+rmshaffer@users.noreply.github.com> Date: Thu, 12 Mar 2026 13:24:34 -0400 Subject: [PATCH 3/7] linter fixes --- src/autoqasm/api.py | 26 +++++++++-------- src/autoqasm/converters/arithmetic.py | 4 +-- src/autoqasm/converters/return_statements.py | 3 +- src/autoqasm/errors.py | 6 ++-- src/autoqasm/instructions/__init__.py | 2 +- src/autoqasm/instructions/gates.py | 4 +-- src/autoqasm/instructions/qubits.py | 4 +-- src/autoqasm/operators/arithmetic.py | 16 +++++------ src/autoqasm/operators/logical.py | 3 +- src/autoqasm/operators/slices.py | 2 +- src/autoqasm/program/pragmas.py | 2 +- src/autoqasm/program/program.py | 19 ++++++------- src/autoqasm/pulse/__init__.py | 2 +- src/autoqasm/simulator/conversion.py | 4 +-- src/autoqasm/simulator/native_interpreter.py | 16 +++++------ src/autoqasm/simulator/program_context.py | 11 ++++--- src/autoqasm/transpiler/transpiler.py | 8 +++--- src/autoqasm/types/conversions.py | 3 +- src/autoqasm/types/types.py | 30 +++++++------------- tox.ini | 3 -- 20 files changed, 74 insertions(+), 94 deletions(-) diff --git a/src/autoqasm/api.py b/src/autoqasm/api.py index 147fe1c6..4717bc31 100644 --- a/src/autoqasm/api.py +++ b/src/autoqasm/api.py @@ -18,9 +18,9 @@ import copy import functools import inspect -from collections.abc import Callable +from collections.abc import Callable, Iterable from types import FunctionType -from typing import Any, Iterable, get_args +from typing import Any, get_args import openqasm3.ast as qasm_ast import oqpy.base @@ -227,7 +227,7 @@ def _convert_main( Returns: aq_program.Program: Generated AutoQASM Program. """ - if "device" in kwargs and kwargs["device"]: + if kwargs.get("device"): user_config.device = kwargs["device"] param_dict = {} @@ -479,8 +479,8 @@ def _clone_function(f_source: Callable) -> Callable: copy.deepcopy(f_source.__defaults__), copy.copy(f_source.__closure__), ) - setattr(f_clone, "__signature__", copy.deepcopy(inspect.signature(f_source))) - setattr(f_clone, "__annotations__", copy.deepcopy(f_source.__annotations__)) + f_clone.__signature__ = copy.deepcopy(inspect.signature(f_source)) + f_clone.__annotations__ = copy.deepcopy(f_source.__annotations__) return f_clone @@ -492,15 +492,15 @@ def f_dummy(*args, **kwargs) -> Any: f_dummy.__name__ = copy.deepcopy(f_source.__name__) f_dummy.__defaults__ = copy.deepcopy(f_source.__defaults__) - setattr(f_dummy, "__signature__", copy.deepcopy(inspect.signature(f_source))) - setattr(f_dummy, "__annotations__", copy.deepcopy(f_source.__annotations__)) + f_dummy.__signature__ = copy.deepcopy(inspect.signature(f_source)) + f_dummy.__annotations__ = copy.deepcopy(f_source.__annotations__) return f_dummy def _make_return_instance_from_f_annotation(f: Callable) -> Any: # TODO: Recursive functions should work even if the user's type hint is wrong annotations = f.__annotations__ - return_type = annotations["return"] if "return" in annotations else None + return_type = annotations.get("return", None) return return_type() if return_type else None @@ -675,11 +675,13 @@ def _convert_calibration( }, } - with aq_program.build_program() as program_conversion_context: - with program_conversion_context.calibration_definition( + with ( + aq_program.build_program() as program_conversion_context, + program_conversion_context.calibration_definition( gate_function.__name__, gate_calibration_qubits, gate_calibration_angles - ): - aq_transpiler.converted_call(f, [], func_call_kwargs, options=options) + ), + ): + aq_transpiler.converted_call(f, [], func_call_kwargs, options=options) return GateCalibration( gate_function=gate_function, diff --git a/src/autoqasm/converters/arithmetic.py b/src/autoqasm/converters/arithmetic.py index edc6a360..e5b74a15 100644 --- a/src/autoqasm/converters/arithmetic.py +++ b/src/autoqasm/converters/arithmetic.py @@ -41,15 +41,13 @@ def visit_BinOp(self, node: ast.stmt) -> ast.stmt: template = f"{ARITHMETIC_OPERATORS[op_type]}(lhs_,rhs_)" - new_node = templates.replace( + return templates.replace( template, lhs_=node.left, rhs_=node.right, original=node, )[0].value - return new_node - def transform(node: ast.stmt, ctx: ag_ctx.ControlStatusCtx) -> ast.stmt: """Transform arithmetic nodes. diff --git a/src/autoqasm/converters/return_statements.py b/src/autoqasm/converters/return_statements.py index dae2ba4c..c7d49a85 100644 --- a/src/autoqasm/converters/return_statements.py +++ b/src/autoqasm/converters/return_statements.py @@ -48,14 +48,13 @@ def visit_Return(self, node: ast.stmt) -> ast.stmt: if isinstance(node.value, gast.Name): name = node.value.id - node = templates.replace( + return templates.replace( template, name_=name, name_const_=gast.Constant(name, None), value_=node.value, original=node, ) - return node def transform( diff --git a/src/autoqasm/errors.py b/src/autoqasm/errors.py index d052fa4d..e745dea3 100644 --- a/src/autoqasm/errors.py +++ b/src/autoqasm/errors.py @@ -92,10 +92,10 @@ class UnsupportedConditionalExpressionError(AutoQasmError): def __init__(self, true_type: type | None, false_type: type | None): if_type = true_type.__name__ if true_type else "None" else_type = false_type.__name__ if false_type else "None" - self.message = """\ -`if` clause resolves to {}, but `else` clause resolves to {}. \ + self.message = f"""\ +`if` clause resolves to {if_type}, but `else` clause resolves to {else_type}. \ Both the `if` and `else` clauses of an inline conditional expression \ -must resolve to the same type.""".format(if_type, else_type) +must resolve to the same type.""" def __str__(self): return self.message diff --git a/src/autoqasm/instructions/__init__.py b/src/autoqasm/instructions/__init__.py index e5e6e4bd..094e31f9 100644 --- a/src/autoqasm/instructions/__init__.py +++ b/src/autoqasm/instructions/__init__.py @@ -25,7 +25,7 @@ def bell(): measure([0, 1]) """ -from .gates import * # noqa: F401, F403 +from .gates import * # noqa: F403 from .instructions import reset # noqa: F401 from .measurements import measure # noqa: F401 from .qubits import global_qubit_register # noqa: F401 diff --git a/src/autoqasm/instructions/gates.py b/src/autoqasm/instructions/gates.py index 24c8aa79..4212a738 100644 --- a/src/autoqasm/instructions/gates.py +++ b/src/autoqasm/instructions/gates.py @@ -14,15 +14,13 @@ """Quantum gates, unitary instructions, that apply to qubits.""" -from typing import Union - import oqpy from autoqasm.instructions.instructions import _qubit_instruction from autoqasm.types import QubitIdentifierType from braket.circuits.free_parameter_expression import FreeParameterExpression -GateParameterType = Union[float, FreeParameterExpression, oqpy._ClassicalVar] +GateParameterType = float | FreeParameterExpression | oqpy._ClassicalVar def ccnot( diff --git a/src/autoqasm/instructions/qubits.py b/src/autoqasm/instructions/qubits.py index c6a63604..cf88c892 100644 --- a/src/autoqasm/instructions/qubits.py +++ b/src/autoqasm/instructions/qubits.py @@ -17,7 +17,7 @@ from __future__ import annotations import re -from collections.abc import Iterable +from collections.abc import Iterator from functools import singledispatch from typing import Any @@ -58,7 +58,7 @@ def __init__(self, size: int | None): def __len__(self) -> int: return self.size - def __iter__(self) -> Iterable: + def __iter__(self) -> Iterator: return iter(range(len(self))) diff --git a/src/autoqasm/operators/arithmetic.py b/src/autoqasm/operators/arithmetic.py index baa9762a..09cf3e73 100644 --- a/src/autoqasm/operators/arithmetic.py +++ b/src/autoqasm/operators/arithmetic.py @@ -22,13 +22,13 @@ def floor_div( - num: aq_types.IntVar | aq_types.FloatVar | int | float, - den: aq_types.IntVar | aq_types.FloatVar | int | float, + num: aq_types.IntVar | aq_types.FloatVar | float, + den: aq_types.IntVar | aq_types.FloatVar | float, ) -> int | aq_types.IntVar: """Functional form of "//". Args: - num (IntVar | FloatVar | int | float) : The numerator of the integer division - den (IntVar | FloatVar | int | float) : The denominator of the integer division + num (IntVar | FloatVar | float) : The numerator of the integer division + den (IntVar | FloatVar | float) : The denominator of the integer division Returns : int | IntVar : integer division, IntVar if either numerator or denominator are QASM types, else int @@ -40,8 +40,8 @@ def floor_div( def _oqpy_floor_div( - num: aq_types.IntVar | aq_types.FloatVar | int | float, - den: aq_types.IntVar | aq_types.FloatVar | int | float, + num: aq_types.IntVar | aq_types.FloatVar | float, + den: aq_types.IntVar | aq_types.FloatVar | float, ) -> aq_types.IntVar | aq_types.FloatVar: num, den = _register_and_convert_parameters(num, den) oqpy_program = program.get_program_conversion_context().get_oqpy_program() @@ -75,7 +75,7 @@ def _oqpy_floor_div( def _py_floor_div( - num: int | float, - den: int | float, + num: float, + den: float, ) -> int | float: return num // den diff --git a/src/autoqasm/operators/logical.py b/src/autoqasm/operators/logical.py index 8e66a9e0..65a99fe4 100644 --- a/src/autoqasm/operators/logical.py +++ b/src/autoqasm/operators/logical.py @@ -16,7 +16,8 @@ from __future__ import annotations -from typing import Any, Callable +from collections.abc import Callable +from typing import Any import oqpy.base from openpulse import ast diff --git a/src/autoqasm/operators/slices.py b/src/autoqasm/operators/slices.py index ca1f6f4d..1d709554 100644 --- a/src/autoqasm/operators/slices.py +++ b/src/autoqasm/operators/slices.py @@ -52,7 +52,7 @@ def _oqpy_get_item(target: Any, i: Any, opts: GetItemOpts) -> Any: elif isinstance(target, oqpy.BitVar): base_type = type(target) else: - raise TypeError(f"{str(type(target))} object is not subscriptable") + raise TypeError(f"{type(target)!s} object is not subscriptable") var = base_type() oqpy_program.set(var, target[i]) diff --git a/src/autoqasm/program/pragmas.py b/src/autoqasm/program/pragmas.py index 266eddd5..cf68be37 100644 --- a/src/autoqasm/program/pragmas.py +++ b/src/autoqasm/program/pragmas.py @@ -31,8 +31,8 @@ def pragma_example() -> None: from __future__ import annotations import contextlib +from collections.abc import Iterable from enum import StrEnum -from typing import Iterable from autoqasm import errors, program from braket.device_schema import DeviceActionType diff --git a/src/autoqasm/program/program.py b/src/autoqasm/program/program.py index f1a7f1fc..b0b0e12a 100644 --- a/src/autoqasm/program/program.py +++ b/src/autoqasm/program/program.py @@ -55,7 +55,7 @@ def _get_local() -> threading.local: local: The thread-local object which stores the program conversion context. """ if not hasattr(_local, "program_conversion_context"): - setattr(_local, "program_conversion_context", None) + _local.program_conversion_context = None return _local @@ -122,7 +122,7 @@ def to_ir( self, ir_type: IRType = IRType.OPENQASM, build_if_necessary: bool = True, - serialization_properties: SerializationProperties = OpenQASMSerializationProperties(), + serialization_properties: SerializationProperties = OpenQASMSerializationProperties(), # noqa: B008 ) -> str: """Serializes the program into an intermediate representation. @@ -228,7 +228,7 @@ def to_ir( self, ir_type: IRType = IRType.OPENQASM, build_if_necessary: bool = True, - serialization_properties: SerializationProperties = OpenQASMSerializationProperties(), + serialization_properties: SerializationProperties = OpenQASMSerializationProperties(), # noqa: B008 ) -> str: """Serializes the program into an intermediate representation. @@ -364,7 +364,7 @@ def qubits(self) -> list[int]: list[int]: The list of virtual qubits, e.g. [0, 1, 2] """ # Can be memoized or otherwise made more performant - return sorted(list(self._virtual_qubits_used)) + return list(sorted(self._virtual_qubits_used)) # noqa: C413 def register_qubit(self, qubit: int) -> None: """Register a virtual qubit that is used in this program.""" @@ -441,7 +441,7 @@ def _free_symbol_names(expr: FreeParameterExpression) -> Iterable[str]: def register_input_parameter( self, name: str, - param_type: float | int | bool = float, + param_type: float | bool = float, ) -> None: """Register an input parameter if it has not already been registered. @@ -471,13 +471,13 @@ def register_input_parameter( return var def register_output_parameter( - self, name: str, value: bool | int | float | oqpy.base.Var | oqpy.OQPyExpression | None + self, name: str, value: bool | float | oqpy.base.Var | oqpy.OQPyExpression | None ) -> None: """Register a new output parameter if it is not None. Args: name (str): The name of the parameter to register with the program. - value (bool | int | float | Var | OQPyExpression | None): Value to + value (bool | float | Var | OQPyExpression | None): Value to register as an output parameter. """ if value is None: @@ -589,10 +589,7 @@ def is_var_name_used(self, var_name: str) -> bool: bool: Return True if the variable already exists """ oqpy_program = self.get_oqpy_program() - return ( - var_name in oqpy_program.declared_vars.keys() - or var_name in oqpy_program.undeclared_vars.keys() - ) + return var_name in oqpy_program.declared_vars or var_name in oqpy_program.undeclared_vars def validate_gate_targets(self, qubits: list[Any], angles: list[Any]) -> None: """Validate that the specified gate targets are valid at this point in the program. diff --git a/src/autoqasm/pulse/__init__.py b/src/autoqasm/pulse/__init__.py index 65e4b09f..0911abd3 100644 --- a/src/autoqasm/pulse/__init__.py +++ b/src/autoqasm/pulse/__init__.py @@ -27,4 +27,4 @@ def my_pulse_program(): pulse.delay([3, 4], 0.34) """ -from .pulse import * # noqa: F401, F403 +from .pulse import * # noqa: F403 diff --git a/src/autoqasm/simulator/conversion.py b/src/autoqasm/simulator/conversion.py index a162e242..2701b524 100644 --- a/src/autoqasm/simulator/conversion.py +++ b/src/autoqasm/simulator/conversion.py @@ -12,7 +12,7 @@ # language governing permissions and limitations under the License. from functools import singledispatch -from typing import Any, Union +from typing import Any import numpy as np @@ -25,7 +25,7 @@ IntegerLiteral, ) -LiteralType = Union[BooleanLiteral, IntegerLiteral, FloatLiteral, ArrayLiteral, BitstringLiteral] +LiteralType = BooleanLiteral | IntegerLiteral | FloatLiteral | ArrayLiteral | BitstringLiteral @singledispatch diff --git a/src/autoqasm/simulator/native_interpreter.py b/src/autoqasm/simulator/native_interpreter.py index 2ab49cca..382cee75 100644 --- a/src/autoqasm/simulator/native_interpreter.py +++ b/src/autoqasm/simulator/native_interpreter.py @@ -14,7 +14,7 @@ from copy import deepcopy from functools import singledispatchmethod from logging import Logger -from typing import Any, List, Optional, Union +from typing import Any from openqasm3.ast import IntegerLiteral @@ -43,8 +43,8 @@ class NativeInterpreter(Interpreter): def __init__( self, simulation: Simulation, - context: Optional[McmProgramContext] = None, - logger: Optional[Logger] = None, + context: McmProgramContext | None = None, + logger: Logger | None = None, ): self.simulation = simulation context = context or McmProgramContext() @@ -53,7 +53,7 @@ def __init__( def simulate( self, source: str, - inputs: Optional[dict[str, Any]] = None, + inputs: dict[str, Any] | None = None, is_file: bool = False, shots: int = 1, ) -> dict[str, Any]: @@ -87,7 +87,7 @@ def simulate( return self.context.outputs @singledispatchmethod - def visit(self, node: Union[QASMNode, List[QASMNode]]) -> Optional[QASMNode]: + def visit(self, node: QASMNode | list[QASMNode]) -> QASMNode | None: """Generic visit function for an AST node""" return super().visit(node) @@ -99,21 +99,21 @@ def _(self, node: QubitDeclaration) -> None: self.simulation.add_qubits(size) @visit.register - def _(self, node: QuantumMeasurement) -> Union[BooleanLiteral, ArrayLiteral]: + def _(self, node: QuantumMeasurement) -> BooleanLiteral | ArrayLiteral: self.logger.debug(f"Quantum measurement: {node}") self.simulation.evolve(self.context.pop_instructions()) targets = self.context.get_qubits(self.visit(node.qubit)) outcome = self.simulation.measure(targets) if len(targets) > 1 or ( isinstance(node.qubit, IndexedIdentifier) - and not len(node.qubit.indices[0]) == 1 + and len(node.qubit.indices[0]) != 1 and isinstance(node.qubit.indices[0], IntegerLiteral) ): return ArrayLiteral([BooleanLiteral(x) for x in outcome]) return BooleanLiteral(outcome[0]) @visit.register - def _(self, node: QuantumMeasurementStatement) -> Union[BooleanLiteral, ArrayLiteral]: + def _(self, node: QuantumMeasurementStatement) -> BooleanLiteral | ArrayLiteral: self.logger.debug(f"Quantum measurement statement: {node}") outcome = self.visit(node.measure) current_value = self.context.get_value_by_identifier(node.target) diff --git a/src/autoqasm/simulator/program_context.py b/src/autoqasm/simulator/program_context.py index bdcacfee..99988f86 100644 --- a/src/autoqasm/simulator/program_context.py +++ b/src/autoqasm/simulator/program_context.py @@ -15,7 +15,6 @@ from collections.abc import Sequence from functools import singledispatchmethod -from typing import Optional, Union import numpy as np from sympy import Integer @@ -51,7 +50,7 @@ def _validate_qubit_in_range(self, qubit: int, register_name: str) -> None: ) @singledispatchmethod - def get_by_identifier(self, identifier: Union[Identifier, IndexedIdentifier]) -> tuple[int]: + def get_by_identifier(self, identifier: Identifier | IndexedIdentifier) -> tuple[int]: """Convenience method to get an element with a possibly indexed identifier. Args: @@ -65,7 +64,7 @@ def get_by_identifier(self, identifier: Union[Identifier, IndexedIdentifier]) -> return self[identifier.name] @get_by_identifier.register - def _(self, identifier: IndexedIdentifier) -> tuple[int]: # noqa: C901 + def _(self, identifier: IndexedIdentifier) -> tuple[int]: """When identifier is an IndexedIdentifier, function returns a tuple corresponding to the elements referenced by the indexed identifier. @@ -94,7 +93,7 @@ def _(self, identifier: IndexedIdentifier) -> tuple[int]: # noqa: C901 for index in index_list: if isinstance(index, int): self._validate_qubit_in_range(index, name) - target = tuple([self[name][0] + index for index in index_list]) + target = tuple([self[name][0] + index for index in index_list]) # noqa: C409 if len(indices) == 2: # used for gate calls on registers, index will be IntegerLiteral @@ -165,7 +164,7 @@ def _get_indices_length( else: raise TypeError(f"tuple indices must be integers or slices, not {type(last_index)}") - def get_qubit_size(self, identifier: Union[Identifier, IndexedIdentifier]) -> int: + def get_qubit_size(self, identifier: Identifier | IndexedIdentifier) -> int: """Gets the number of qubit indices for the given identifier. Args: @@ -182,7 +181,7 @@ def get_qubit_size(self, identifier: Union[Identifier, IndexedIdentifier]) -> in class McmProgramContext(ProgramContext): - def __init__(self, circuit: Optional[Circuit] = None): + def __init__(self, circuit: Circuit | None = None): """ Args: circuit (Optional[Circuit]): A partially-built circuit to continue building with this diff --git a/src/autoqasm/transpiler/transpiler.py b/src/autoqasm/transpiler/transpiler.py index 6b40a2ff..61f2b8dd 100644 --- a/src/autoqasm/transpiler/transpiler.py +++ b/src/autoqasm/transpiler/transpiler.py @@ -62,11 +62,11 @@ class PyToOqpy(transpiler.PyToPy): """The AutoQASM transpiler which converts a Python function into an oqpy program.""" def __init__(self): - super(PyToOqpy, self).__init__() + super().__init__() self._extra_locals = None def get_transformed_name(self, node: gast.Lambda | gast.FunctionDef) -> str: - return "oq__" + super(PyToOqpy, self).get_transformed_name(node) + return "oq__" + super().get_transformed_name(node) def get_extra_locals(self) -> dict: """Returns extra static local variables to be made to transformed code. @@ -147,7 +147,7 @@ def transform_ast( node = logical_expressions.transform(node, ctx) node = variables.transform(node, ctx) - return node + return node # noqa: RET504 def _convert_actual(entity: Callable, program_ctx: ag_ctx.ControlStatusCtx | None) -> Callable: @@ -288,7 +288,7 @@ def _try_convert_actual( converted_f = _convert_actual(target_entity, program_ctx) if logging.has_verbosity(2): _log_callargs(converted_f, effective_args, kwargs) - except Exception as e: + except Exception as e: # noqa: BLE001 logging.log(1, "Error transforming entity %s", target_entity, exc_info=True) exc = e return converted_f, exc diff --git a/src/autoqasm/types/conversions.py b/src/autoqasm/types/conversions.py index 023d9ab7..edf2793d 100644 --- a/src/autoqasm/types/conversions.py +++ b/src/autoqasm/types/conversions.py @@ -116,8 +116,7 @@ def wrap_value(node: Any) -> Any: @wrap_value.register(tuple) def _(node: tuple): - wrapped_nodes = tuple(wrap_value(item) for item in node) - return wrapped_nodes + return tuple(wrap_value(item) for item in node) @wrap_value.register(bool) diff --git a/src/autoqasm/types/types.py b/src/autoqasm/types/types.py index 2b7ad0cc..8ed7b6fd 100644 --- a/src/autoqasm/types/types.py +++ b/src/autoqasm/types/types.py @@ -16,7 +16,7 @@ from __future__ import annotations from collections.abc import Iterable -from typing import Any, List, Union, get_args +from typing import Any, get_args import numpy as np import oqpy @@ -52,13 +52,11 @@ def is_qasm_type(val: Any) -> bool: return isinstance(val, qasm_types) -def make_annotations_list(annotations: str | Iterable[str] | None) -> List[str]: +def make_annotations_list(annotations: str | Iterable[str] | None) -> list[str]: return [annotations] if isinstance(annotations, str) else annotations or [] -QubitIdentifierType = Union[ - int, str, Qubit, oqpy._ClassicalVar, oqpy.base.OQPyExpression, oqpy.Qubit -] +QubitIdentifierType = int | str | Qubit | oqpy._ClassicalVar | oqpy.base.OQPyExpression | oqpy.Qubit def is_qubit_identifier_type(qubit: Any) -> bool: @@ -92,7 +90,7 @@ def __init__( if stop is None: stop = start start = 0 - super(Range, self).__init__(start, stop, step) + super().__init__(start, stop, step) self.annotations = make_annotations_list(annotations) @@ -116,9 +114,9 @@ def __init__( raise errors.InvalidArrayDeclaration("init_expression must be an iterable type.") dimensions = np.shape(init_expression) - super(ArrayVar, self).__init__( + super().__init__( init_expression=init_expression, - *args, + *args, # noqa: B026 annotations=make_annotations_list(annotations), dimensions=dimensions, **kwargs, @@ -128,9 +126,7 @@ def __init__( class BitVar(oqpy.BitVar): def __init__(self, *args, annotations: str | Iterable[str] | None = None, **kwargs): - super(BitVar, self).__init__( - *args, annotations=make_annotations_list(annotations), **kwargs - ) + super().__init__(*args, annotations=make_annotations_list(annotations), **kwargs) self.name = program.get_program_conversion_context().next_var_name(oqpy.BitVar) if self.size and self.init_expression != "output": value = self.init_expression or 0 @@ -139,23 +135,17 @@ def __init__(self, *args, annotations: str | Iterable[str] | None = None, **kwar class BoolVar(oqpy.BoolVar): def __init__(self, *args, annotations: str | Iterable[str] | None = None, **kwargs): - super(BoolVar, self).__init__( - *args, annotations=make_annotations_list(annotations), **kwargs - ) + super().__init__(*args, annotations=make_annotations_list(annotations), **kwargs) self.name = program.get_program_conversion_context().next_var_name(oqpy.BoolVar) class FloatVar(oqpy.FloatVar): def __init__(self, *args, annotations: str | Iterable[str] | None = None, **kwargs): - super(FloatVar, self).__init__( - *args, annotations=make_annotations_list(annotations), **kwargs - ) + super().__init__(*args, annotations=make_annotations_list(annotations), **kwargs) self.name = program.get_program_conversion_context().next_var_name(oqpy.FloatVar) class IntVar(oqpy.IntVar): def __init__(self, *args, annotations: str | Iterable[str] | None = None, **kwargs): - super(IntVar, self).__init__( - *args, annotations=make_annotations_list(annotations), **kwargs - ) + super().__init__(*args, annotations=make_annotations_list(annotations), **kwargs) self.name = program.get_program_conversion_context().next_var_name(oqpy.IntVar) diff --git a/tox.ini b/tox.ini index 21dfb51a..53175946 100644 --- a/tox.ini +++ b/tox.ini @@ -54,20 +54,17 @@ commands = [testenv:linters_check] basepython = python3 deps = ruff -extras = linters commands = {[testenv:ruff-check]commands} [testenv:ruff-check] basepython = python3 -extras = linters deps = ruff commands = ruff check src {posargs} [testenv:ruff-format] basepython = python3 -extras = linters deps = ruff commands = ruff format . {posargs} From 9f35203fb74f9732b52dbdc4db23fcb27e31de38 Mon Sep 17 00:00:00 2001 From: Ryan Shaffer <3620100+rmshaffer@users.noreply.github.com> Date: Thu, 12 Mar 2026 13:27:25 -0400 Subject: [PATCH 4/7] linter fixes --- src/autoqasm/api.py | 5 ++--- src/autoqasm/instructions/__init__.py | 2 +- src/autoqasm/pulse/__init__.py | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/autoqasm/api.py b/src/autoqasm/api.py index 4717bc31..6034613a 100644 --- a/src/autoqasm/api.py +++ b/src/autoqasm/api.py @@ -609,9 +609,8 @@ def _get_gate_args(f: Callable) -> aq_program.GateArgs: if param.annotation == aq_instructions.QubitIdentifierType: gate_args.append_qubit(param.name) - elif param.annotation == float or any( # noqa: E721 - type_ == float # noqa: E721 - for type_ in get_args(param.annotation) + elif param.annotation == float or any( + type_ == float for type_ in get_args(param.annotation) ): gate_args.append_angle(param.name) else: diff --git a/src/autoqasm/instructions/__init__.py b/src/autoqasm/instructions/__init__.py index 094e31f9..71f367cf 100644 --- a/src/autoqasm/instructions/__init__.py +++ b/src/autoqasm/instructions/__init__.py @@ -25,7 +25,7 @@ def bell(): measure([0, 1]) """ -from .gates import * # noqa: F403 +from .gates import * from .instructions import reset # noqa: F401 from .measurements import measure # noqa: F401 from .qubits import global_qubit_register # noqa: F401 diff --git a/src/autoqasm/pulse/__init__.py b/src/autoqasm/pulse/__init__.py index 0911abd3..a6def8ce 100644 --- a/src/autoqasm/pulse/__init__.py +++ b/src/autoqasm/pulse/__init__.py @@ -27,4 +27,4 @@ def my_pulse_program(): pulse.delay([3, 4], 0.34) """ -from .pulse import * # noqa: F403 +from .pulse import * From 6d73edccd2a7f24fe0945da737ff8494323c85bd Mon Sep 17 00:00:00 2001 From: Ryan Shaffer <3620100+rmshaffer@users.noreply.github.com> Date: Thu, 12 Mar 2026 13:57:50 -0400 Subject: [PATCH 5/7] pin diastatic-malt version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 59fd8c4b..64962916 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ "amazon-braket-sdk>=1.89.1", "amazon-braket-default-simulator>=1.23.2", "oqpy~=0.3.5", - "diastatic-malt", + "diastatic-malt<=2.15.2", "numpy", "openpulse", "openqasm3", From 0b1a2202332078947a1c4f26eab9a9e09288f393 Mon Sep 17 00:00:00 2001 From: Ryan Shaffer <3620100+rmshaffer@users.noreply.github.com> Date: Thu, 12 Mar 2026 14:42:37 -0400 Subject: [PATCH 6/7] update changelog --- CHANGELOG.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 656e0b0b..697d7b7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,29 @@ # Changelog +## v0.3.0 (2026-03-13) + +### What's Changed +* fix: call ProgramContext constructor by @rmshaffer in https://github.com/amazon-braket/autoqasm/pull/93 +* fix: updated config file by @sesmart in https://github.com/amazon-braket/autoqasm/pull/81 +* update error message for index error by @yitchen-tim in https://github.com/amazon-braket/autoqasm/pull/82 +* depr: drop Python 3.10 support by @rmshaffer in https://github.com/amazon-braket/autoqasm/pull/92 + +### New Contributors +* @sesmart made their first contribution in https://github.com/amazon-braket/autoqasm/pull/81 +* @yitchen-tim made their first contribution in https://github.com/amazon-braket/autoqasm/pull/82 +* @speller26 made their first contribution in https://github.com/amazon-braket/autoqasm/pull/84 + +**Full Changelog**: https://github.com/amazon-braket/autoqasm/compare/v0.2.0...v0.3.0 + ## v0.2.0 (2025-08-26) -## What's Changed +### What's Changed * infra: update supported python versions by @rmshaffer in https://github.com/amazon-braket/autoqasm/pull/77 * change: Use Ankaa-2 instead of Aspen-M-3 in pulse examples by @rmshaffer in https://github.com/amazon-braket/autoqasm/pull/48 * infra: onboard to use ruff by @AbeCoull in https://github.com/amazon-braket/autoqasm/pull/53 * feature: Use hybrid_job from braket.jobs by @rmshaffer in https://github.com/amazon-braket/autoqasm/pull/66 -## New Contributors +### New Contributors * @AbeCoull made their first contribution in https://github.com/amazon-braket/autoqasm/pull/53 **Full Changelog**: https://github.com/amazon-braket/autoqasm/compare/v0.1.2...v0.1.3 From 49ffe8424a2d1675fbd59806d042f7634c71f06e Mon Sep 17 00:00:00 2001 From: Ryan Shaffer <3620100+rmshaffer@users.noreply.github.com> Date: Fri, 13 Mar 2026 08:46:08 -0400 Subject: [PATCH 7/7] remove gast dependency --- setup.py | 3 +-- src/autoqasm/converters/arithmetic.py | 3 +-- src/autoqasm/converters/assignments.py | 5 ++--- src/autoqasm/converters/comparisons.py | 9 ++++----- src/autoqasm/converters/return_statements.py | 5 ++--- src/autoqasm/transpiler/transpiler.py | 14 +++++++------- test/unit_tests/autoqasm/mock_transpiler.py | 6 +++--- 7 files changed, 20 insertions(+), 25 deletions(-) diff --git a/setup.py b/setup.py index 64962916..746eab50 100644 --- a/setup.py +++ b/setup.py @@ -27,13 +27,12 @@ "amazon-braket-sdk>=1.89.1", "amazon-braket-default-simulator>=1.23.2", "oqpy~=0.3.5", - "diastatic-malt<=2.15.2", + "diastatic-malt>=2.15.3", "numpy", "openpulse", "openqasm3", "sympy", "astunparse", - "gast", "termcolor", "openqasm_pygments", ], diff --git a/src/autoqasm/converters/arithmetic.py b/src/autoqasm/converters/arithmetic.py index e5b74a15..577ae826 100644 --- a/src/autoqasm/converters/arithmetic.py +++ b/src/autoqasm/converters/arithmetic.py @@ -15,12 +15,11 @@ import ast -import gast from malt.core import ag_ctx, converter from malt.pyct import templates ARITHMETIC_OPERATORS = { - gast.FloorDiv: "ag__.floor_div", + ast.FloorDiv: "ag__.floor_div", } diff --git a/src/autoqasm/converters/assignments.py b/src/autoqasm/converters/assignments.py index 7b81718d..f0d2a808 100644 --- a/src/autoqasm/converters/assignments.py +++ b/src/autoqasm/converters/assignments.py @@ -16,7 +16,6 @@ import ast -import gast from malt.core import ag_ctx, converter from malt.pyct import templates @@ -52,8 +51,8 @@ def visit_Assign(self, node: ast.stmt) -> ast.stmt: if len(node.targets) > 1: raise NotImplementedError - if isinstance(node.targets[0], gast.Name): - target_name = gast.Constant(node.targets[0].id, None) + if isinstance(node.targets[0], ast.Name): + target_name = ast.Constant(node.targets[0].id, None) new_node = templates.replace( template, tar_name_=target_name, diff --git a/src/autoqasm/converters/comparisons.py b/src/autoqasm/converters/comparisons.py index 7fffdd81..22638d28 100644 --- a/src/autoqasm/converters/comparisons.py +++ b/src/autoqasm/converters/comparisons.py @@ -15,15 +15,14 @@ import ast -import gast from malt.core import ag_ctx, converter from malt.pyct import templates COMPARISON_OPERATORS = { - gast.Lt: "ag__.lt_", - gast.LtE: "ag__.lteq_", - gast.Gt: "ag__.gt_", - gast.GtE: "ag__.gteq_", + ast.Lt: "ag__.lt_", + ast.LtE: "ag__.lteq_", + ast.Gt: "ag__.gt_", + ast.GtE: "ag__.gteq_", } diff --git a/src/autoqasm/converters/return_statements.py b/src/autoqasm/converters/return_statements.py index c7d49a85..a9052889 100644 --- a/src/autoqasm/converters/return_statements.py +++ b/src/autoqasm/converters/return_statements.py @@ -16,7 +16,6 @@ import ast -import gast from malt.converters import return_statements from malt.core import ag_ctx, converter from malt.pyct import templates @@ -45,13 +44,13 @@ def visit_Return(self, node: ast.stmt) -> ast.stmt: ) name = constants.MAIN_RETURN_VAL_NAME - if isinstance(node.value, gast.Name): + if isinstance(node.value, ast.Name): name = node.value.id return templates.replace( template, name_=name, - name_const_=gast.Constant(name, None), + name_const_=ast.Constant(name, None), value_=node.value, original=node, ) diff --git a/src/autoqasm/transpiler/transpiler.py b/src/autoqasm/transpiler/transpiler.py index 61f2b8dd..a363b3cb 100644 --- a/src/autoqasm/transpiler/transpiler.py +++ b/src/autoqasm/transpiler/transpiler.py @@ -20,13 +20,13 @@ from __future__ import annotations +import ast import functools import importlib import inspect from collections.abc import Callable from typing import Any -import gast from malt.converters import ( asserts, call_trees, @@ -65,7 +65,7 @@ def __init__(self): super().__init__() self._extra_locals = None - def get_transformed_name(self, node: gast.Lambda | gast.FunctionDef) -> str: + def get_transformed_name(self, node: ast.Lambda | ast.FunctionDef) -> str: return "oq__" + super().get_transformed_name(node) def get_extra_locals(self) -> dict: @@ -95,8 +95,8 @@ def get_caching_key(self, ctx: ag_ctx.ControlStatusCtx) -> converter.ConversionO return ctx.options def _initial_analysis( - self, node: gast.Lambda | gast.FunctionDef, ctx: ag_ctx.ControlStatusCtx - ) -> gast.Lambda | gast.FunctionDef: + self, node: ast.Lambda | ast.FunctionDef, ctx: ag_ctx.ControlStatusCtx + ) -> ast.Lambda | ast.FunctionDef: graphs = cfg.build(node) node = qual_names.resolve(node) node = activity.resolve(node, ctx, None) @@ -110,8 +110,8 @@ def _initial_analysis( return node def transform_ast( - self, node: gast.Lambda | gast.FunctionDef, ctx: ag_ctx.ControlStatusCtx - ) -> gast.Lambda | gast.FunctionDef: + self, node: ast.Lambda | ast.FunctionDef, ctx: ag_ctx.ControlStatusCtx + ) -> ast.Lambda | ast.FunctionDef: """Performs an actual transformation of a function's AST. Args: @@ -147,7 +147,7 @@ def transform_ast( node = logical_expressions.transform(node, ctx) node = variables.transform(node, ctx) - return node # noqa: RET504 + return node def _convert_actual(entity: Callable, program_ctx: ag_ctx.ControlStatusCtx | None) -> Callable: diff --git a/test/unit_tests/autoqasm/mock_transpiler.py b/test/unit_tests/autoqasm/mock_transpiler.py index 3d81fd6a..7b992bb9 100644 --- a/test/unit_tests/autoqasm/mock_transpiler.py +++ b/test/unit_tests/autoqasm/mock_transpiler.py @@ -13,9 +13,9 @@ """Mock transpiler for testing converters.""" +import ast from typing import Union -import gast from malt.core import ag_ctx from autoqasm.transpiler import PyToOqpy @@ -37,8 +37,8 @@ def __init__(self, converters: list): self._converters = (converters,) def transform_ast( - self, node: Union[gast.Lambda, gast.FunctionDef], ctx: ag_ctx.ControlStatusCtx - ) -> Union[gast.Lambda, gast.FunctionDef]: + self, node: Union[ast.Lambda, ast.FunctionDef], ctx: ag_ctx.ControlStatusCtx + ) -> Union[ast.Lambda, ast.FunctionDef]: """Transform AST from a node using the provided converters. Args: node (Union[Lambda, FunctionDef]): One or more ast.AST nodes