コード例 #1
0
ファイル: test_sklearn_train.py プロジェクト: automl/pynisher
def test_train_svr_cputime(context: str) -> None:
    """
    Expects
    -------
    * Limiting cputime should result in a CpuTimeoutException
    """
    from sklearn.datasets import make_regression
    from sklearn.svm import SVR

    model = SVR()
    X, y = make_regression(n_samples=30_000, n_features=128)

    cpu_limit = (2, "s")
    lf = limit(train_svr, cpu_time=cpu_limit)

    completed = False
    with pytest.raises(CpuTimeoutException):
        completed = lf(model, X, y, cpu_limit)

    time.sleep(1)
    assert completed is not True
    assert lf._process is not None and not lf._process.is_running()

    try:
        children = lf._process.children()
        assert not any(children)
    except psutil.NoSuchProcess:
        pass
コード例 #2
0
def test_import_fail_windows() -> None:
    """
    Expects
    -------
    * Should fail to import if the memory limit is too low

    Note
    ----
    For sklearn on windows, this triggers an OSError with code 22 and winerr 1455
    and so we have to be aware of it before hand.
    There's no automatic way to identfiy this from a regular OSError so we better
    be explicit about it.
    """
    m = Monitor()
    print("Before job ", m.memory("mb"))
    try:
        with limit(
                import_sklearn,
                memory=(100, "mb"),
                wrap_errors={"memory": [(OSError, 22, 1455)]},
        ) as lf:
            lf()
    except MemoryLimitException:
        pass
    except Exception as e:
        print(e, type(e))
        raise e
コード例 #3
0
def test_import_with_enough_memory() -> None:
    """
    Expects
    -------
    * Should import without a problem given enough memory
    """
    with limit(import_sklearn, memory=(1, "GB")) as lf:
        assert lf() is True
コード例 #4
0
def test_import_fail_mac() -> None:
    """
    Expects
    -------
    * Should fail to import if the memory limit is too low
    """
    with pytest.raises(MemoryLimitException):
        with limit(import_sklearn, memory=(100, "mb")) as lf:
            lf()
コード例 #5
0
def test_limit_usage(context: str) -> None:
    """
    Expects
    -------
    * Should be able to use in the `limit` api usage
    """
    with limit(get_process_id, context=context) as rf:
        this_process_id = os.getpid()
        other_process_id = rf()

    assert this_process_id != other_process_id
コード例 #6
0
ファイル: test_import.py プロジェクト: automl/pynisher
def test_import_large_module(context: str) -> None:
    """
    Expects
    -------
    * A MemoryLimitException should be raised import a module that's too big

    Note
    ----
    The module just consists of a bytearray of 200mb
    """
    with pytest.raises(MemoryLimitException):
        with limit(import_large_module, memory=(100, "MB")) as lf:
            lf()
コード例 #7
0
def test_two_level_fail_second_level(
    top_limit: dict,
    func: Callable,
    err_type: Type[Exception],
    root_context: str,
    sub_context: str,
) -> None:
    """
    | pynisher_1
    |   pynisher_2
    |       raise ErrorType

    Expects
    -------
    * The underlying error from pynisher level 2 should be propogated up
    * All of the processes children should be terminated
    """
    if root_context == "fork" and sub_context == "forkserver":
        pytest.skip(
            "Doesn't seem to like when pyisher uses 'fork' while the child uses"
            "'forkserver' to spawn new processes."
        )

    if root_context == "fork" and sub_context == "spawn" and sys.version_info < (3, 8):
        pytest.skip(
            "Python 3.7 doesn't seem to allow for a 'fork' process function"
            " to create new subprocesses with 'spawn'"
        )

    if err_type is MemoryLimitException and not supports("memory"):
        pytest.skip(f"System {sys.platform} does not support 'memory' limiting")

    # The function being limitied will raise one of the specific errors
    # as seen in `parametrize` above
    lf = limit(func, **top_limit, context=root_context)

    try:
        lf(context=sub_context)
    except err_type:
        # We should catch the expected error type as it propgates up, in which
        # case everything is working as intended and we move on
        pass

    assert lf._process is not None

    try:
        children = lf._process.children(recursive=True)
        print(children)
        assert len(children) == 0
    except psutil.NoSuchProcess:
        pass
コード例 #8
0
ファイル: test_import.py プロジェクト: automl/pynisher
def test_import_slow_walltime_module(context: str) -> None:
    """
    Expects
    -------
    * A WallTimeoutException should be raised importing a module that takes
      too long to import by walltime measure

    Note
    ----
    The module sleeps for 10seconds
    """
    with pytest.raises(WallTimeoutException):
        with limit(import_slow_walltime_module, wall_time=(1, "s")) as lf:
            lf()
