import asyncio from urllib.parse import urlencode import aiohttp import async_timeout import requests import slacker from .compat import PY_350, ensure_future __version__ = '0.0.11' Error = slacker.Error Response = slacker.Response class BaseAPI(slacker.BaseAPI): def __init__( self, token=None, timeout=slacker.DEFAULT_TIMEOUT, *, loop=None ): if loop is None: loop = asyncio.get_event_loop() self.loop = loop self.session = aiohttp.ClientSession( connector=aiohttp.TCPConnector( use_dns_cache=False, loop=self.loop, ), ) self.methods = { requests.get: 'GET', requests.post: 'POST', } self.futs = set() super().__init__(token=token, timeout=timeout) @asyncio.coroutine def __request(self, method, api, **kwargs): method = self.methods[method] kwargs.setdefault('params', {}) kwargs.setdefault('timeout', None) if self.token: kwargs['params']['token'] = self.token kwargs['params'] = urlencode(kwargs['params'], doseq=True) if method == 'POST': files = kwargs.pop('files', None) if files is not None: data = kwargs.pop('data', {}) _data = aiohttp.FormData() for k, v in files.items(): _data.add_field(k, open(v.name, 'rb')) for k, v in data.items(): if v is not None: _data.add_field(k, str(v)) kwargs['data'] = _data _url = slacker.API_BASE_URL.format(api=api) _request = self.session.request(method, _url, **kwargs) _response = None try: with async_timeout.timeout(self.timeout, loop=self.loop): _response = yield from _request _response.raise_for_status() text = yield from _response.text() finally: if _response is not None: yield from _response.release() response = Response(text) if not response.successful: raise Error(response.error) return response def _request(self, method, api, **kwargs): coro = self.__request(method, api, **kwargs) fut = ensure_future(coro, loop=self.loop) self.futs.add(fut) fut.add_done_callback(self.futs.remove) return fut @asyncio.coroutine def close(self): if self.futs: yield from asyncio.gather( *self.futs, loop=self.loop, return_exceptions=True ) yield from self.session.close() class IM(BaseAPI, slacker.IM): pass class API(BaseAPI, slacker.API): pass class DND(BaseAPI, slacker.DND): pass class RTM(BaseAPI, slacker.RTM): pass class Auth(BaseAPI, slacker.Auth): pass class Bots(BaseAPI, slacker.Bots): pass class Chat(BaseAPI, slacker.Chat): pass class TeamProfile(BaseAPI, slacker.TeamProfile): pass class Team(BaseAPI, slacker.Team): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._profile = TeamProfile(*args, **kwargs) def close(self): coros = [ super().close(), self._profile.close(), ] return asyncio.gather( *coros, loop=self.loop, return_exceptions=True ) class Pins(BaseAPI, slacker.Pins): pass class MPIM(BaseAPI, slacker.MPIM): pass class UsersProfile(BaseAPI, slacker.UsersProfile): pass class Users(BaseAPI, slacker.Users): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._profile = UsersProfile(*args, **kwargs) def close(self): coros = [ super().close(), self._profile.close(), ] return asyncio.gather( *coros, loop=self.loop, return_exceptions=True ) class FilesComments(BaseAPI, slacker.FilesComments): pass class Files(BaseAPI, slacker.Files): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._comments = FilesComments(*args, **kwargs) def close(self): coros = [ super().close(), self._comments.close(), ] return asyncio.gather( *coros, loop=self.loop, return_exceptions=True ) class Stars(BaseAPI, slacker.Stars): pass class Emoji(BaseAPI, slacker.Emoji): pass class Search(BaseAPI, slacker.Search): pass class Groups(BaseAPI, slacker.Groups): pass class Channels(BaseAPI, slacker.Channels): pass class Presence(BaseAPI, slacker.Presence): pass class Reminders(BaseAPI, slacker.Reminders): pass class Reactions(BaseAPI, slacker.Reactions): pass class IDPGroups(BaseAPI, slacker.IDPGroups): pass class UserGroupsUsers(BaseAPI, slacker.UserGroupsUsers): pass class UserGroups(BaseAPI, slacker.UserGroups): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._users = UserGroupsUsers(*args, **kwargs) def close(self): coros = [ super().close(), self._users.close(), ] return asyncio.gather( *coros, loop=self.loop, return_exceptions=True ) class IncomingWebhook(BaseAPI, slacker.IncomingWebhook): def __init__( self, url=None, timeout=slacker.DEFAULT_TIMEOUT, *, loop=None ): self.url = url super().__init__(token=None, timeout=timeout, loop=loop) @asyncio.coroutine def post(self, data): if not self.url: raise slacker.Error('URL for incoming webhook is undefined') _request = self.session.request( 'POST', self.url, data=data, timeout=None, ) _response = None try: with async_timeout.timeout(self.timeout, loop=self.loop): _response = yield from _request _response.raise_for_status() _json = yield from _response.json() finally: if _response is not None: yield from _response.release() return _json class Slacker(slacker.Slacker): def __init__( self, token, incoming_webhook_url=None, timeout=slacker.DEFAULT_TIMEOUT, *, loop=None ): if loop is None: loop = asyncio.get_event_loop() self.loop = loop self.im = IM( token=token, timeout=timeout, loop=self.loop, ) self.api = API( token=token, timeout=timeout, loop=self.loop, ) self.dnd = DND( token=token, timeout=timeout, loop=self.loop, ) self.rtm = RTM( token=token, timeout=timeout, loop=self.loop, ) self.auth = Auth( token=token, timeout=timeout, loop=self.loop, ) self.bots = Bots( token=token, timeout=timeout, loop=self.loop, ) self.chat = Chat( token=token, timeout=timeout, loop=self.loop, ) self.team = Team( token=token, timeout=timeout, loop=self.loop, ) self.pins = Pins( token=token, timeout=timeout, loop=self.loop, ) self.mpim = MPIM( token=token, timeout=timeout, loop=self.loop, ) self.users = Users( token=token, timeout=timeout, loop=self.loop, ) self.files = Files( token=token, timeout=timeout, loop=self.loop, ) self.stars = Stars( token=token, timeout=timeout, loop=self.loop, ) self.emoji = Emoji( token=token, timeout=timeout, loop=self.loop, ) self.search = Search( token=token, timeout=timeout, loop=self.loop, ) self.groups = Groups( token=token, timeout=timeout, loop=self.loop, ) self.channels = Channels( token=token, timeout=timeout, loop=self.loop, ) self.presence = Presence( token=token, timeout=timeout, loop=self.loop, ) self.reminders = Reminders( token=token, timeout=timeout, loop=self.loop, ) self.reactions = Reactions( token=token, timeout=timeout, loop=self.loop, ) self.idpgroups = IDPGroups( token=token, timeout=timeout, loop=self.loop, ) self.usergroups = UserGroups( token=token, timeout=timeout, loop=self.loop, ) self.incomingwebhook = IncomingWebhook( url=incoming_webhook_url, timeout=timeout, loop=self.loop, ) def close(self): coros = [ self.im.close(), self.api.close(), self.dnd.close(), self.rtm.close(), self.auth.close(), self.bots.close(), self.chat.close(), self.team.close(), self.pins.close(), self.mpim.close(), self.users.close(), self.files.close(), self.stars.close(), self.emoji.close(), self.search.close(), self.groups.close(), self.channels.close(), self.presence.close(), self.reminders.close(), self.reactions.close(), self.idpgroups.close(), self.usergroups.close(), self.incomingwebhook.close(), ] return asyncio.gather( *coros, loop=self.loop, return_exceptions=True ) if PY_350: @asyncio.coroutine def __aenter__(self): # noqa return self @asyncio.coroutine def __aexit__(self, *exc_info): # noqa yield from self.close()