Skip to content

Commit 2ce2f6b

Browse files
committed
Fix VkRequestsPool to work with any types
1 parent 5f5572e commit 2ce2f6b

5 files changed

Lines changed: 258 additions & 189 deletions

File tree

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
build/
22
dist/
33
*.pyc
4+
MANIFEST
45
.project
56
.pydevproject
67
.settings/
7-
/testing
8+
testing/
9+
tests/config.py
10+
tests/vk_config.json

MANIFEST

Lines changed: 0 additions & 8 deletions
This file was deleted.

vk_api/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@
1414
__contact__ = 'https://vk.com/python273'
1515

1616
from .vk_api import *
17-
from .vk_upload import *
18-
from .vk_tools import *
17+
from .vk_upload import VkUpload
18+
from .vk_tools import VkTools
19+
from .vk_requestspool import VkRequestsPool

vk_api/vk_requestspool.py

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
# -*- coding: utf-8 -*-
2+
3+
import sys
4+
from collections import namedtuple
5+
6+
try:
7+
import simplejson as json
8+
except ImportError:
9+
import json
10+
11+
12+
if sys.version_info.major == 2:
13+
range = xrange
14+
15+
PoolRequest = namedtuple('PoolRequest', ['method', 'values', 'result'])
16+
17+
18+
class RequestResult(object):
19+
def __init__(self):
20+
self._result = None
21+
self.ready = False
22+
self.error = False
23+
24+
def set_result(self, result):
25+
self._result = result
26+
self.ready = True
27+
28+
def set_error(self, error):
29+
self.error = error
30+
self.ready = True
31+
32+
@property
33+
def ok(self):
34+
return not self.error
35+
36+
@property
37+
def result(self):
38+
if not self.ready:
39+
raise Exception('Result is not ready')
40+
41+
if self.error:
42+
raise Exception('Got error while executing request')
43+
44+
return self._result
45+
46+
47+
class VkRequestsPool(object):
48+
""" Позволяет сделать несколько обращений к API за один запрос
49+
за счет метода execute
50+
"""
51+
52+
__slots__ = ('vk', 'pool', 'one_param', 'execute_errors')
53+
54+
def __init__(self, vk):
55+
self.vk = vk
56+
self.pool = []
57+
self.one_param = {}
58+
self.execute_errors = []
59+
60+
def __enter__(self):
61+
return self
62+
63+
def __exit__(self, *args, **kwargs):
64+
if self.one_param:
65+
self.execute_one_param()
66+
else:
67+
self.execute()
68+
69+
def get_execute_errors(self):
70+
return self.execute_errors
71+
72+
def method(self, method, values=None):
73+
""" Добавляет запрос в пулл
74+
75+
:param method: метод
76+
:type method: basestring
77+
78+
:param values: параметры
79+
:type values: dict
80+
81+
:rtype: RequestResult
82+
"""
83+
84+
if self.one_param:
85+
raise Exception('One param mode is not working with self.method')
86+
87+
if values is None:
88+
values = {}
89+
90+
result = RequestResult()
91+
self.pool.append(PoolRequest(method, values, result))
92+
93+
return result
94+
95+
def method_one_param(self, method, key, values, default_values=None):
96+
""" Использовать, если изменяется значение только одного параметра
97+
98+
:param method: метод
99+
:type method: basestring
100+
101+
:param default_values: одинаковые значения для запросов
102+
:type default_values: dict
103+
104+
:param key: ключ изменяющегося параметра
105+
:type key: basestring
106+
107+
:param values: список значений изменяющегося параметра (max: 25)
108+
:type values: list
109+
110+
:rtype: RequestResult
111+
"""
112+
113+
if not self.one_param and self.pool:
114+
raise Exception('One param mode is not working with self.method')
115+
116+
if default_values is None:
117+
default_values = {}
118+
119+
self.one_param = {
120+
'method': method,
121+
'default': default_values,
122+
'key': key,
123+
'return': RequestResult()
124+
}
125+
126+
self.pool = values
127+
128+
return self.one_param['return']
129+
130+
def execute(self):
131+
for i in range(0, len(self.pool), 25):
132+
cur_pool = self.pool[i:i + 25]
133+
134+
if check_one_method(cur_pool):
135+
code = gen_code_one_method(cur_pool)
136+
else:
137+
code = gen_code_many_methods(cur_pool)
138+
139+
response_raw = self.vk.method('execute', {'code': code}, raw=True)
140+
141+
response = response_raw['response']
142+
response_errors = response_raw.get('execute_errors')
143+
144+
if response_errors:
145+
self.execute_errors += response_errors[:-1]
146+
147+
for x, r in enumerate(response):
148+
if r is not False:
149+
cur_pool[x].result.set_result(r)
150+
else:
151+
cur_pool[x].result.set_error(True)
152+
153+
def execute_one_param(self):
154+
result = {}
155+
156+
for i in range(0, len(self.pool), 25):
157+
cur_pool = self.pool[i:i + 25]
158+
159+
code = gen_code_one_param(
160+
cur_pool,
161+
self.one_param['default'],
162+
self.one_param['key'],
163+
self.one_param['method']
164+
)
165+
166+
response_raw = self.vk.method('execute', {'code': code}, raw=True)
167+
168+
response = response_raw['response']
169+
response_errors = response_raw.get('execute_errors')
170+
171+
if response_errors:
172+
self.execute_errors += response_errors[:-1]
173+
174+
for x, r in enumerate(response):
175+
if r is not False:
176+
result[cur_pool[x]] = r
177+
178+
self.one_param['return'].set_result(result)
179+
180+
181+
def sjson_dumps(*args, **kwargs):
182+
kwargs['ensure_ascii'] = False
183+
kwargs['separators'] = (',', ':')
184+
185+
return json.dumps(*args, **kwargs)
186+
187+
188+
def check_one_method(pool):
189+
""" Возвращает True, если все запросы в пулле к одному методу """
190+
191+
if not pool:
192+
return False
193+
194+
first_method = pool[0].method
195+
return all(req.method == first_method for req in pool[1:])
196+
197+
198+
def gen_code_one_method(pool):
199+
""" Генерирует код для одного метода
200+
(если в пулле запросы к одному методу)
201+
"""
202+
203+
method = pool[0].method
204+
list_values = [i.values for i in pool]
205+
206+
return code_requestspoll_one_method % (
207+
sjson_dumps(list_values), method
208+
)
209+
210+
211+
def gen_code_one_param(pool, default_values, key, method):
212+
""" Генерирует код для одного метода и одного меняющегося параметра
213+
(если в пулле запросы к одному методу, с одним меняющимся параметром)
214+
"""
215+
216+
return code_requestspoll_one_param % (
217+
sjson_dumps(default_values),
218+
sjson_dumps(pool),
219+
key,
220+
method
221+
)
222+
223+
224+
def gen_code_many_methods(pool):
225+
""" Генерирует код для нескольких методов """
226+
227+
requests = ','.join(
228+
'API.{}({})'.format(i.method, sjson_dumps(i.values))
229+
for i in pool
230+
)
231+
232+
return 'return [{}];'.format(requests)
233+
234+
235+
# Полный код в файле vk_procedures
236+
code_get_all_items = """
237+
var m=%s,n=%s,b="%s",v=n;var c={count:m,offset:v}+%s;var r=API.%s(c),k=r.count,
238+
j=r[b],i=1;while(i<25&&v+m<=k){v=i*m+n;c.offset=v;j=j+API.%s(c)[b];i=i+1;}
239+
return {count:k,items:j,offset:v+m};
240+
""".replace('\n', '')
241+
242+
code_requestspoll_one_method = """
243+
var p=%s,i=0,r=[];while(i<p.length){r.push(API.%s(p[i]));i=i+1;}return r;
244+
""".replace('\n', '')
245+
246+
code_requestspoll_one_param = """
247+
var d=%s,v=%s,r=[],i=0;while(i<v.length){d.%s=v[i];r.push(API.%s(d));i=i+1;};
248+
return r;
249+
""".replace('\n', '')

0 commit comments

Comments
 (0)