Skip to content

Instantly share code, notes, and snippets.

@greut
Last active June 2, 2020 21:20
Show Gist options
  • Save greut/4dcd1b99381deed0b5b04b6865200ed6 to your computer and use it in GitHub Desktop.
Save greut/4dcd1b99381deed0b5b04b6865200ed6 to your computer and use it in GitHub Desktop.
Revamped api.py (with test and 100% coverage)
"""
Slack Web API
=============
The `Slack Web API`_ let you communicate with Slack.
Usage:
------
The following example calls the ``api.test`` method which test whether your
token is valid.
.. code-block:: python
import os
import asyncio
from votebot.api import call
token = os.environ['SLACK_TOKEN']
loop = asyncio.get_event_loop()
response = loop.run_until_complete(call('api.test',
token=token))
print(response)
loop.close()
.. _Slack Web API: https://api.slack.com/web/
"""
import json
from collections.abc import Mapping
from aiohttp import ClientSession, FormData
async def call(method, file=None, **kwargs):
"""
Perform an API call to Slack.
:param file: File pointer
:type file: file
:Keyword Arguments:
All the arguments required by the Slack API.
:return: JSON response.
:rtype: dict
"""
# JSON encode any sub-structure...
for k, w in kwargs.items():
# list, tuple or dict but not a str.
if isinstance(w, (Mapping, list, tuple)):
kwargs[k] = json.dumps(w)
form = FormData(kwargs)
# Handle file upload
if file:
form.add_field('file', file)
with ClientSession() as session:
async with session.post('https://slack.com/api/{0}'.format(method),
data=form) as response:
assert 200 == response.status, response
return await response.json()
from urllib.parse import urlencode
import pytest
from asynctest import patch
from votebot.api import call
@pytest.fixture(scope='session')
def hello_file(tmpdir_factory):
fn = tmpdir_factory.mktemp('data').join('hello.txt')
fn.write('Hello world!\n')
return str(fn)
class MockClientSession:
def __enter__(self):
return MockSession()
def __exit__(self, *args):
pass
class MockSession:
def post(self, *args, **kwargs):
return MockRequest(*args, **kwargs)
class MockRequest:
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
async def __aenter__(self):
return MockResponse(200, *self.args, **self.kwargs)
async def __aexit__(self, *args):
pass
class MockResponse:
def __init__(self, status, *args, **kwargs):
self.status = status
self.args = args
self.kwargs = kwargs
async def json(self):
return {'ok': False,
'error': 'I am a mock',
'args': self.args,
'kwargs': self.kwargs}
@pytest.mark.asyncio
async def test_api_simple():
with patch('votebot.api.ClientSession', new=MockClientSession):
response = await call('api.test', token='xoxb-123')
assert not response['ok']
assert 'I am a mock' == response['error']
assert ('https://slack.com/api/api.test',) == response['args']
data = response['kwargs']['data']('utf-8')
assert b'token=xoxb-123' == data
@pytest.mark.asyncio
async def test_api_subfields():
with patch('votebot.api.ClientSession', new=MockClientSession):
response = await call('api.dummy', fields=[1, 2, 3])
data = response['kwargs']['data']('utf-8')
assert urlencode({'fields': '[1, 2, 3]'}).encode('utf-8') == data
@pytest.mark.asyncio
async def test_api_file(hello_file):
with patch('votebot.api.ClientSession', new=MockClientSession):
with open(hello_file, 'r', encoding='utf-8') as f:
response = await call('api.file', file=f)
data = response['kwargs']['data']
assert data.is_multipart
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment