Repository: nomic-ai/gpt4all
File: gpt4all-chat/tests/python/test_server_api.py (Python)

Code before:
@pytest.fixture
def chat_server(chat_server_config: dict[str, str]) -> Iterator[None]:
    chat_executable = Path(os.environ['CHAT_EXECUTABLE']).absolute()
    with subprocess.Popen(chat_executable, env=chat_server_config) as process:
        try:
            yield
        except:
            process.kill()
            raise
        process.send_signal(signal.SIGINT)
        if retcode := process.wait():
            raise CalledProcessError(retcode, process.args)


@pytest.fixture
def chat_server_with_model(chat_server_with_model_config: dict[str, str]) -> Iterator[None]:
    chat_executable = Path(os.environ['CHAT_EXECUTABLE']).absolute()
    with subprocess.Popen(chat_executable, env=chat_server_with_model_config) as process:
        try:
            yield
        except:
            process.kill()
            raise
        process.send_signal(signal.SIGINT)
        if retcode := process.wait():
            raise CalledProcessError(retcode, process.args)


def test_with_models_empty(chat_server: None) -> None:
    # non-sense endpoint
    with pytest.raises(requests.exceptions.HTTPError) as excinfo:
        request.get('foobarbaz', wait=True)
    assert excinfo.value.response.status_code == 404

    # empty model list
    response = request.get('models', wait=True)
    assert response == {'object': 'list', 'data': []}

    # empty model info
    response = request.get('models/foo', wait=True)
    assert response == {}

    # POST for model list
    with pytest.raises(requests.exceptions.HTTPError) as excinfo:
        response = request.post('models', data=None, wait=True)
    assert excinfo.value.response.status_code == 405

    # POST for model info
    with pytest.raises(requests.exceptions.HTTPError) as excinfo:
        response = request.post('models/foo', data=None, wait=True)
    assert excinfo.value.response.status_code == 405

Review comment (suggestion):
There is no need for the code duplication between chat_server_config/chat_server_with_model_config and chat_server/chat_server_with_model.

There only really need to be two fixtures: chat_server and chat_server_with_model. They can each be a single line function that calls some common function like `def prepare_chat_server(with_model: bool = False)`. You can always `return` a generator, or `yield from` if it's called inside of a `with` block.

Code after:
            process.kill()
            raise
        process.send_signal(signal.SIGINT)
        if retcode := process.wait():
            raise CalledProcessError(retcode, process.args)


@pytest.fixture
def chat_server() -> Iterator[None]:
    with prepare_chat_server(model_copied=False) as config:
        yield from start_chat_server(config)


@pytest.fixture
def chat_server_with_model() -> Iterator[None]:
    with prepare_chat_server(model_copied=True) as config:
        yield from start_chat_server(config)


def test_with_models_empty(chat_server: None) -> None:
    # non-sense endpoint
    status_code, response = request.get('foobarbaz', wait=True, raise_for_status=False)
    assert status_code == 404
    assert response is None

    # empty model list
    response = request.get('models')
    assert response == {'object': 'list', 'data': []}

    # empty model info
    response = request.get('models/foo')
    assert response == {}

    # POST for model list
    status_code, response = request.post('models', data=None, raise_for_status=False)
    assert status_code == 405
    assert response == {'error': {
        'code': None,
        'message': 'Not allowed to POST on /v1/models. (HINT: Perhaps you meant to use a different HTTP method?)',
        'param': None,
        'type': 'invalid_request_error',
    }}

    # POST for model info
    status_code, response = request.post('models/foo', data=None, raise_for_status=False)
    assert status_code == 405
    assert response == {'error': {
        'code': None,
        'message': 'Not allowed to POST on /v1/models/*. (HINT: Perhaps you meant to use a different HTTP method?)',
        'param': None,
        'type': 'invalid_request_error',