コード例 #9
0
ファイル: test_import.py プロジェクト: automl/pynisher
def test_import_slow_cputime_module(context: str) -> None:
    """
    Expects
    -------
    * A CpuTimeoutException should be raised importing a module that takes
      too long to import by cputime measure

    Note
    ----
    The module keeps cpu busy for 10seconds
    """
    with pytest.raises(CpuTimeoutException):
        with limit(import_slow_cputime_module, cpu_time=(1, "s")) as lf:
            lf()
コード例 #10
0
def test_not_in_namespace(context: str, wrap_errors: Any) -> None:
    """
    Expects
    -------
    * If wrapping exceptions from a locally imported namespace,
      the error should leak no namespaces into the master process
    """
    with limit(import_sklearn, context=context, wrap_errors=wrap_errors) as lf:

        try:
            lf()
        except PynisherException:
            pass

    assert "sklearn" not in sys.modules.keys()
コード例 #11
0
def test_terminate_child_processes_false_keeps_children(
    pynisher_context: str,
    child_context: str,
    daemon: bool,
) -> None:
    """
    Expects
    -------
    * Child processes should not be killed if specified
    """
    if pynisher_context == "fork" and child_context == "forkserver":
        pytest.skip(
            "Doesn't seem to like when pyisher uses 'fork' while the child uses"
            "'forkserver' to spawn new processes.")

    if (pynisher_context == "fork" and child_context == "spawn"
            and sys.version_info < (3, 8)):
        pytest.skip(
            "Python 3.7 doesn't seem to allow for a 'fork' process function"
            " to create new subprocesses with 'spawn'")

    if daemon is False:
        pytest.skip(
            "Non-Daemon subprocess need to be terminate or `spawn_children`"
            " will timeout")

    lf = limit(
        spawn_children,
        wall_time=5,
        terminate_child_processes=False,
        context=pynisher_context,
    )

    with pytest.raises(CustomException) as e:
        lf(child_sleeps=[20, 20], context=child_context, daemon=daemon)

    children_pids = [pid for _, pid in e.value.args[0]]

    assert children_pids is not None and len(children_pids) > 0

    assert lf._process is not None and not lf._process.is_running()

    for pid in children_pids:
        try:
            child = psutil.Process(pid)
            assert not child.is_running()
        except psutil.NoSuchProcess:
            pass
コード例 #12
0
def test_read_large_file(tmp_path: Path, context: str) -> None:
    """
    Expects
    -------
    * Reading files under memory limits should raise a memory limit exception
    """
    fpath = tmp_path / "bytefile.bytes"

    size = round(memconvert(100, frm="mb"))
    x = bytearray(size)
    with fpath.open("wb") as f:
        f.write(x)

    with limit(read_file,
               memory=(50, "mb")) as lf, pytest.raises(MemoryLimitException):
        lf(fpath)
コード例 #13
0
def test_import_fail_linux() -> None:
    """
    Expects
    -------
    * Should fail to import if the memory limit is too low

    Note
    ----
    For sklearn on linux, this triggers an ImportError and so we have
    to be aware of it before hand. There's no automatic way to identfiy
    this from a regular ImportError so we better be explicit about it.
    """
    with pytest.raises(MemoryLimitException):
        with limit(
                import_sklearn,
                memory=(100, "mb"),
                wrap_errors={"memory": [ImportError]},
        ) as lf:
            lf()
コード例 #14
0
def test_import_fail_all() -> None:
    """
    Expects
    -------
    * Should fail to import but give a PynisherException as we can't properly
      identify that it's root cause is due to memory
    """
    m = Monitor()
    print("Before job ", m.memory("mb"))
    try:
        with limit(import_sklearn, wrap_errors=True, memory=(100, "mb")) as lf:
            lf()
    except MemoryLimitException as e:
        raise e
    except PynisherException:
        pass
    except Exception as e:
        print(e, type(e))
        raise e
コード例 #15
0
def test_large_return_value(context: str) -> None:
    """
    Expects
    -------
    * Python multiprocessing.connection.Connection say sending values
    larger than 32 MiB may result in a ValueError exception, depending
    on OS.

    Turns out this doesn't cause an issue but is extremely slow to send this
    information through a pipe. This is documented in the readme but the test left in
    case of future need.
    """
    pytest.skip(
        "This doesn't seem to raise errors on Linux but is extremely slow. Instead"
        " of enforicing behaviour, we simply warn users about return sizes being"
        " problematic and to instead write to file."
    )

    lf = limit(return_large_value)
    with pytest.raises(ValueError):
        lf()
