Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,39 @@ def run_ci_historic_benchmark():
build_wheel(python_bin, pip_src, env=pip_env)
step_end()

if run_tests:
# The qsharp shim tests require qdk (with its native extension) to be
# installed. If qdk was built in this run it is already available;
# otherwise check the environment.
qdk_available = build_qdk
if not qdk_available:
python_bin_check, _ = use_python_env(qdk_python_src)
result = subprocess.run(
[python_bin_check, "-c", "import qdk"],
capture_output=True,
)
qdk_available = result.returncode == 0

if qdk_available:
step_start("Running tests for the qsharp compatibility shim")
# Use the qdk environment where qdk and test deps are already installed.
python_bin, pip_env = use_python_env(qdk_python_src)

if not args.editable:
install_from_wheels(python_bin, "qsharp", cwd=pip_src)

run_python_tests(
os.path.join(pip_src, "tests"),
python_bin,
pip_env,
)
step_end()
else:
print(
"Skipping qsharp shim tests: qdk is not installed. "
"Run with --qdk or install qdk first."
)


if build_widgets:
step_start("Building the Python widgets")
Expand Down
93 changes: 93 additions & 0 deletions source/pip/tests/test_qsharp_shim.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

"""Tests for the ``qsharp`` compatibility shim.

The ``qsharp`` package is a thin deprecation wrapper that re-exports the
public API from ``qdk``. These tests verify that the expected symbols and
submodules are accessible via ``import qsharp``.
"""

import importlib
import warnings

import pytest

# ---- Symbols that must be directly accessible on ``qsharp`` ----

_EXPECTED_SYMBOLS = [
# functions
"init",
"eval",
"run",
"compile",
"circuit",
"estimate",
"estimate_custom",
"logical_counts",
"set_quantum_seed",
"set_classical_seed",
"dump_machine",
"dump_circuit",
# types / classes
"Result",
"Pauli",
"QSharpError",
"TargetProfile",
"StateDump",
"ShotResult",
"PauliNoise",
"DepolarizingNoise",
"BitFlipNoise",
"PhaseFlipNoise",
"CircuitGenerationMethod",
]

# Submodules that must be importable *and* accessible as attributes
# on the ``qsharp`` module after a bare ``import qsharp``.
_EXPECTED_SUBMODULES = [
"code",
"estimator",
]


@pytest.fixture()
def qsharp_module():
"""Import the ``qsharp`` shim while suppressing the deprecation warning."""
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
mod = importlib.import_module("qsharp")
return mod


def test_deprecation_warning_on_import():
"""Importing ``qsharp`` must emit a DeprecationWarning."""
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
importlib.reload(importlib.import_module("qsharp"))

deprecations = [w for w in caught if issubclass(w.category, DeprecationWarning)]
assert any("qsharp" in str(w.message) for w in deprecations)


@pytest.mark.parametrize("name", _EXPECTED_SYMBOLS)
def test_symbol_accessible(qsharp_module, name):
"""Every expected symbol must be an attribute of ``qsharp``."""
assert hasattr(qsharp_module, name), f"qsharp.{name} is missing"


@pytest.mark.parametrize("name", _EXPECTED_SUBMODULES)
def test_submodule_accessible_as_attribute(qsharp_module, name):
"""Submodules like ``code`` must be reachable via ``qsharp.<name>``
without a separate ``from qsharp import <name>``."""
attr = getattr(qsharp_module, name, None)
assert attr is not None, f"qsharp.{name} is not accessible as an attribute"


@pytest.mark.parametrize("name", _EXPECTED_SUBMODULES)
def test_submodule_importable(name):
"""``from qsharp import <submodule>`` must work."""
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
mod = importlib.import_module(f"qsharp.{name}")
assert mod is not None
Loading