Skip to content

Commit

Permalink
Change name from env to code
Browse files Browse the repository at this point in the history
  • Loading branch information
swernli committed Dec 11, 2024
1 parent 301a389 commit bd50c86
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 69 deletions.
3 changes: 1 addition & 2 deletions pip/qsharp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

telemetry_events.on_import()

from ._native import Result, Pauli, QSharpError, TargetProfile, GlobalCallable
from ._native import Result, Pauli, QSharpError, TargetProfile

# IPython notebook specific features
try:
Expand Down Expand Up @@ -57,5 +57,4 @@
"DepolarizingNoise",
"BitFlipNoise",
"PhaseFlipNoise",
"GlobalCallable",
]
16 changes: 8 additions & 8 deletions pip/qsharp/_qsharp.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

from . import telemetry_events, env
from . import telemetry_events, code
from ._native import (
Interpreter,
TargetProfile,
Expand Down Expand Up @@ -195,18 +195,18 @@ def init(
# Loop through the environment module and remove any dynamically added attributes that represent
# Q# callables. This is necessary to avoid conflicts with the new interpreter instance.
keys_to_remove = []
for key in env.__dict__:
if hasattr(env.__dict__[key], "__qs_gen") or isinstance(
env.__dict__[key], types.ModuleType
for key in code.__dict__:
if hasattr(code.__dict__[key], "__qs_gen") or isinstance(
code.__dict__[key], types.ModuleType
):
keys_to_remove.append(key)
for key in keys_to_remove:
env.__delattr__(key)
code.__delattr__(key)

# Also remove any namespace modules dynamically added to the system.
keys_to_remove = []
for key in sys.modules:
if key.startswith("qsharp.env."):
if key.startswith("qsharp.code."):
keys_to_remove.append(key)
for key in keys_to_remove:
sys.modules.__delitem__(key)
Expand Down Expand Up @@ -278,10 +278,10 @@ def callback(output: Output) -> None:
# used by the underlying native code to create functions for callables on the fly that know
# how to get the currently intitialized global interpreter instance.
def _make_callable(callable, namespace, callable_name):
module = env
module = code
# Create a name that will be used to collect the hierachy of namespace identifiers if they exist and use that
# to register created modules with the system.
accumulated_namespace = "qsharp.env"
accumulated_namespace = "qsharp.code"
accumulated_namespace += "."
for name in namespace:
accumulated_namespace += name
Expand Down
6 changes: 6 additions & 0 deletions pip/qsharp/code/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

"""
Code module that receives any user-defined Q# callables as Python functions.
"""
4 changes: 0 additions & 4 deletions pip/qsharp/env/__init__.py

This file was deleted.

110 changes: 55 additions & 55 deletions pip/tests/test_qsharp.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import pytest
import qsharp
import qsharp.env
import qsharp.code
import qsharp.utils
from contextlib import redirect_stdout
import io
Expand Down Expand Up @@ -381,21 +381,21 @@ def test_target_profile_from_str_match_enum_values() -> None:
def test_callables_exposed_into_env() -> None:
qsharp.init()
qsharp.eval("function Four() : Int { 4 }")
assert qsharp.env.Four() == 4, "callable should be available"
assert qsharp.code.Four() == 4, "callable should be available"

Check notice

Code scanning / devskim

If untrusted data (data from HTTP requests, user submitted files, etc.) is included in an eval statement it can allow an attacker to inject their own code. Note test

Review eval for untrusted data
qsharp.eval("function Add(a : Int, b : Int) : Int { a + b }")
assert qsharp.env.Four() == 4, "first callable should still be available"
assert qsharp.env.Add(2, 3) == 5, "second callable should be available"
assert qsharp.code.Four() == 4, "first callable should still be available"
assert qsharp.code.Add(2, 3) == 5, "second callable should be available"
# After init, the callables should be cleared and no longer available
qsharp.init()
with pytest.raises(AttributeError):
qsharp.env.Four()
qsharp.code.Four()


def test_callable_exposed_into_env_complex_types() -> None:
qsharp.eval(
"function Complicated(a : Int, b : (Double, BigInt)) : ((Double, BigInt), Int) { (b, a) }"
)
assert qsharp.env.Complicated(2, (3.0, 4000000000000000000000)) == (
assert qsharp.code.Complicated(2, (3.0, 4000000000000000000000)) == (
(3.0, 4000000000000000000000),
2,
), "callables that take complex types should marshall them correctly"
Expand All @@ -405,103 +405,103 @@ def test_callable_exposed_into_env_with_array() -> None:
qsharp.init()
qsharp.eval("function Smallest(a : Int[]) : Int { Std.Math.Min(a)}")

Check notice

Code scanning / devskim

If untrusted data (data from HTTP requests, user submitted files, etc.) is included in an eval statement it can allow an attacker to inject their own code. Note test

Review eval for untrusted data
assert (
qsharp.env.Smallest([1, 2, 3, 0, 4, 5]) == 0
qsharp.code.Smallest([1, 2, 3, 0, 4, 5]) == 0
), "callable that takes array should work"


def test_callable_with_int_exposed_into_env_fails_incorrect_types() -> None:
qsharp.init()
qsharp.eval("function Identity(a : Int) : Int { a }")
assert qsharp.env.Identity(4) == 4
assert qsharp.code.Identity(4) == 4
with pytest.raises(TypeError):
qsharp.env.Identity("4")
qsharp.code.Identity("4")
with pytest.raises(TypeError):
qsharp.env.Identity(4.0)
qsharp.code.Identity(4.0)
with pytest.raises(OverflowError):
qsharp.env.Identity(4000000000000000000000)
qsharp.code.Identity(4000000000000000000000)
with pytest.raises(TypeError):
qsharp.env.Identity([4])
qsharp.code.Identity([4])


def test_callable_with_double_exposed_into_env_fails_incorrect_types() -> None:
qsharp.init()
qsharp.eval("function Identity(a : Double) : Double { a }")
assert qsharp.env.Identity(4.0) == 4.0
assert qsharp.env.Identity(4) == 4.0
assert qsharp.code.Identity(4.0) == 4.0
assert qsharp.code.Identity(4) == 4.0
with pytest.raises(TypeError):
qsharp.env.Identity("4")
qsharp.code.Identity("4")
with pytest.raises(TypeError):
qsharp.env.Identity([4])
qsharp.code.Identity([4])


def test_callable_with_bigint_exposed_into_env_fails_incorrect_types() -> None:
qsharp.init()
qsharp.eval("function Identity(a : BigInt) : BigInt { a }")
assert qsharp.env.Identity(4000000000000000000000) == 4000000000000000000000
assert qsharp.code.Identity(4000000000000000000000) == 4000000000000000000000
with pytest.raises(TypeError):
qsharp.env.Identity("4")
qsharp.code.Identity("4")
with pytest.raises(TypeError):
qsharp.env.Identity(4.0)
qsharp.code.Identity(4.0)


def test_callable_with_string_exposed_into_env_fails_incorrect_types() -> None:
qsharp.init()
qsharp.eval("function Identity(a : String) : String { a }")
assert qsharp.env.Identity("4") == "4"
assert qsharp.code.Identity("4") == "4"
with pytest.raises(TypeError):
qsharp.env.Identity(4)
qsharp.code.Identity(4)
with pytest.raises(TypeError):
qsharp.env.Identity(4.0)
qsharp.code.Identity(4.0)
with pytest.raises(TypeError):
qsharp.env.Identity([4])
qsharp.code.Identity([4])


def test_callable_with_bool_exposed_into_env_fails_incorrect_types() -> None:
qsharp.init()
qsharp.eval("function Identity(a : Bool) : Bool { a }")
assert qsharp.env.Identity(True) == True
assert qsharp.code.Identity(True) == True
with pytest.raises(TypeError):
qsharp.env.Identity("4")
qsharp.code.Identity("4")
with pytest.raises(TypeError):
qsharp.env.Identity(4)
qsharp.code.Identity(4)
with pytest.raises(TypeError):
qsharp.env.Identity(4.0)
qsharp.code.Identity(4.0)
with pytest.raises(TypeError):
qsharp.env.Identity([4])
qsharp.code.Identity([4])


def test_callable_with_array_exposed_into_env_fails_incorrect_types() -> None:
qsharp.init()
qsharp.eval("function Identity(a : Int[]) : Int[] { a }")

Check notice

Code scanning / devskim

If untrusted data (data from HTTP requests, user submitted files, etc.) is included in an eval statement it can allow an attacker to inject their own code. Note test

Review eval for untrusted data
assert qsharp.env.Identity([4, 5, 6]) == [4, 5, 6]
assert qsharp.env.Identity([]) == []
assert qsharp.env.Identity((4, 5, 6)) == [4, 5, 6]
assert qsharp.code.Identity([4, 5, 6]) == [4, 5, 6]
assert qsharp.code.Identity([]) == []
assert qsharp.code.Identity((4, 5, 6)) == [4, 5, 6]
with pytest.raises(TypeError):
qsharp.env.Identity(4)
qsharp.code.Identity(4)
with pytest.raises(TypeError):
qsharp.env.Identity("4")
qsharp.code.Identity("4")
with pytest.raises(TypeError):
qsharp.env.Identity(4.0)
qsharp.code.Identity(4.0)
with pytest.raises(TypeError):
qsharp.env.Identity([1, 2, 3.0])
qsharp.code.Identity([1, 2, 3.0])


def test_callable_with_tuple_exposed_into_env_fails_incorrect_types() -> None:
qsharp.init()
qsharp.eval("function Identity(a : (Int, Double)) : (Int, Double) { a }")
assert qsharp.env.Identity((4, 5.0)) == (4, 5.0)
assert qsharp.env.Identity((4, 5)) == (4, 5.0)
assert qsharp.env.Identity([4, 5.0]) == (4, 5.0)
assert qsharp.code.Identity((4, 5.0)) == (4, 5.0)
assert qsharp.code.Identity((4, 5)) == (4, 5.0)
assert qsharp.code.Identity([4, 5.0]) == (4, 5.0)
with pytest.raises(qsharp.QSharpError):
qsharp.env.Identity((4, 5, 6))
qsharp.code.Identity((4, 5, 6))
with pytest.raises(TypeError):
qsharp.env.Identity(4)
qsharp.code.Identity(4)
with pytest.raises(TypeError):
qsharp.env.Identity("4")
qsharp.code.Identity("4")
with pytest.raises(TypeError):
qsharp.env.Identity(4.0)
qsharp.code.Identity(4.0)
with pytest.raises(TypeError):
qsharp.env.Identity([4.0, 5])
qsharp.code.Identity([4.0, 5])


def test_callables_in_namespaces_exposed_into_env_submodules_and_removed_on_reinit() -> (
Expand All @@ -512,17 +512,17 @@ def test_callables_in_namespaces_exposed_into_env_submodules_and_removed_on_rein
qsharp.eval("namespace Test { function Four() : Int { 4 } }")
qsharp.eval("function Identity(a : Int) : Int { a }")
# should be able to import callables from env and namespace submodule
from qsharp.env import Identity
from qsharp.env.Test import Four
from qsharp.code import Identity
from qsharp.code.Test import Four

assert Identity(4) == 4
assert Four() == 4
qsharp.init()
# namespaces should be removed
with pytest.raises(AttributeError):
qsharp.env.Test
qsharp.code.Test
with pytest.raises(AttributeError):
qsharp.env.Identity()
qsharp.code.Identity()
# imported callables should fail gracefully
with pytest.raises(qsharp.QSharpError):
Four()
Expand All @@ -532,21 +532,21 @@ def test_callables_with_unsupported_types_raise_errors_on_call() -> None:
qsharp.init()
qsharp.eval("function Unsupported(a : Int, q : Qubit) : Unit { }")
with pytest.raises(qsharp.QSharpError, match="unsupported input type: `Qubit`"):
qsharp.env.Unsupported()
qsharp.code.Unsupported()


def test_callables_with_unsupported_types_in_tuples_raise_errors_on_call() -> None:
qsharp.init()
qsharp.eval("function Unsupported(q : (Int, Qubit)[]) : Unit { }")
with pytest.raises(qsharp.QSharpError, match="unsupported input type: `Qubit`"):
qsharp.env.Unsupported()
qsharp.code.Unsupported()


def test_callables_with_unsupported_return_types_raise_errors_on_call() -> None:
qsharp.init()
qsharp.eval('function Unsupported() : Qubit { fail "won\'t be called" }')
with pytest.raises(qsharp.QSharpError, match="unsupported output type: `Qubit`"):
qsharp.env.Unsupported()
qsharp.code.Unsupported()


def test_callables_with_unsupported_udt_types_raise_errors_on_call() -> None:
Expand All @@ -555,7 +555,7 @@ def test_callables_with_unsupported_udt_types_raise_errors_on_call() -> None:
with pytest.raises(
qsharp.QSharpError, match='unsupported input type: `UDT<"Complex":'
):
qsharp.env.Unsupported()
qsharp.code.Unsupported()


def test_callable_with_unsupported_udt_return_types_raise_errors_on_call() -> None:
Expand All @@ -564,19 +564,19 @@ def test_callable_with_unsupported_udt_return_types_raise_errors_on_call() -> No
with pytest.raises(
qsharp.QSharpError, match='unsupported output type: `UDT<"Complex":'
):
qsharp.env.Unsupported()
qsharp.code.Unsupported()


def test_struct_call_constructor_not_exposed_into_env() -> None:
qsharp.init()
qsharp.eval("struct CustomUDT { a : Int }")
with pytest.raises(AttributeError):
qsharp.env.CustomUDT
qsharp.code.CustomUDT


def test_lambdas_not_exposed_into_env() -> None:
qsharp.init()
qsharp.eval("a -> a + 1")

Check notice

Code scanning / devskim

If untrusted data (data from HTTP requests, user submitted files, etc.) is included in an eval statement it can allow an attacker to inject their own code. Note test

Review eval for untrusted data
assert not hasattr(qsharp.env, "<lambda>")
assert not hasattr(qsharp.code, "<lambda>")
qsharp.eval("q => I(q)")

Check notice

Code scanning / devskim

If untrusted data (data from HTTP requests, user submitted files, etc.) is included in an eval statement it can allow an attacker to inject their own code. Note test

Review eval for untrusted data
assert not hasattr(qsharp.env, "<lambda>")
assert not hasattr(qsharp.code, "<lambda>")

0 comments on commit bd50c86

Please sign in to comment.