Test and valid Python code with 100% coverage

This commit is contained in:
w0rp
2023-02-13 06:46:12 +00:00
parent 25f4bf4abe
commit 93299cf890
12 changed files with 218 additions and 6 deletions
+3 -1
View File
@@ -1,8 +1,10 @@
.* export-ignore
/env export-ignore
/Dockerfile export-ignore
/README.md export-ignore
/env export-ignore
/install-python-env.sh export-ignore
/run-tests export-ignore
/run-tests.bat export-ignore
/test export-ignore
/test-requirements.txt export-ignore
/tox.ini export-ignore
+4 -1
View File
@@ -1,3 +1,6 @@
tags
.coverage
.directory
.tox
/env
__pycache__
tags
+17
View File
@@ -0,0 +1,17 @@
WIP
Make sure all required Python versions for testing are installed.
Neural tests against Python 3.7 and Python 3.10.
Run the following: >
python -m pip install --user tox
python -m tox
<
To get the same configuration in your editor, run `./install-python-env.sh`.
ALE should pick up on how to run `ruff` and `pyright` automatically.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
+1 -1
View File
@@ -13,4 +13,4 @@ if ! [ -d env ]; then
python3.10 -m venv env
fi
env/bin/pip install pyright ruff==0.0.237
env/bin/pip install -r test-requirements.txt
View File
+1 -3
View File
@@ -4,8 +4,8 @@ A Neural datasource for loading generated text via OpenAI.
import json
import sys
import urllib.error
from typing import Any, Dict
import urllib.request
from typing import Any, Dict
API_ENDPOINT = 'https://api.openai.com/v1/completions'
@@ -57,8 +57,6 @@ def get_openai_completion(config: Config, prompt: str) -> None:
method="POST",
)
buffer = b''
with urllib.request.urlopen(req) as response:
while True:
line_bytes = response.readline()
+11
View File
@@ -0,0 +1,11 @@
[tool.ruff]
target-version = "py310"
line-length = 79
select = ["W", "E", "F", "I"]
fixable = ["W", "E", "F", "I"]
# Do not auto-fix unused variables.
unfixable = ["F841"]
ignore = []
exclude = [".tox", ".ruff_cache", ".git", "env"]
+4
View File
@@ -0,0 +1,4 @@
pyright==1.1.293
pytest-cov==4.0.0
pytest==7.2.1
ruff==0.0.237
View File
+154
View File
@@ -0,0 +1,154 @@
import json
import sys
import urllib.error
import urllib.request
from io import BytesIO
from typing import Any, Dict, cast
from unittest import mock
import pytest
from neural_sources import openai
def get_valid_config() -> Dict[str, Any]:
return {
"api_key": ".",
"prompt": "say hello",
"temperature": 1,
"top_p": 1,
"max_tokens": 1,
"presence_penalty": 1,
"frequency_penalty": 1,
}
def test_load_config_errors():
with pytest.raises(ValueError) as exc:
openai.load_config(cast(Any, 0))
assert str(exc.value) == "openai config is not a dictionary"
config: Dict[str, Any] = {}
for modification, expected_error in [
({}, "openai.api_key is not defined"),
({"api_key": ""}, "openai.api_key is not defined"),
(
{"api_key": ".", "temperature": "x"},
"openai.temperature is invalid"
),
(
{"temperature": 1, "top_p": "x"},
"openai.top_p is invalid"
),
(
{"top_p": 1, "max_tokens": "x"},
"openai.max_tokens is invalid"
),
(
{"max_tokens": 1, "presence_penalty": "x"},
"openai.presence_penalty is invalid"
),
(
{"presence_penalty": 1, "frequency_penalty": "x"},
"openai.frequency_penalty is invalid"
),
]:
config.update(modification)
with pytest.raises(ValueError) as exc:
openai.load_config(config)
assert str(exc.value) == expected_error, config
def test_main_function_rate_other_error():
with mock.patch.object(sys.stdin, 'readline') as readline_mock, \
mock.patch.object(openai, 'get_openai_completion') as completion_mock:
completion_mock.side_effect = urllib.error.HTTPError(
url='',
msg='',
hdrs=mock.Mock(),
fp=None,
code=500,
)
readline_mock.return_value = json.dumps({
"config": get_valid_config(),
"prompt": "hello there",
})
with pytest.raises(urllib.error.HTTPError):
openai.main()
def test_print_openai_results():
result_data = (
b'data: {"id": "cmpl-6jMlRJtbYTGrNwE6Lxy1Ns1EtD0is", "object": "text_completion", "created": 1676270285, "choices": [{"text": "\\n", "index": 0, "logprobs": null, "finish_reason": null}], "model": "text-davinci-003"}\n' # noqa
b'\n'
b'data: {"id": "cmpl-6jMlRJtbYTGrNwE6Lxy1Ns1EtD0is", "object": "text_completion", "created": 1676270285, "choices": [{"text": "\\n", "index": 0, "logprobs": null, "finish_reason": null}], "model": "text-davinci-003"}\n' # noqa
b'\n'
b'data: {"id": "cmpl-6jMlRJtbYTGrNwE6Lxy1Ns1EtD0is", "object": "text_completion", "created": 1676270285, "choices": [{"text": "Hello", "index": 0, "logprobs": null, "finish_reason": null}], "model": "text-davinci-003"}\n' # noqa
b'data: {"id": "cmpl-6jMlRJtbYTGrNwE6Lxy1Ns1EtD0is", "object": "text_completion", "created": 1676270285, "choices": [{"text": "!", "index": 0, "logprobs": null, "finish_reason": null}], "model": "text-davinci-003"}\n' # noqa
b'\n'
b'data: {"id": "cmpl-6jMlRJtbYTGrNwE6Lxy1Ns1EtD0is", "object": "text_completion", "created": 1676270285, "choices": [{"text": "", "index": 0, "logprobs": null, "finish_reason": "stop"}], "model": "text-davinci-003"}\n' # noqa
b'\n'
b'data: [DONE]\n'
b'\n'
b''
)
with mock.patch.object(sys.stdin, 'readline') as readline_mock, \
mock.patch.object(urllib.request, 'urlopen') as urlopen_mock, \
mock.patch('builtins.print') as print_mock:
urlopen_mock.return_value.__enter__.return_value = BytesIO(result_data)
readline_mock.return_value = json.dumps({
"config": get_valid_config(),
"prompt": "hello there",
})
openai.main()
assert print_mock.call_args_list == [
mock.call('\n', end='', flush=True),
mock.call('\n', end='', flush=True),
mock.call('Hello', end='', flush=True),
mock.call('!', end='', flush=True),
mock.call('', end='', flush=True),
mock.call(),
]
def test_main_function_bad_config():
with mock.patch.object(sys.stdin, 'readline') as readline_mock, \
mock.patch.object(openai, 'load_config') as load_config_mock:
load_config_mock.side_effect = ValueError("expect this")
readline_mock.return_value = json.dumps({"config": {}})
with pytest.raises(SystemExit) as exc:
openai.main()
assert str(exc.value) == 'expect this'
def test_main_function_rate_limit_error():
with mock.patch.object(sys.stdin, 'readline') as readline_mock, \
mock.patch.object(openai, 'get_openai_completion') as completion_mock:
completion_mock.side_effect = urllib.error.HTTPError(
url='',
msg='',
hdrs=mock.Mock(),
fp=None,
code=429,
)
readline_mock.return_value = json.dumps({
"config": get_valid_config(),
"prompt": "hello there",
})
with pytest.raises(SystemExit) as exc:
openai.main()
assert str(exc.value) == 'Neural error: OpenAI request limit reached!'
+23
View File
@@ -0,0 +1,23 @@
[tox]
requires = tox>=4
env_list = lint, type, py{37,310}
[testenv]
description = run unit tests
deps = -r{toxinidir}/test-requirements.txt
skip_install = true
setenv = PYTHONPATH=.
commands = pytest --cov=neural_sources --cov-fail-under=100 {posargs:test/python}
[testenv:lint]
description = run linters
deps = -r{toxinidir}/test-requirements.txt
skip_install = true
commands = ruff {posargs:neural_sources}
[testenv:type]
description = run type checks
deps = -r{toxinidir}/test-requirements.txt
skip_install = true
setenv = PYTHONPATH=.
commands = pyright {postarg:neural_sources}
View File