Skip to content

Commit

Permalink
Merge pull request #53 from Fahreeve/v4
Browse files Browse the repository at this point in the history
replace aiosocksy to aiohttp-socks
rename Socks5Driver to ProxyDriver (suuports http, socks4, socks5 and TCP proxy)
rename methods in BaseDriver
add support iteration over LongPoll events
add AsyncVkExecuteRequestPool for execute method
update requirements version
drop support python3.5
rewrite tests with pytest
  • Loading branch information
Fahreeve authored Dec 19, 2020
2 parents 85098d1 + d1e7d57 commit c758eb2
Show file tree
Hide file tree
Showing 44 changed files with 1,142 additions and 1,575 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# Created by .ignore support plugin (hsz.mobi)
### Project files
# auth data
/tests/auth_data.py
/tests/captcha.jpg
.pytest_cache/

### Python template
# Byte-compiled / optimized / DLL files
Expand Down
73 changes: 65 additions & 8 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ Features
* support python 3.5+ versions
* have only one dependency - ``aiohttp 3+``
* support two-factor authentication
* support socks proxy with ``aiosocksy``
* support socks proxy with ``aiohttp-socks``
* support rate limit of requests
* support Long Poll connection

TODO
----
* replace ``aiosocksy`` to ``aiohttp-socks``
* need refactoring tests for ``AsyncVkExecuteRequestPool``

Install
-------
Expand Down Expand Up @@ -109,9 +109,9 @@ Drivers
.. code-block:: python
>>> driver = Socks5Driver(PROXY_ADDRESS, PORT) # 1234 is port
>>> driver = Socks5Driver(PROXY_ADDRESS, PORT, timeout=10)
>>> driver = Socks5Driver(PROXY_ADDRESS, PORT, PROXY_LOGIN, PROXY_PASSWORD, timeout=10)
>>> driver = ProxyDriver(PROXY_ADDRESS, PORT) # 1234 is port
>>> driver = ProxyDriver(PROXY_ADDRESS, PORT, timeout=10)
>>> driver = ProxyDriver(PROXY_ADDRESS, PORT, PROXY_LOGIN, PROXY_PASSWORD, timeout=10)
How to use custom driver with session:

Expand All @@ -125,7 +125,7 @@ How to use driver with own loop:
>>> loop = asyncio.get_event_loop()
>>> asyncio.set_event_loop(None)
>>> session = TokenSession(driver=HttpDriver(loop=loop)) # or Socks5Driver
>>> session = TokenSession(driver=HttpDriver(loop=loop)) # or ProxyDriver
How to use driver with custom http session object:

Expand Down Expand Up @@ -211,6 +211,14 @@ Use Session object
>>> await lp.get_pts(need_ts=True) # return pts, ts
191231223, 1820350345
You can iterate over events

.. code-block:: python
>>> async for event in lp.iter():
... print(event)
{"type":..., "object": {...}}
Notice that ``wait`` value only for long pool connection.

Real pause could be more ``wait`` time because of need time
Expand All @@ -225,7 +233,7 @@ Use exist API object
.. code-block:: python
>>> api = API(session)
>>> lp = BotsLongPoll(api, mode=2, group_id=1) # default wait=25
>>> lp = BotsLongPoll(api, group_id=1) # default wait=25
>>> await lp.wait()
{"ts":345,"updates":[...]}
>>> await lp.wait()
Expand All @@ -235,15 +243,64 @@ Use Session object

.. code-block:: python
>>> lp = BotsLongPoll(session, mode=2, group_id=1) # default wait=25
>>> lp = BotsLongPoll(session, group_id=1) # default wait=25
>>> await lp.wait()
{"ts":78455,"updates":[...]}
>>> await lp.get_pts() # return pts
191231223
>>> await lp.get_pts(need_ts=True) # return pts, ts
191231223, 1820350345
BotsLongPoll supports iterating too

.. code-block:: python
>>> async for event in lp.iter():
... print(event)
{"type":..., "object": {...}}
Notice that ``wait`` value only for long pool connection.

Real pause could be more ``wait`` time because of need time
for authorization (if needed), reconnect and etc.

Async execute request pool
--------------
For documentation, see: https://vk.com/dev/execute

.. code-block:: python
from aiovk.pools import AsyncVkExecuteRequestPool
async with AsyncVkExecuteRequestPool() as pool:
response = pool.add_call('users.get', 'YOUR_TOKEN', {'user_ids': 1})
response2 = pool.add_call('users.get', 'YOUR_TOKEN', {'user_ids': 2})
response3 = pool.add_call('users.get', 'ANOTHER_TOKEN', {'user_ids': 1})
response4 = pool.add_call('users.get', 'ANOTHER_TOKEN', {'user_ids': -1})
>>> print(response.ok)
True
>>> print(response.result)
[{'id': 1, 'first_name': 'Павел', 'last_name': 'Дуров'}]
>>> print(response2.result)
[{'id': 2, 'first_name': 'Александра', 'last_name': 'Владимирова'}]
>>> print(response3.result)
[{'id': 1, 'first_name': 'Павел', 'last_name': 'Дуров'}]
>>> print(response4.ok)
False
>>> print(response4.error)
{'method': 'users.get', 'error_code': 113, 'error_msg': 'Invalid user id'}
or

