clean up request
Browse files- pytube/request.py +31 -21
- pytube/streams.py +3 -3
- tests/test_request.py +4 -4
- tests/test_streams.py +16 -20
pytube/request.py
CHANGED
@@ -1,39 +1,49 @@
|
|
1 |
# -*- coding: utf-8 -*-
|
2 |
"""Implements a simple wrapper around urlopen."""
|
|
|
3 |
from urllib.request import Request
|
4 |
from urllib.request import urlopen
|
5 |
|
6 |
|
7 |
-
def
|
|
|
|
|
|
|
|
|
8 |
"""Send an http GET request.
|
9 |
|
10 |
:param str url:
|
11 |
The URL to perform the GET request for.
|
12 |
-
:
|
13 |
-
|
14 |
-
|
15 |
-
Returns the response body in chunks via a generator.
|
16 |
-
:param int chunk_size:
|
17 |
-
The size in bytes of each chunk. Defaults to 8*1024
|
18 |
"""
|
|
|
19 |
|
20 |
-
req = Request(url, headers={"User-Agent": "Mozilla/5.0"})
|
21 |
-
response = urlopen(req)
|
22 |
-
|
23 |
-
if streaming:
|
24 |
-
return stream_response(response, chunk_size)
|
25 |
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
while True:
|
36 |
buf = response.read(chunk_size)
|
37 |
if not buf:
|
38 |
break
|
39 |
yield buf
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
# -*- coding: utf-8 -*-
|
2 |
"""Implements a simple wrapper around urlopen."""
|
3 |
+
from typing import Any, Iterable, Dict
|
4 |
from urllib.request import Request
|
5 |
from urllib.request import urlopen
|
6 |
|
7 |
|
8 |
+
def _execute_request(url:str) -> Any:
|
9 |
+
return urlopen(Request(url, headers={"User-Agent": "Mozilla/5.0"}))
|
10 |
+
|
11 |
+
|
12 |
+
def get(url) -> str:
|
13 |
"""Send an http GET request.
|
14 |
|
15 |
:param str url:
|
16 |
The URL to perform the GET request for.
|
17 |
+
:rtype: str
|
18 |
+
:returns:
|
19 |
+
UTF-8 encoded string of response
|
|
|
|
|
|
|
20 |
"""
|
21 |
+
return _execute_request(url).read().decode("utf-8")
|
22 |
|
|
|
|
|
|
|
|
|
|
|
23 |
|
24 |
+
def stream(url: str, chunk_size:int = 8192) -> Iterable[bytes]:
|
25 |
+
"""Read the response in chunks.
|
26 |
+
:param str url:
|
27 |
+
The URL to perform the GET request for.
|
28 |
+
:param int chunk_size:
|
29 |
+
The size in bytes of each chunk. Defaults to 8*1024
|
30 |
+
:rtype: Iterable[bytes]
|
31 |
+
"""
|
32 |
+
response = _execute_request(url)
|
33 |
while True:
|
34 |
buf = response.read(chunk_size)
|
35 |
if not buf:
|
36 |
break
|
37 |
yield buf
|
38 |
+
|
39 |
+
|
40 |
+
def headers(url: str) -> Dict:
|
41 |
+
"""Fetch headers returned http GET request.
|
42 |
+
|
43 |
+
:param str url:
|
44 |
+
The URL to perform the GET request for.
|
45 |
+
:rtype: dict
|
46 |
+
:returns:
|
47 |
+
dictionary of lowercase headers
|
48 |
+
"""
|
49 |
+
return {k.lower(): v for k, v in _execute_request(url).info().items()}
|
pytube/streams.py
CHANGED
@@ -160,7 +160,7 @@ class Stream:
|
|
160 |
Filesize (in bytes) of the stream.
|
161 |
"""
|
162 |
if self._filesize is None:
|
163 |
-
headers = request.
|
164 |
self._filesize = int(headers["content-length"])
|
165 |
return self._filesize
|
166 |
|
@@ -239,7 +239,7 @@ class Stream:
|
|
239 |
)
|
240 |
|
241 |
with open(file_path, "wb") as fh:
|
242 |
-
for chunk in request.
|
243 |
# reduce the (bytes) remainder by the length of the chunk.
|
244 |
bytes_remaining -= len(chunk)
|
245 |
# send to the on_progress callback.
|
@@ -258,7 +258,7 @@ class Stream:
|
|
258 |
"downloading (%s total bytes) file to BytesIO buffer", self.filesize,
|
259 |
)
|
260 |
|
261 |
-
for chunk in request.
|
262 |
# reduce the (bytes) remainder by the length of the chunk.
|
263 |
bytes_remaining -= len(chunk)
|
264 |
# send to the on_progress callback.
|
|
|
160 |
Filesize (in bytes) of the stream.
|
161 |
"""
|
162 |
if self._filesize is None:
|
163 |
+
headers = request.headers(self.url)
|
164 |
self._filesize = int(headers["content-length"])
|
165 |
return self._filesize
|
166 |
|
|
|
239 |
)
|
240 |
|
241 |
with open(file_path, "wb") as fh:
|
242 |
+
for chunk in request.stream(self.url):
|
243 |
# reduce the (bytes) remainder by the length of the chunk.
|
244 |
bytes_remaining -= len(chunk)
|
245 |
# send to the on_progress callback.
|
|
|
258 |
"downloading (%s total bytes) file to BytesIO buffer", self.filesize,
|
259 |
)
|
260 |
|
261 |
+
for chunk in request.stream(self.url):
|
262 |
# reduce the (bytes) remainder by the length of the chunk.
|
263 |
bytes_remaining -= len(chunk)
|
264 |
# send to the on_progress callback.
|
tests/test_request.py
CHANGED
@@ -7,7 +7,7 @@ from pytube import request
|
|
7 |
|
8 |
|
9 |
@mock.patch("pytube.request.urlopen")
|
10 |
-
def
|
11 |
fake_stream_binary = [
|
12 |
iter(os.urandom(8 * 1024)),
|
13 |
iter(os.urandom(8 * 1024)),
|
@@ -17,18 +17,18 @@ def test_get_streaming(mock_urlopen):
|
|
17 |
response = mock.Mock()
|
18 |
response.read.side_effect = fake_stream_binary
|
19 |
mock_urlopen.return_value = response
|
20 |
-
response = request.
|
21 |
call_count = len(list(response))
|
22 |
|
23 |
assert call_count == 3
|
24 |
|
25 |
|
26 |
@mock.patch("pytube.request.urlopen")
|
27 |
-
def
|
28 |
response = mock.Mock()
|
29 |
response.info.return_value = {"content-length": "16384"}
|
30 |
mock_urlopen.return_value = response
|
31 |
-
response = request.
|
32 |
assert response == {"content-length": "16384"}
|
33 |
|
34 |
|
|
|
7 |
|
8 |
|
9 |
@mock.patch("pytube.request.urlopen")
|
10 |
+
def test_streaming(mock_urlopen):
|
11 |
fake_stream_binary = [
|
12 |
iter(os.urandom(8 * 1024)),
|
13 |
iter(os.urandom(8 * 1024)),
|
|
|
17 |
response = mock.Mock()
|
18 |
response.read.side_effect = fake_stream_binary
|
19 |
mock_urlopen.return_value = response
|
20 |
+
response = request.stream("http://fakeassurl.gov")
|
21 |
call_count = len(list(response))
|
22 |
|
23 |
assert call_count == 3
|
24 |
|
25 |
|
26 |
@mock.patch("pytube.request.urlopen")
|
27 |
+
def test_headers(mock_urlopen):
|
28 |
response = mock.Mock()
|
29 |
response.info.return_value = {"content-length": "16384"}
|
30 |
mock_urlopen.return_value = response
|
31 |
+
response = request.headers("http://fakeassurl.gov")
|
32 |
assert response == {"content-length": "16384"}
|
33 |
|
34 |
|
tests/test_streams.py
CHANGED
@@ -8,8 +8,8 @@ from pytube import Stream
|
|
8 |
|
9 |
|
10 |
def test_filesize(cipher_signature, mocker):
|
11 |
-
mocker.patch.object(request, "
|
12 |
-
request.
|
13 |
assert cipher_signature.streams.first().filesize == 6796391
|
14 |
|
15 |
|
@@ -36,12 +36,10 @@ def test_title(cipher_signature):
|
|
36 |
|
37 |
|
38 |
def test_download(cipher_signature, mocker):
|
39 |
-
mocker.patch.object(request, "
|
40 |
-
request.
|
41 |
-
|
42 |
-
|
43 |
-
iter([str(random.getrandbits(8 * 1024))]),
|
44 |
-
]
|
45 |
with mock.patch("pytube.streams.open", mock.mock_open(), create=True):
|
46 |
stream = cipher_signature.streams.first()
|
47 |
stream.download()
|
@@ -61,12 +59,11 @@ def test_on_progress_hook(cipher_signature, mocker):
|
|
61 |
callback_fn = mock.MagicMock()
|
62 |
cipher_signature.register_on_progress_callback(callback_fn)
|
63 |
|
64 |
-
mocker.patch.object(request, "
|
65 |
-
request.
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
]
|
70 |
with mock.patch("pytube.streams.open", mock.mock_open(), create=True):
|
71 |
stream = cipher_signature.streams.first()
|
72 |
stream.download()
|
@@ -81,12 +78,11 @@ def test_on_complete_hook(cipher_signature, mocker):
|
|
81 |
callback_fn = mock.MagicMock()
|
82 |
cipher_signature.register_on_complete_callback(callback_fn)
|
83 |
|
84 |
-
mocker.patch.object(request, "
|
85 |
-
request.
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
]
|
90 |
with mock.patch("pytube.streams.open", mock.mock_open(), create=True):
|
91 |
stream = cipher_signature.streams.first()
|
92 |
stream.download()
|
|
|
8 |
|
9 |
|
10 |
def test_filesize(cipher_signature, mocker):
|
11 |
+
mocker.patch.object(request, "headers")
|
12 |
+
request.headers.return_value = {"content-length": "6796391"}
|
13 |
assert cipher_signature.streams.first().filesize == 6796391
|
14 |
|
15 |
|
|
|
36 |
|
37 |
|
38 |
def test_download(cipher_signature, mocker):
|
39 |
+
mocker.patch.object(request, "headers")
|
40 |
+
request.headers.return_value = {"content-length": "16384"}
|
41 |
+
mocker.patch.object(request, "stream")
|
42 |
+
request.stream.return_value = iter([str(random.getrandbits(8 * 1024))])
|
|
|
|
|
43 |
with mock.patch("pytube.streams.open", mock.mock_open(), create=True):
|
44 |
stream = cipher_signature.streams.first()
|
45 |
stream.download()
|
|
|
59 |
callback_fn = mock.MagicMock()
|
60 |
cipher_signature.register_on_progress_callback(callback_fn)
|
61 |
|
62 |
+
mocker.patch.object(request, "headers")
|
63 |
+
request.headers.return_value = {"content-length": "16384"}
|
64 |
+
mocker.patch.object(request, "stream")
|
65 |
+
request.stream.return_value = iter([str(random.getrandbits(8 * 1024))])
|
66 |
+
|
|
|
67 |
with mock.patch("pytube.streams.open", mock.mock_open(), create=True):
|
68 |
stream = cipher_signature.streams.first()
|
69 |
stream.download()
|
|
|
78 |
callback_fn = mock.MagicMock()
|
79 |
cipher_signature.register_on_complete_callback(callback_fn)
|
80 |
|
81 |
+
mocker.patch.object(request, "headers")
|
82 |
+
request.headers.return_value = {"content-length": "16384"}
|
83 |
+
mocker.patch.object(request, "stream")
|
84 |
+
request.stream.return_value = iter([str(random.getrandbits(8 * 1024))])
|
85 |
+
|
|
|
86 |
with mock.patch("pytube.streams.open", mock.mock_open(), create=True):
|
87 |
stream = cipher_signature.streams.first()
|
88 |
stream.download()
|