Skip to content

Commit cccc8cb

Browse files
committed
Do CLI import in __main__, not __init__
Importing the CLI code doubles the import time for httpx altogether. By importing in httpx/__main__.py instead of in httpx/__init__.py, the additional time only happens when running the httpx CLI, and not on every "import httpx".
1 parent 9e8ab40 commit cccc8cb

File tree

4 files changed

+37
-29
lines changed

4 files changed

+37
-29
lines changed

httpx/__init__.py

-16
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,6 @@
1111
from ._types import *
1212
from ._urls import *
1313

14-
try:
15-
from ._main import main
16-
except ImportError: # pragma: no cover
17-
18-
def main() -> None: # type: ignore
19-
import sys
20-
21-
print(
22-
"The httpx command line client could not run because the required "
23-
"dependencies were not installed.\nMake sure you've installed "
24-
"everything with: pip install 'httpx[cli]'"
25-
)
26-
sys.exit(1)
27-
28-
2914
__all__ = [
3015
"__description__",
3116
"__title__",
@@ -59,7 +44,6 @@ def main() -> None: # type: ignore
5944
"InvalidURL",
6045
"Limits",
6146
"LocalProtocolError",
62-
"main",
6347
"MockTransport",
6448
"NetRCAuth",
6549
"NetworkError",

httpx/__main__.py

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
try:
2+
from ._main import main
3+
except ImportError: # pragma: no cover
4+
5+
def main() -> None: # type: ignore
6+
import sys
7+
8+
print(
9+
"The httpx command line client could not run because the required "
10+
"dependencies were not installed.\nMake sure you've installed "
11+
"everything with: pip install 'httpx[cli]'"
12+
)
13+
sys.exit(1)
14+
15+
16+
__all__ = ["main"]
17+
18+
19+
if __name__ == "__main__": # pragma: no cover
20+
main()

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ zstd = [
5757
]
5858

5959
[project.scripts]
60-
httpx = "httpx:main"
60+
httpx = "httpx.__main__:main"
6161

6262
[project.urls]
6363
Changelog = "https://github.com/encode/httpx/blob/master/CHANGELOG.md"

tests/test_main.py

+16-12
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from click.testing import CliRunner
55

6-
import httpx
6+
import httpx.__main__
77

88

99
def splitlines(output: str) -> typing.Iterable[str]:
@@ -16,15 +16,15 @@ def remove_date_header(lines: typing.Iterable[str]) -> typing.Iterable[str]:
1616

1717
def test_help():
1818
runner = CliRunner()
19-
result = runner.invoke(httpx.main, ["--help"])
19+
result = runner.invoke(httpx.__main__.main, ["--help"])
2020
assert result.exit_code == 0
2121
assert "A next generation HTTP client." in result.output
2222

2323

2424
def test_get(server):
2525
url = str(server.url)
2626
runner = CliRunner()
27-
result = runner.invoke(httpx.main, [url])
27+
result = runner.invoke(httpx.__main__.main, [url])
2828
assert result.exit_code == 0
2929
assert remove_date_header(splitlines(result.output)) == [
3030
"HTTP/1.1 200 OK",
@@ -39,7 +39,7 @@ def test_get(server):
3939
def test_json(server):
4040
url = str(server.url.copy_with(path="/json"))
4141
runner = CliRunner()
42-
result = runner.invoke(httpx.main, [url])
42+
result = runner.invoke(httpx.__main__.main, [url])
4343
assert result.exit_code == 0
4444
assert remove_date_header(splitlines(result.output)) == [
4545
"HTTP/1.1 200 OK",
@@ -57,7 +57,7 @@ def test_binary(server):
5757
url = str(server.url.copy_with(path="/echo_binary"))
5858
runner = CliRunner()
5959
content = "Hello, world!"
60-
result = runner.invoke(httpx.main, [url, "-c", content])
60+
result = runner.invoke(httpx.__main__.main, [url, "-c", content])
6161
assert result.exit_code == 0
6262
assert remove_date_header(splitlines(result.output)) == [
6363
"HTTP/1.1 200 OK",
@@ -72,7 +72,7 @@ def test_binary(server):
7272
def test_redirects(server):
7373
url = str(server.url.copy_with(path="/redirect_301"))
7474
runner = CliRunner()
75-
result = runner.invoke(httpx.main, [url])
75+
result = runner.invoke(httpx.__main__.main, [url])
7676
assert result.exit_code == 1
7777
assert remove_date_header(splitlines(result.output)) == [
7878
"HTTP/1.1 301 Moved Permanently",
@@ -86,7 +86,7 @@ def test_redirects(server):
8686
def test_follow_redirects(server):
8787
url = str(server.url.copy_with(path="/redirect_301"))
8888
runner = CliRunner()
89-
result = runner.invoke(httpx.main, [url, "--follow-redirects"])
89+
result = runner.invoke(httpx.__main__.main, [url, "--follow-redirects"])
9090
assert result.exit_code == 0
9191
assert remove_date_header(splitlines(result.output)) == [
9292
"HTTP/1.1 301 Moved Permanently",
@@ -106,7 +106,9 @@ def test_follow_redirects(server):
106106
def test_post(server):
107107
url = str(server.url.copy_with(path="/echo_body"))
108108
runner = CliRunner()
109-
result = runner.invoke(httpx.main, [url, "-m", "POST", "-j", '{"hello": "world"}'])
109+
result = runner.invoke(
110+
httpx.__main__.main, [url, "-m", "POST", "-j", '{"hello": "world"}']
111+
)
110112
assert result.exit_code == 0
111113
assert remove_date_header(splitlines(result.output)) == [
112114
"HTTP/1.1 200 OK",
@@ -121,7 +123,7 @@ def test_post(server):
121123
def test_verbose(server):
122124
url = str(server.url)
123125
runner = CliRunner()
124-
result = runner.invoke(httpx.main, [url, "-v"])
126+
result = runner.invoke(httpx.__main__.main, [url, "-v"])
125127
assert result.exit_code == 0
126128
assert remove_date_header(splitlines(result.output)) == [
127129
"* Connecting to '127.0.0.1'",
@@ -145,7 +147,9 @@ def test_verbose(server):
145147
def test_auth(server):
146148
url = str(server.url)
147149
runner = CliRunner()
148-
result = runner.invoke(httpx.main, [url, "-v", "--auth", "username", "password"])
150+
result = runner.invoke(
151+
httpx.__main__.main, [url, "-v", "--auth", "username", "password"]
152+
)
149153
print(result.output)
150154
assert result.exit_code == 0
151155
assert remove_date_header(splitlines(result.output)) == [
@@ -172,15 +176,15 @@ def test_download(server):
172176
url = str(server.url)
173177
runner = CliRunner()
174178
with runner.isolated_filesystem():
175-
runner.invoke(httpx.main, [url, "--download", "index.txt"])
179+
runner.invoke(httpx.__main__.main, [url, "--download", "index.txt"])
176180
assert os.path.exists("index.txt")
177181
with open("index.txt", "r") as input_file:
178182
assert input_file.read() == "Hello, world!"
179183

180184

181185
def test_errors():
182186
runner = CliRunner()
183-
result = runner.invoke(httpx.main, ["invalid://example.org"])
187+
result = runner.invoke(httpx.__main__.main, ["invalid://example.org"])
184188
assert result.exit_code == 1
185189
assert splitlines(result.output) == [
186190
"UnsupportedProtocol: Request URL has an unsupported protocol 'invalid://'.",

0 commit comments

Comments
 (0)