.. code-block:: python
from aiovk.pools import AsyncVkExecuteRequestPool
pool = AsyncVkExecuteRequestPool()
response = pool.add_call('users.get', 'YOUR_TOKEN', {'user_ids': 1})
response2 = pool.add_call('users.get', 'YOUR_TOKEN', {'user_ids': 2})
response3 = pool.add_call('users.get', 'ANOTHER_TOKEN', {'user_ids': 1})
response4 = pool.add_call('users.get', 'ANOTHER_TOKEN', {'user_ids': -1})
await pool.execute()
...
2 changes: 1 addition & 1 deletion aiovk/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = '3.0.0'
__version__ = '4.0.0'

from aiovk.sessions import ImplicitSession, TokenSession, AuthorizationCodeSession
from aiovk.api import API
Expand Down
7 changes: 2 additions & 5 deletions aiovk/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,9 @@ def __getattr__(self, method_name):

async def __call__(self, **method_args):
timeout = method_args.pop('timeout', None)
need_raw_response = method_args.pop('raw_response', False)
self._method_args = method_args
return await self._api._session.send_api_request(
self._method_name,
method_args,
timeout,
)
return await self._api._session.send_api_request(self._method_name, method_args, timeout, need_raw_response)


class LazyAPI:
Expand Down
74 changes: 36 additions & 38 deletions aiovk/drivers.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import aiohttp

try:
import aiosocksy
from aiosocksy.connector import ProxyConnector
from aiohttp_socks.connector import ProxyConnector
except ImportError as e:
ProxyConnector = None

Expand All @@ -12,32 +11,32 @@ def __init__(self, timeout=10, loop=None):
self.timeout = timeout
self._loop = loop

async def json(self, url, params, timeout=None):
'''
async def post_json(self, url, params, timeout=None):
"""
:param params: dict of query params
:return: dict from json response
'''
:return: http status code, dict from json response
"""
raise NotImplementedError

async def get_text(self, url, params, timeout=None):
'''
async def get_bin(self, url, params, timeout=None):
"""
:param params: dict of query params
:return: http status code, text body of response
'''
:return: http status code, binary body of response
"""
raise NotImplementedError

async def get_bin(self, url, params, timeout=None):
'''
async def get_text(self, url, params, timeout=None):
"""
:param params: dict of query params
:return: http status code, binary body of response
'''
:return: http status code, text body of response and redirect_url
"""
raise NotImplementedError

async def post_text(self, url, data, timeout=None):
'''
"""
:param data: dict pr string
:return: redirect url and text body of response
'''
:return: http status code, text body of response and redirect url
"""
raise NotImplementedError

async def close(self):
Expand All @@ -52,37 +51,36 @@ def __init__(self, timeout=10, loop=None, session=None):
else:
self.session = session

async def json(self, url, params, timeout=None):
# timeouts - https://docs.aiohttp.org/en/v3.0.0/client_quickstart.html#timeouts
async with self.session.get(url, params=params, timeout=timeout or self.timeout) as response:
return await response.json()
async def post_json(self, url, params, timeout=None):
async with self.session.post(url, data=params, timeout=timeout or self.timeout) as response:
return response.status, await response.json()

async def get_text(self, url, params, timeout=None):
async def get_bin(self, url, params, timeout=None):
async with self.session.get(url, params=params, timeout=timeout or self.timeout) as response:
return response.status, await response.text()
return response.status, await response.read()

async def get_bin(self, url, params, timeout=None):
async def get_text(self, url, params, timeout=None):
async with self.session.get(url, params=params, timeout=timeout or self.timeout) as response:
return await response.read()
return response.status, await response.text(), response.real_url

async def post_text(self, url, data, timeout=None):
async with self.session.post(url, data=data, timeout=timeout or self.timeout) as response:
return response._real_url, await response.text()
return response.status, await response.text(), response.real_url

async def close(self):
await self.session.close()


if ProxyConnector:
class Socks5Driver(HttpDriver):
connector = ProxyConnector
class ProxyDriver(HttpDriver):
connector = ProxyConnector

def __init__(self, address, port, login=None, password=None, timeout=10, loop=None):
addr = aiosocksy.Socks5Addr(address, port)
if login and password:
auth = aiosocksy.Socks5Auth(login, password=password)
else:
auth = None
conn = self.connector(proxy=addr, proxy_auth=auth, loop=loop)
session = aiohttp.ClientSession(connector=conn)
super().__init__(timeout, loop, session)
def __init__(self, address, port, login=None, password=None, timeout=10, **kwargs):
connector = ProxyConnector(
host=address,
port=port,
username=login,
password=password,
**kwargs
)
session = aiohttp.ClientSession(connector=connector)
super().__init__(timeout, kwargs.get('loop'), session)
9 changes: 4 additions & 5 deletions aiovk/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import urllib.parse
from aiovk.utils import get_request_params
from urllib.parse import urlencode


CAPTCHA_IS_NEEDED = 14
Expand All @@ -14,7 +13,7 @@ class VkAuthError(VkException):
def __init__(self, error, description, url='', params=''):
self.error = error
self.description = description
self.url = "{}?{}".format(url, urllib.parse.urlencode(params))
self.url = "{}?{}".format(url, urlencode(params))

def __str__(self):
return self.description
Expand All @@ -39,15 +38,15 @@ class VkAPIError(VkException):
def __init__(self, error, url):
self.error_code = error.get('error_code')
self.error_msg = error.get('error_msg')
self.params = get_request_params(error.get('request_params'))
self.params = {param['key']: param['value'] for param in error.get('request_params', [])}
self.url = url


class VkLongPollError(VkException):
def __init__(self, error, description, url='', params=''):
self.error = error
self.description = description
self.url = "{}?{}".format(url, urllib.parse.urlencode(params))
self.url = "{}?{}".format(url, urlencode(params))

def __str__(self):
return self.description
Loading

0 comments on commit c758eb2

Please sign in to comment.