Repository: django/django
File: django/test/runner.py (Python)

Code before:

    This helper lives at module-level because of the multiprocessing module's
    requirements.
    """

    global _worker_id

    with counter.get_lock():
        counter.value += 1
        _worker_id = counter.value

    is_spawn_or_forkserver = multiprocessing.get_start_method() in {
        "forkserver",
        "spawn",
    }

    if is_spawn_or_forkserver:
        if process_setup and callable(process_setup):
            if process_setup_args is None:
                process_setup_args = ()
            process_setup(*process_setup_args)
        django.setup()
        setup_test_environment(debug=debug_mode)

    db_aliases = used_aliases if used_aliases is not None else connections
    for alias in db_aliases:
        connection = connections[alias]
        if is_spawn_or_forkserver:
            # Restore initial settings in spawned processes.
            connection.settings_dict.update(initial_settings[alias])
            if value := serialized_contents.get(alias):
                connection._test_serialized_contents = value
        connection.creation.setup_worker_connection(_worker_id)


def _run_subsuite(args):
    """
    Run a suite of tests with a RemoteTestRunner and return a RemoteTestResult.

    This helper lives at module-level and its arguments are wrapped in a tuple
    because of the multiprocessing module's requirements.
    """
    runner_class, subsuite_index, subsuite, failfast, buffer = args
    runner = runner_class(failfast=failfast, buffer=buffer)
    result = runner.run(subsuite)
    return subsuite_index, result.events


def _process_setup_stub(*args):
    """Stub method to simplify run() implementation."""
    pass

Review comment (suggestion):
I find it a little awkward that we're going through calling the management command to form its output and discard, but after drilling down, I found that we need this to reuse the logic from `BaseCommand.check()` to raise `SystemCheckError` for any "serious" issues. So it's not easy to avoid this step.

Code after:

    This helper lives at module-level because of the multiprocessing module's
    requirements.
    """

    global _worker_id

    with counter.get_lock():
        counter.value += 1
        _worker_id = counter.value

    is_spawn_or_forkserver = multiprocessing.get_start_method() in {
        "forkserver",
        "spawn",
    }

    if is_spawn_or_forkserver:
        if process_setup and callable(process_setup):
            if process_setup_args is None:
                process_setup_args = ()
            process_setup(*process_setup_args)
        django.setup()
        setup_test_environment(debug=debug_mode)
        call_command(
            "check", stdout=io.StringIO(), stderr=io.StringIO(), databases=used_aliases
        )

    db_aliases = used_aliases if used_aliases is not None else connections
    for alias in db_aliases:
        connection = connections[alias]
        if is_spawn_or_forkserver:
            # Restore initial settings in spawned processes.
            connection.settings_dict.update(initial_settings[alias])
            if value := serialized_contents.get(alias):
                connection._test_serialized_contents = value
        connection.creation.setup_worker_connection(_worker_id)


def _run_subsuite(args):
    """
    Run a suite of tests with a RemoteTestRunner and return a RemoteTestResult.

    This helper lives at module-level and its arguments are wrapped in a tuple
    because of the multiprocessing module's requirements.
    """
    runner_class, subsuite_index, subsuite, failfast, buffer = args
    runner = runner_class(failfast=failfast, buffer=buffer)
    result = runner.run(subsuite)
    return subsuite_index, result.events