def test_no_parameter_with_name(self): @fixed("dne") def func(a, b, c): return assert func.fixed == {"dne": True} # Test Operation API with pytest.raises(ValidationError): operation(func)
def test_extra_input_names(self): # Test when there are more input names given that there are function args @input_names("first", "second", "third", "fourth") def my_sum(x, y): return x + y assert my_sum.input_names == ("first", "second", "third", "fourth") # Test the Operation API with pytest.raises(ValidationError): operation(my_sum)
def test_missing_output_name(self): # TODO: what should the expected shape be? A collection (list/tuple)? @output_shape("out", (10, 10)) def func(a) -> np.ndarray: return np.zeros(shape=(10, 10)) assert func.output_shape == {"out": (10, 10)} # Test Operation API with pytest.raises(ValidationError): operation(func)
def test_fewer_input_names(self): # Test when there are fewer input names given than there are function args @input_names("first") def my_sum(x, y): return x + y assert my_sum.input_names == ("first", ) # Test the Operation API with pytest.raises(ValidationError): operation(my_sum)
def test_auto_connect_all_only_matching_types(self, graph): def my_increment(n: int) -> int: return n + 1 def my_decrement(m: int) -> int: return m - 1 increment_op = operation(my_increment, output_names=("increment", ))() decrement_op = operation(my_decrement, output_names=("decrement", ))() graph.add_operations(increment_op, decrement_op) graph.auto_connect_all() assert graph.links() == []
def test_auto_connect_all_matching_names_and_types(self, graph): def my_increment(n: int) -> int: return n + 1 def my_decrement(increment: int) -> int: return increment - 1 increment_op = operation(my_increment, output_names=("increment",))() decrement_op = operation(my_decrement, output_names=("end_result",))() graph.add_operations(increment_op, decrement_op) graph.auto_connect_all() assert graph.links() == [(increment_op, decrement_op, "increment", "increment")]
def test_operation_links_multiple(self, sum_op, square_op, negative_op): # # (y) --> (n1) # my_func sum (n) --> (num) square # (x) --> (n2) # def my_func(x: int, y: int) -> (int, int): return y, x my_op = operation(my_func, output_names=("y", "x"))() workflow = Workflow() # workflow.add_operations(sum_op, square_op, negative_op, my_op) workflow.add_operations(my_op, sum_op, square_op, negative_op) link1 = (my_op, sum_op, "y", "n1") link2 = (my_op, sum_op, "x", "n2") link3 = (sum_op, square_op, "sum", "n") link4 = (square_op, negative_op, "square", "num") workflow.add_link(my_op, sum_op, "y", "n1") workflow.add_link(my_op, sum_op, "x", "n2") workflow.add_link(sum_op, square_op, "sum", "n") workflow.add_link(square_op, negative_op, "square", "num") # assert workflow.operation_links(my_op) == [link1, link2] # assert workflow.operation_links(sum_op) == [link3] # assert workflow.operation_links(square_op) == [link4] # assert workflow.operation_links(negative_op) == [] workflow._pretty_print() dask_graph, end_ids = workflow.as_dask_graph() # test execution results = workflow.execute_synchronous(x=3, y=5)
def test_add_multiple_links(self, graph, sum_op, square_op): graph.add_operation(sum_op) graph.add_operation(square_op) import math def my_sqrt(num): return math.sqrt(num) sqrt_op = operation(my_sqrt, output_names=("sqrt"))() graph.add_operation(sqrt_op) # sum -> square -> sqrt # \ | # -------->------ graph.add_link(source=sum_op, dest=square_op, source_param="sum", dest_param="n") graph.add_link(source=square_op, dest=sqrt_op, source_param="square", dest_param="num") graph.add_link(source=sum_op, dest=sqrt_op, source_param="sum", dest_param="num") # sum -> square assert graph.get_inbound_links(sum_op)[square_op] == [] assert graph.get_outbound_links(sum_op)[square_op] == [("sum", "n")] assert graph.get_inbound_links(square_op)[sum_op] == [("sum", "n")] assert graph.get_outbound_links(square_op)[sum_op] == [] # square -> sqrt assert graph.get_inbound_links(square_op)[sqrt_op] == [] assert graph.get_outbound_links(square_op)[sqrt_op] == [("square", "num")] assert graph.get_inbound_links(sqrt_op)[square_op] == [("square", "num")] assert graph.get_outbound_links(sqrt_op)[square_op] == [] # sum -> sqrt assert graph.get_inbound_links(sum_op)[sqrt_op] == [] assert graph.get_outbound_links(sum_op)[sqrt_op] == [("sum", "num")] assert graph.get_inbound_links(sqrt_op)[sum_op] == [("sum", "num")] assert graph.get_outbound_links(sqrt_op)[sum_op] == []
def test_defaults(self): def func(a): return assert not hasattr(func, "name") # Test Operation API op = operation(func) assert op.name == func.__name__
def test_defaults(self): def func(a): return assert not hasattr(func, "opts") # Test Operation API op = operation(func) assert op.opts == {}
def test_defaults(self): # Test not using the input_names decorator def my_op(x, y): return x + y assert hasattr(my_op, "input_names") is False # Test Operation API op = operation(my_op) assert op.input_names == ("x", "y")
def test_output_names(self): @output_names("sum") def my_sum(a, b): return np.sum(a, b) assert my_sum.output_names == ("sum", ) # Test Operation API op = operation(my_sum) assert op.output_names == ("sum", )
def test_limits(self): @limits("a", [0.0, 1.0]) def func(a): return assert func.limits == {"a": [0.0, 1.0]} # Test Operation API op = operation(func) assert op.limits == {"a": [0.0, 1.0]}
def test_output_names_tuple(self): @output_names("x", "y") def my_solution(n): return n, -1 * n assert my_solution.output_names == ("x", "y") # Test operation API op = operation(my_solution) assert op.output_names == ("x", "y")
def test_default(self): @visible('a') def func(a, b): return assert func.visible == {'a': True} # Test Operations API op = operation(func) assert op.visible == {'a': True}
def test_units(self): @units('a', 'mm') def func(a): return assert func.units == {'a': 'mm'} # Test Operation API op = operation(func) assert op.units == {'a': 'mm'}
def test_single(self): @fixed("a") def func(a, b): return assert func.fixed == {"a": True} # Test Operation API op = operation(func) assert op.fixed == {"a": True}
def test_false(self): @visible("a", False) def func(a, b): return assert func.visible == {"a": False} # Test Operations API op = operation(func) assert op.visible == {"a": False}
def test_defaults(self): def func(a, b): return # assert func.fixed == {} assert not hasattr(func, "fixed") # Test Operation API op = operation(func) assert op.fixed == {}
def test_true(self): @visible("a", True) def func(a, b): return assert func.visible == {"a": True} # Test Operations API op = operation(func) assert op.visible == {"a": True}
def test_display_name(self): @display_name("my operation name") def func(a): return assert func.name == "my operation name" # Test Operation API op = operation(func) assert op.name == "my operation name"
def test_units(self): @units("a", "mm") def func(a): return assert func.units == {"a": "mm"} # Test Operation API op = operation(func) assert op.units == {"a": "mm"}
def test_opts(self): # TODO: what happens if you pass in an 'invalid' opt? what is an invalid opt? @opts('a', someopt='opt') def func(a, b): return assert func.opts == {'a': {'someopt': 'opt'}} # Test Operation API op = operation(func) assert op.opts == {'a': {'someopt': 'opt'}}
def test_redundant(self): @fixed("b") @fixed("b") def func(a, b, c): return assert func.fixed == {"b": True} # Test Operation API op = operation(func) assert op.fixed == {"b": True}
def test_explicit(self): @fixed("a", True) @fixed("b", False) def func(a, b, c): return assert func.fixed == {"a": True, "b": False} # Test Operation API op = operation(func) assert op.fixed == {"a": True, "b": False}
def test_multiple(self): @fixed("a") @fixed("b") def func(a, b, c): return assert func.fixed == {"a": True, "b": True} # Test Operation API op = operation(func) assert op.fixed == {"a": True, "b": True}
def test_opts(self): # TODO: what happens if you pass in an 'invalid' opt? what is an invalid opt? @opts("a", someopt="opt") def func(a, b): return assert func.opts == {"a": {"someopt": "opt"}} # Test Operation API op = operation(func) assert op.opts == {"a": {"someopt": "opt"}}
def test_explicit(self): @fixed('a', True) @fixed('b', False) def func(a, b, c): return assert func.fixed == {'a': True, 'b': False} # Test Operation API op = operation(func) assert op.fixed == {'a': True, 'b': False}
def test_matching_number_of_names(self): # Test a good use of the input_names decorator @input_names("first", "second") def my_sum(x, y): return x + y assert my_sum.input_names == ("first", "second") # Test the Operation API op = operation(my_sum) assert op.input_names == ("first", "second")
def test_multiple(self): @fixed('a') @fixed('b') def func(a, b, c): return assert func.fixed == {'a': True, 'b': True} # Test Operation API op = operation(func) assert op.fixed == {'a': True, 'b': True}