def test_prints_to_std_err_with_warnings_true( tmp_path: Path, raise_warnings: bool, ) -> None: """ Expects ------- * Expects the warnings to be printed to stderr """ # We warn about memory limits being smaller than the limit # I tried a more direct approach by patching the __call__ but # that doesn't work as the wrapper __call__ then can not call # the real __call__ # By using raises=False, we don't have to worry about errors path = tmp_path / "tmp.txt" with path.open("w") as fn, redirect_stderr(fn): rf = Pynisher( f, warnings=raise_warnings, memory=(1, "KB"), raises=False, context="fork", # Only seems to work with fork context ) rf() with path.open("r") as fn: result = fn.readlines() assert any(result) == raise_warnings
def test_bad_func_arg() -> None: """ Expects ------- * Should raise an Error about a none callable bad memory limit """ with pytest.raises(ValueError, match=r"func"): Pynisher(func=None) # type: ignore
def test_success(context: str) -> None: """ Expects ------- * Should complete successfully if using less time than given """ with Pynisher(walltime_sleep, wall_time=5, context=context) as rf: rf(sleep=1)
def test_success(context: str) -> None: """ Expects ------- * Should raise no error and execute te function """ with Pynisher(busy_wait, cpu_time=4, context=context) as rf: print(rf(1))
def test_raises_false(context: str) -> None: """ Expects ------- * Should raise no error even though the restricted function did """ with Pynisher(raises_error, raises=False, context=context) as rf: rf()
def test_bad_memory_arg(memory: int) -> None: """ Expects ------- * Should raise an Error about a bad memory limit """ with pytest.raises(ValueError, match=r"memory"): Pynisher(get_process_id, memory=memory)
def test_cputime_no_raise_gets_empty(context: str) -> None: """ Expects ------- * No raise should return empty if there was a cputime out """ rf = Pynisher(busy_wait, cpu_time=1, raises=False, context=context) result = rf(10000) assert result is EMPTY
def test_walltime_no_raise_gets_empty(context: str) -> None: """ Expects ------- * No raise should return empty if there was a wall time limit reached """ rf = Pynisher(raises_error, wall_time=1, raises=False, context=context) result = rf() assert result is EMPTY
def test_no_raise_gets_empty(context: str) -> None: """ Expects ------- * Setting `raises=False` on a function that raises should return EMPTY """ rf = Pynisher(raises_error, raises=False, context=context) result = rf() assert result is EMPTY
def test_raises_true(context: str) -> None: """ Expects ------- * Should complete successfully if using less time than given """ with Pynisher(raises_error, raises=True, context=context) as rf: with pytest.raises(CustomException): rf(CustomException)
def test_memory_no_raise_gets_empty(context: str) -> None: """ Expects ------- * No raise should return empty if there was a memort limit reached """ rf = Pynisher(usememory, memory=(1, "B"), raises=False, context=context) result = rf((1, "mb")) assert result is EMPTY
def test_func_can_return_none(context: str) -> None: """ Expects ------- * A function return None should recieve None as the answer, making sure we don't accidentally eat it while processing everything. """ rf = Pynisher(return_none, context=context) result = rf() assert result is None
def test_fail(wall_time: int, context: str) -> None: """ Expects ------- * Should fail when the method uses more time than given """ with pytest.raises(TimeoutException): with Pynisher(walltime_sleep, wall_time=wall_time, context=context) as rf: rf(sleep=wall_time * 2)
def test_fail(context: str) -> None: """ Expects ------- * The Pynisher process should raise a CpuTimeoutException when exceeding the time limit """ with pytest.raises(CpuTimeoutException): with Pynisher(busy_wait, cpu_time=2, context=context) as rf: rf(20)
def test_raises_with_args(context: str) -> None: """ Expects ------- * Should be able to pass back args of an exception """ with Pynisher(raises_error, raises=True, context=context) as rf: with pytest.raises(CustomException) as e: rf(CustomException("apple")) assert e.value.args[0] == "apple"
def test_as_contextmanager(context: str) -> None: """ Expects ------- * Should be able to use as a context manager """ with Pynisher(get_process_id, context=context) as rf: other_process_id = rf() this_process_id = os.getpid() assert this_process_id != other_process_id
def test_bad_wall_time_arg(wall_time: int) -> None: """ Expects ------- * Should raise an Error about a bad wall_time limit """ def _f() -> None: pass with pytest.raises(ValueError, match=r"wall_time"): Pynisher(_f, wall_time=wall_time)
def test_bad_context_arg() -> None: """ Expects ------- * Should raise an Error about a bad context arg """ def _f() -> None: pass with pytest.raises(ValueError, match=r"context"): Pynisher(_f, context="bad arg")
def test_call(context: str) -> None: """ Expects ------- * Should be able to call the restricted function """ rf = Pynisher(get_process_id, context=context) this_process_id = os.getpid() other_process_id = rf() assert this_process_id != other_process_id
def test_memory_limit(context: str) -> None: """ Expects ------- * With a cputime limit set and a memory limit set, allocating too much memory should still raise a MemoryLimitException """ mem_limit = (100, "MB") cputime_limit = 100 allocate_mem = (200, "MB") with pytest.raises(MemoryLimitException): with Pynisher( usememory, memory=mem_limit, cpu_time=cputime_limit, context=context, ) as rf: rf(allocate_mem)
def test_cputime_limit(context: str) -> None: """ Expects ------- * With a cputime limit set and a memory limit set, spending too long computing should raise a cpu time limit """ mem_limit = (500, "MB") cputime_limit = 2 busy = 10 with pytest.raises(CpuTimeoutException): with Pynisher( busy_wait, memory=mem_limit, cpu_time=cputime_limit, context=context, ) as rf: rf(busy)
def test_success(limit: int, context: str) -> None: """Using less than the allocated memory should be fine Processes take up some amount of memory natively, e.g. 37MB was preallocated for my own run on Linx where "fork" is used. Hence, we skip if the test limit is not enough """ allocate = int(limit / 3) current_usage = Monitor().memory("MB") expected_usage = current_usage + allocate if expected_usage > limit: msg = ( f"Limit {limit}MB is too low as the current usage is {current_usage}MB" f" with another {allocate}MB being allocated. This will total " f" {expected_usage}MB, over the limit.") pytest.skip(msg) rf = Pynisher(usememory, memory=(limit, "MB"), context=context) rf((allocate, "MB"))
def test_fail(limit: int, context: str) -> None: """Using more than the allocated memory should raise an Error""" rf = Pynisher(usememory, memory=(limit, "MB"), context=context) with pytest.raises(MemoryLimitException): rf((limit * 3, "MB"))