Skip to content

Add http_timeout configuration setting to configure timeout when gett… #718

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,5 +164,9 @@ If you are carefully curating your `title` properties already to ensure no dupli

If this option results in conflicts, you will need to manually override class names instead via the `class_overrides` option.

### http_timeout

By default, the timeout for retrieving the schema file via HTTP is 5 seconds. In case there is an error when retrieving the schema, you might try and increase this setting to a higher value.

[changelog.md]: CHANGELOG.md
[poetry]: https://python-poetry.org/
6 changes: 3 additions & 3 deletions openapi_python_client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ def _get_project_for_url_or_path( # pylint: disable=too-many-arguments
custom_template_path: Optional[Path] = None,
file_encoding: str = "utf-8",
) -> Union[Project, GeneratorError]:
data_dict = _get_document(url=url, path=path)
data_dict = _get_document(url=url, path=path, timeout=config.http_timeout)
if isinstance(data_dict, GeneratorError):
return data_dict
openapi = GeneratorData.from_dict(data_dict, config=config)
Expand Down Expand Up @@ -394,14 +394,14 @@ def _load_yaml_or_json(data: bytes, content_type: Optional[str]) -> Union[Dict[s
return GeneratorError(header=f"Invalid YAML from provided source: {err}")


def _get_document(*, url: Optional[str], path: Optional[Path]) -> Union[Dict[str, Any], GeneratorError]:
def _get_document(*, url: Optional[str], path: Optional[Path], timeout: int) -> Union[Dict[str, Any], GeneratorError]:
yaml_bytes: bytes
content_type: Optional[str]
if url is not None and path is not None:
return GeneratorError(header="Provide URL or Path, not both.")
if url is not None:
try:
response = httpx.get(url)
response = httpx.get(url, timeout=timeout)
yaml_bytes = response.content
if "content-type" in response.headers:
content_type = response.headers["content-type"].split(";")[0]
Expand Down
1 change: 1 addition & 0 deletions openapi_python_client/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class Config(BaseModel):
"black .",
]
field_prefix: str = "field_"
http_timeout: int = 5

@staticmethod
def load_from_path(path: Path) -> "Config":
Expand Down
30 changes: 17 additions & 13 deletions tests/test___init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

from openapi_python_client import Config, ErrorLevel, GeneratorError, Project

default_http_timeout = Config.schema()["properties"]["http_timeout"]["default"]


def test__get_project_for_url_or_path(mocker):
data_dict = mocker.MagicMock()
Expand All @@ -17,12 +19,13 @@ def test__get_project_for_url_or_path(mocker):
url = mocker.MagicMock()
path = mocker.MagicMock()
config = mocker.MagicMock()
config.http_timeout = default_http_timeout

from openapi_python_client import MetaType, _get_project_for_url_or_path

project = _get_project_for_url_or_path(url=url, path=path, meta=MetaType.POETRY, config=config)

_get_document.assert_called_once_with(url=url, path=path)
_get_document.assert_called_once_with(url=url, path=path, timeout=default_http_timeout)
from_dict.assert_called_once_with(data_dict, config=config)
_Project.assert_called_once_with(
openapi=openapi, custom_template_path=None, meta=MetaType.POETRY, file_encoding="utf-8", config=config
Expand All @@ -39,12 +42,13 @@ def test__get_project_for_url_or_path_generator_error(mocker):
url = mocker.MagicMock()
path = mocker.MagicMock()
config = mocker.MagicMock()
config.http_timeout = default_http_timeout

from openapi_python_client import MetaType, _get_project_for_url_or_path

project = _get_project_for_url_or_path(url=url, path=path, meta=MetaType.POETRY, config=config)

_get_document.assert_called_once_with(url=url, path=path)
_get_document.assert_called_once_with(url=url, path=path, timeout=default_http_timeout)
from_dict.assert_called_once_with(data_dict, config=config)
_Project.assert_not_called()
assert project == error
Expand All @@ -62,7 +66,7 @@ def test__get_project_for_url_or_path_document_error(mocker):

project = _get_project_for_url_or_path(url=url, path=path, meta=MetaType.POETRY, config=Config())

_get_document.assert_called_once_with(url=url, path=path)
_get_document.assert_called_once_with(url=url, path=path, timeout=default_http_timeout)
from_dict.assert_not_called()
assert project == error

Expand Down Expand Up @@ -153,7 +157,7 @@ def test__get_document_no_url_or_path(self, mocker):

from openapi_python_client import _get_document

result = _get_document(url=None, path=None)
result = _get_document(url=None, path=None, timeout=default_http_timeout)

assert result == GeneratorError(header="No URL or Path provided")
get.assert_not_called()
Expand All @@ -167,7 +171,7 @@ def test__get_document_url_and_path(self, mocker):

from openapi_python_client import _get_document

result = _get_document(url=mocker.MagicMock(), path=mocker.MagicMock())
result = _get_document(url=mocker.MagicMock(), path=mocker.MagicMock(), timeout=default_http_timeout)

assert result == GeneratorError(header="Provide URL or Path, not both.")
get.assert_not_called()
Expand All @@ -182,10 +186,10 @@ def test__get_document_bad_url(self, mocker):
from openapi_python_client import _get_document

url = mocker.MagicMock()
result = _get_document(url=url, path=None)
result = _get_document(url=url, path=None, timeout=default_http_timeout)

assert result == GeneratorError(header="Could not get OpenAPI document from provided URL")
get.assert_called_once_with(url)
get.assert_called_once_with(url, timeout=default_http_timeout)
_Path.assert_not_called()
loads.assert_not_called()

Expand All @@ -197,9 +201,9 @@ def test__get_document_url_no_path(self, mocker):
from openapi_python_client import _get_document

url = "test"
_get_document(url=url, path=None)
_get_document(url=url, path=None, timeout=default_http_timeout)

get.assert_called_once_with(url)
get.assert_called_once_with(url, timeout=default_http_timeout)
_Path.assert_not_called()
loads.assert_called_once_with(get().content)

Expand All @@ -211,7 +215,7 @@ def test__get_document_path_no_url(self, tmp_path, mocker):

from openapi_python_client import _get_document

_get_document(url=None, path=path)
_get_document(url=None, path=path, timeout=default_http_timeout)

get.assert_not_called()
loads.assert_called_once_with(b"some test data")
Expand All @@ -222,7 +226,7 @@ def test__get_document_bad_yaml(self, mocker, tmp_path):

path = tmp_path / "test.yaml"
path.write_text("'")
result = _get_document(url=None, path=path)
result = _get_document(url=None, path=path, timeout=default_http_timeout)

get.assert_not_called()
assert isinstance(result, GeneratorError)
Expand All @@ -241,7 +245,7 @@ class FakeResponse:
from openapi_python_client import _get_document

url = mocker.MagicMock()
result = _get_document(url=url, path=None)
result = _get_document(url=url, path=None, timeout=default_http_timeout)

get.assert_called_once()
json_loads.assert_called_once_with(FakeResponse.content.decode())
Expand All @@ -258,7 +262,7 @@ class FakeResponse:
from openapi_python_client import _get_document

url = mocker.MagicMock()
result = _get_document(url=url, path=None)
result = _get_document(url=url, path=None, timeout=default_http_timeout)

get.assert_called_once()
assert result == GeneratorError(
Expand Down