コード例 #16
0
def test_terminate_child_processes_removes_all_children(
        pynisher_context: str, child_context: str, daemon: bool) -> None:
    """
    Expects
    -------
    * All children processes should be cleaned up when by the time
     the function exits.
    """
    if pynisher_context == "fork" and child_context == "forkserver":
        pytest.skip(
            "Doesn't seem to like when pyisher uses 'fork' while the child uses"
            "'forkserver' to spawn new processes.")

    if (pynisher_context == "fork" and child_context == "spawn"
            and sys.version_info < (3, 8)):
        pytest.skip(
            "Python 3.7 doesn't seem to allow for a 'fork' process function"
            " to create new subprocesses with 'spawn'")

    lf = limit(
        spawn_children,
        wall_time=5,
        terminate_child_processes=True,
        context=pynisher_context,
    )
    with pytest.raises(CustomException) as e:
        lf(child_sleeps=[20, 20], context=child_context, daemon=daemon)

    children_pids = [pid for _, pid in e.value.args[0]]

    assert children_pids is not None and len(children_pids) > 0

    assert lf._process is not None and not lf._process.is_running()

    for pid in children_pids:
        try:
            child = psutil.Process(pid)
            assert not child.is_running()
        except psutil.NoSuchProcess:
            pass
コード例 #17
0
ファイル: test_sklearn_train.py プロジェクト: automl/pynisher
def test_train_svr_memory(context: str) -> None:
    """
    Expects
    -------
    * Should raise a MemoryError if it ran out of memory during fit

    Note
    ----
    What will actually happen is a segmentation fault, we deal with this
    in `pynisher`
    """
    m = Monitor()
    from sklearn.datasets import make_regression
    from sklearn.svm import SVR

    model = SVR()
    X, y = make_regression(n_samples=30_000, n_features=128)

    # Seem fit will consume about 28mb extra, see __main__
    # Add 1MB
    too_little_mem = round(m.memory("MB") + 1)

    lf = limit(train_svr, memory=(too_little_mem, "MB"))

    completed = False
    with pytest.raises(MemoryLimitException):
        completed = lf(model, X, y, too_little_mem)

    assert completed is not True
    assert lf._process is not None and not lf._process.is_running()

    try:
        children = lf._process.children()
        assert not any(children)
    except psutil.NoSuchProcess:
        pass
コード例 #18
0
def test_two_level_success_result(root_context: str, sub_context: str) -> None:
    """
    | pynisher_1
    |   pynisher_2
    |       return 10

    Expects
    -------
    * The result of the nested level should reach the top
    """
    if root_context == "fork" and sub_context == "forkserver":
        pytest.skip(
            "Doesn't seem to like when pyisher uses 'fork' while the child uses"
            "'forkserver' to spawn new processes."
        )

    if root_context == "fork" and sub_context == "spawn" and sys.version_info < (3, 8):
        pytest.skip(
            "Python 3.7 doesn't seem to allow for a 'fork' process function"
            " to create new subprocesses with 'spawn'"
        )

    lf = limit(pynish_success, context=root_context)
    assert lf(x=10, context=sub_context) == 10
コード例 #19
0
            pass


if __name__ == "__main__":
    """
    Testing out daemon processes and using htop to identify behaviour

    * Each of these seems to leave no long term hanging process as the
    subprocesses just sleep and exit. The onyl exception is Non-daemon
    subprocesses with no termination, this causes a hang. I guess this
    should be expected and a responsibility of the user.
    """
    print("Host process ", os.getpid())

    # Daemon processes and terminate
    lf = limit(spawn_children, terminate_child_processes=True)
    try:
        lf(daemon=True, child_sleeps=[30])
    except CustomException as e:
        raise e
        print(e.args, "Terminate and Daemon")

    # Daemon processes and no terminate
    lf = limit(spawn_children, terminate_child_processes=False)
    try:
        lf(daemon=True, child_sleeps=[30])
    except CustomException as e:
        print(e.args[0], "No Terminate and Daemon")

    # Non-Daemon processes and terminate
    lf = limit(spawn_children, terminate_child_processes=True)
コード例 #20
0
def pynish_cputime(context: str) -> float:
    """Will pynish a function and exceed cputime"""
    lf = limit(busy_wait, cpu_time=(1, "s"), context=context)
    lf(10)
    return 13.37
コード例 #21
0
def pynish_walltime(context: str) -> float:
    """Will pynish a function and exceed walltime"""
    lf = limit(walltime_sleep, wall_time=(1, "s"), context=context)
    return lf(5)
コード例 #22
0
def pynish_memory(context: str) -> int:
    """Will pynish a function and exceed memory"""
    lf = limit(usememory, memory=(50, "mb"), context=context)
    return lf((100, "mb"))
コード例 #23
0
def pynish_custom(context: str) -> int:
    """Will pynish a function and exceed memory"""
    lf = limit(raises_error, context=context)
    lf(CustomException)
    return 4
コード例 #24
0
def pynish_success(x: Any, context: str) -> Any:
    """A successful pynished function"""
    lf = limit(echo, context=context)
    return lf(x)