From 280787e641f906cb1aa4f62650732f081f1362eb Mon Sep 17 00:00:00 2001 From: Sergey Gaynetdinov Date: Mon, 3 Dec 2018 16:32:48 +0500 Subject: [PATCH 1/4] Send payload use POST method --- requirements-dev.txt | 3 ++- tests/test_fetch.py | 18 ++++++++++++++++++ vk/fetch.py | 10 +++++++--- 3 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 tests/test_fetch.py diff --git a/requirements-dev.txt b/requirements-dev.txt index e36326f..43861ef 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,2 +1,3 @@ pytest -isort \ No newline at end of file +isort +pytest-mock \ No newline at end of file diff --git a/tests/test_fetch.py b/tests/test_fetch.py new file mode 100644 index 0000000..24e2257 --- /dev/null +++ b/tests/test_fetch.py @@ -0,0 +1,18 @@ +import vk + + +def test_url_open(mocker): + mocker.patch('vk.fetch.urlopen') + + mock_json = mocker.patch('json.load') + mock_json.return_value = {'response': [{ + "id": 1, + "first_name": "Павел", + "last_name": "Дуров", + "domain": "durov", + }]} + + api = vk.Api('TOKEN') + user = api.get_user('durov') + + assert user.domain == 'durov' diff --git a/vk/fetch.py b/vk/fetch.py index 09aff2d..9f2a7e7 100644 --- a/vk/fetch.py +++ b/vk/fetch.py @@ -5,7 +5,7 @@ try: from urllib.parse import urlencode - from urllib.request import urlopen + from urllib.request import urlopen, Request except ImportError: from urllib import urlencode, urlopen @@ -40,9 +40,13 @@ def fetch(self, method_name, **params): params = {key: value for key, value in params.items() if value is not None} - url = url + "?" + urlencode(params) + request = Request(url, data=urlencode(params).encode()) + res = urlopen(request) - data_json = self.url_open(url) + try: + data_json = json.load(res) + except ValueError: + raise VKParseJsonError if 'error' in data_json: error = data_json['error'] From e947e06398e11fc31d45e93d874ad8134bedceb2 Mon Sep 17 00:00:00 2001 From: Sergey Gaynetdinov Date: Mon, 3 Dec 2018 18:26:13 +0500 Subject: [PATCH 2/4] Fix PEP8 --- vk/fetch.py | 1 - 1 file changed, 1 deletion(-) diff --git a/vk/fetch.py b/vk/fetch.py index 9f2a7e7..55210b8 100644 --- a/vk/fetch.py +++ b/vk/fetch.py @@ -10,7 +10,6 @@ from urllib import urlencode, urlopen - class Session(object): def __init__(self, access_token=None, lang='ru', version_api='5.63'): self.access_token = access_token From cad9600391bdae8dacb21579da835904070f3ca0 Mon Sep 17 00:00:00 2001 From: Sergey Gaynetdinov Date: Tue, 4 Dec 2018 01:01:05 +0500 Subject: [PATCH 3/4] Upload photo use `urllib` --- tests/test_fetch.py | 13 +++++++++++++ vk/fetch.py | 43 +++++++++++++++++++++++++++++-------------- vk/groups.py | 3 +-- vk/photos.py | 4 ++-- 4 files changed, 45 insertions(+), 18 deletions(-) diff --git a/tests/test_fetch.py b/tests/test_fetch.py index 24e2257..711b724 100644 --- a/tests/test_fetch.py +++ b/tests/test_fetch.py @@ -1,4 +1,7 @@ +import io + import vk +from vk.fetch import Session def test_url_open(mocker): @@ -16,3 +19,13 @@ def test_url_open(mocker): user = api.get_user('durov') assert user.domain == 'durov' + + +def test_upload_photo(): + file_obj = io.BytesIO(b'Python developer and blogger.') + data, boundary = Session()._file_upload(file_obj) + + assert b'Content-Disposition: file; name="photo"; filename="photo.jpg"' in data + assert b'Content-Type: application/octet-stream' in data + assert b'Python developer and blogger.' in data + assert boundary.encode() in data diff --git a/vk/fetch.py b/vk/fetch.py index 55210b8..d16bdd8 100644 --- a/vk/fetch.py +++ b/vk/fetch.py @@ -1,5 +1,7 @@ # coding=utf-8 +import io import json +import uuid from .error import VKError, VKParseJsonError @@ -16,18 +18,6 @@ def __init__(self, access_token=None, lang='ru', version_api='5.63'): self.lang = lang self.version_api = version_api - @staticmethod - def url_open(url, data=None): - data = data or {} - res = urlopen(url, data=data) - - try: - data_json = json.loads(res.read()) - except ValueError: - raise VKParseJsonError - - return data_json - def fetch(self, method_name, **params): url = "https://api.vk.com/method/{method_name}".format(method_name=method_name) params['v'] = self.version_api @@ -83,8 +73,19 @@ def fetch_items(self, method_name, constructor_from_json, count, **params): offset += count - def fetch_post(self, url, **kwargs): - return self.url_open(url, data=kwargs) + def fetch_photo(self, url, file_obj): + data, boundary = self._file_upload(file_obj) + + req = Request(url, data=data) + req.add_header('Content-type', 'multipart/form-data; boundary={0}'.format(boundary)) + req.add_header('Content-length', len(data)) + + res = urlopen(req) + + try: + return json.load(res) + except ValueError: + raise VKParseJsonError def _convert_list2str(self, fields): """ @@ -94,3 +95,17 @@ def _convert_list2str(self, fields): if isinstance(fields, tuple) or isinstance(fields, list): return ','.join(fields) return fields + + def _file_upload(self, file_obj): + boundary = uuid.uuid4().hex + + buffer = io.BytesIO() + buffer.write('--{0}\r\n'.format(boundary).encode('utf-8')) + buffer.write('Content-Disposition: file; name="photo"; filename="photo.jpg"\r\n'.encode('utf-8')) + buffer.write('Content-Type: application/octet-stream\r\n'.encode('utf-8')) + buffer.write(b'\r\n') + buffer.write(file_obj.read()) + buffer.write(b'\r\n') + buffer.write('--{0}--\r\n'.format(boundary).encode('utf-8')) + + return buffer.getvalue(), boundary diff --git a/vk/groups.py b/vk/groups.py index d02c832..e6f7a70 100644 --- a/vk/groups.py +++ b/vk/groups.py @@ -67,8 +67,7 @@ def get_walls_count(self): def set_cover_photo(self, file_like, width, height): upload_url = Photo._get_owner_cover_photo_upload_server(self._session, self.id, crop_x2=width, crop_y2=height) - files = {'photo': file_like} - response_json = self._session.fetch_post(upload_url, files=files) + response_json = self._session.fetch_photo(upload_url, file_like) Photo._save_owner_cover_photo(self._session, response_json['hash'], response_json['photo']) diff --git a/vk/photos.py b/vk/photos.py index e38c744..25a6b78 100644 --- a/vk/photos.py +++ b/vk/photos.py @@ -81,7 +81,7 @@ def _upload_wall_photos_for_group(session, group_id, image_files): attachments = [] for image_fd in image_files: - response_json = session.fetch_post(upload_url, files={'photo': image_fd}) + response_json = session.fetch_photo(upload_url, image_fd) photo, server, _hash = response_json['photo'], response_json['server'], response_json['hash'] photo_id, owner_id = Photo._get_save_wall_photo(session, photo, server, _hash, group_id=group_id) attachments.append("photo{0}_{1}".format(owner_id, photo_id)) @@ -110,7 +110,7 @@ def _upload_messages_photos_for_group(session, user_id, image_files): attachments = [] for image_fd in image_files: - response_json = session.fetch_post(upload_url, files={'photo': image_fd}) + response_json = session.fetch_photo(upload_url, image_fd) photo, server, _hash = response_json['photo'], response_json['server'], response_json['hash'] photo_id, owner_id = Photo._get_save_messages_photo(session, photo, server, _hash) attachments.append("photo{0}_{1}".format(owner_id, photo_id)) From b70629735becb4b66ae323598089ac65e1aac7e6 Mon Sep 17 00:00:00 2001 From: Sergey Gaynetdinov Date: Tue, 4 Dec 2018 01:03:52 +0500 Subject: [PATCH 4/4] Replace `.encode('utf-8') => `.encode()` --- vk/fetch.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vk/fetch.py b/vk/fetch.py index d16bdd8..34c8cff 100644 --- a/vk/fetch.py +++ b/vk/fetch.py @@ -100,12 +100,12 @@ def _file_upload(self, file_obj): boundary = uuid.uuid4().hex buffer = io.BytesIO() - buffer.write('--{0}\r\n'.format(boundary).encode('utf-8')) - buffer.write('Content-Disposition: file; name="photo"; filename="photo.jpg"\r\n'.encode('utf-8')) - buffer.write('Content-Type: application/octet-stream\r\n'.encode('utf-8')) + buffer.write('--{0}\r\n'.format(boundary).encode()) + buffer.write('Content-Disposition: file; name="photo"; filename="photo.jpg"\r\n'.encode()) + buffer.write('Content-Type: application/octet-stream\r\n'.encode()) buffer.write(b'\r\n') buffer.write(file_obj.read()) buffer.write(b'\r\n') - buffer.write('--{0}--\r\n'.format(boundary).encode('utf-8')) + buffer.write('--{0}--\r\n'.format(boundary).encode()) return buffer.getvalue(), boundary