diff --git a/CHANGELOG.md b/CHANGELOG.md index a186e759..e1ce1b8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ Types of changes: ### Removed ### Fixed +- Fixed `loads("")` / whitespace-only input raising `AttributeError` instead of `ValidationError`. Empty and whitespace programs now raise `ValidationError` like other parse failures. ([#451](https://github.com/qBraid/pyqasm/pull/451), [#437](https://github.com/qBraid/pyqasm/issues/437)) ### Dependencies diff --git a/src/pyqasm/entrypoint.py b/src/pyqasm/entrypoint.py index 00aaf2db..7e55ea3e 100644 --- a/src/pyqasm/entrypoint.py +++ b/src/pyqasm/entrypoint.py @@ -182,7 +182,8 @@ def loads(program: openqasm3.ast.Program | str, **kwargs) -> QasmModule: program, opaque_gates = rewrite_opaque_declarations(program) try: program = openqasm3.parse(program) - except openqasm3.parser.QASM3ParsingError as err: + except (openqasm3.parser.QASM3ParsingError, AttributeError) as err: + # openqasm3 can raise AttributeError on empty/whitespace-only input raise ValidationError(f"Failed to parse OpenQASM string: {err}") from err elif not isinstance(program, openqasm3.ast.Program): raise TypeError("Input quantum program must be of type 'str' or 'openqasm3.ast.Program'.") diff --git a/tests/qasm3/test_entrypoint.py b/tests/qasm3/test_entrypoint.py index 4fa791e9..11d52532 100644 --- a/tests/qasm3/test_entrypoint.py +++ b/tests/qasm3/test_entrypoint.py @@ -74,3 +74,17 @@ def test_incorrect_module_unroll_raises_error(): with pytest.raises(ValidationError): module = loads("OPENQASM 3.0;\n qubit q; h q[2]") module.unroll() + + +def test_loads_empty_string_raises_validation_error(): + """Empty / whitespace-only input must raise ValidationError, not AttributeError.""" + for program in ("", " ", "\n\t"): + with pytest.raises(ValidationError, match="Failed to parse OpenQASM string"): + loads(program) + + +def test_loads_header_only_module_ok(): + """A header-only OpenQASM 3 program (no statements) remains valid.""" + module = loads("OPENQASM 3.0;\n") + assert module.num_qubits == 0 + assert module.num_clbits == 0