def test_stack_frame_basic(self): plan = uberjob.Plan() stack_frame = get_stack_frame(1) x = plan.call(operator.truediv, 1, 0) with self.assert_call_exception( expected_stack_frame=copy_with_line_offset(stack_frame, 1) ): uberjob.run(plan, output=x)
def test_stack_frame_registry_add(self): plan = uberjob.Plan() registry = uberjob.Registry() x = plan.call(operator.add, 2, 2) stack_frame = get_stack_frame(1) registry.add(x, TestStore(can_write=False)) with self.assert_call_exception( expected_stack_frame=copy_with_line_offset(stack_frame, 1)): uberjob.run(plan, registry=registry, output=x)
def test_stack_frame_registry_source(self): plan = uberjob.Plan() registry = uberjob.Registry() stack_frame = get_stack_frame(1) x = registry.source(plan, TestStore()) with self.assert_call_exception( expected_stack_frame=copy_with_line_offset(stack_frame, 1)): uberjob.run(plan, output=x) with self.assert_call_exception( expected_stack_frame=copy_with_line_offset(stack_frame, 1)): uberjob.run(plan, registry=registry, output=x)
def add(self, node: Node, value_store: ValueStore) -> None: """ Assign a :class:`~uberjob.graph.Node` to a :class:`~uberjob.ValueStore`. :param node: The plan node. :param value_store: The value store for the node. """ validation.assert_is_instance(node, "node", Node) validation.assert_is_instance(value_store, "value_store", ValueStore) if node in self.mapping: raise Exception("The node already has a value store.") self.mapping[node] = RegistryValue(value_store, is_source=False, stack_frame=get_stack_frame())
def gather(self, value) -> Node: """ Gather a structured value that may contain instances of :class:`~uberjob.graph.Node` into a single :class:`~uberjob.graph.Node` representing the entire structured value. If the value is already a :class:`~uberjob.graph.Node`, it will be returned unchanged. When navigating the structured value, gather will only recognize Python's general purpose built-in containers: :class:`dict`, :class:`list`, :class:`set`, and :class:`tuple`. :param value: A structured value that may contain instances of :class:`~uberjob.graph.Node`. :return: A single :class:`~uberjob.graph.Node` representing the gathered input value. """ return self._gather(get_stack_frame(), value)
def call(self, fn: Callable, *args, **kwargs) -> Call: """ Add a function call to this :class:`~uberjob.Plan`. Non-symbolic arguments are automatically converted to symbolic arguments using :func:`~uberjob.Plan.gather`. :param fn: The function to be called. :param args: The symbolic positional arguments. :param kwargs: The symbolic keyword arguments. :return: The symbolic result of the function call. :raises TypeError: If arguments fail to bind to parameters. """ validation.assert_is_callable(fn, "fn") validation.assert_can_bind(fn, *args, **kwargs) return self._call(get_stack_frame(), fn, *args, **kwargs)
def unpack(self, iterable, length: int) -> Tuple[Node, ...]: """ Unpack a symbolic iterable into a tuple of symbolic values. :param iterable: The symbolic iterable. :param length: The number of values in the iterable. :return: A tuple of :class:`~uberjob.graph.Node`. """ if not isinstance(length, int) or length < 0: raise ValueError("length must be a non-negative integer.") stack_frame = get_stack_frame() t = self._call(stack_frame, _builtins.unpack, iterable, length) return tuple( self._call(stack_frame, operator.getitem, t, index) for index in range(length))
def source(self, plan: Plan, value_store: ValueStore) -> Node: """ Create a :class:`~uberjob.graph.Node` in the :class:`~uberjob.Plan` that reads from the given :class:`~uberjob.ValueStore`. :param plan: The plan to add a source node to. :param value_store: The value store to read from. :return: The newly added plan node. """ validation.assert_is_instance(plan, "plan", Plan) validation.assert_is_instance(value_store, "value_store", ValueStore) stack_frame = get_stack_frame() node = plan._call(stack_frame, source) self.mapping[node] = RegistryValue(value_store, is_source=True, stack_frame=stack_frame) return node
def test_stack_frame_function(self): stack_frame1 = get_stack_frame(1) stack_frame2 = get_stack_frame(1) self.assertEqual(stack_frame1.path, __file__) self.assertEqual(stack_frame1.line + 1, stack_frame2.line)