Skip to content

Commit

Permalink
Merge pull request #9 from oklahomer/feature/pycharm5
Browse files Browse the repository at this point in the history
Trying out PyCharm 5 EAP
  • Loading branch information
oklahomer committed Nov 8, 2015
2 parents 4484f8d + 668ddb4 commit 11c7e38
Show file tree
Hide file tree
Showing 18 changed files with 117 additions and 107 deletions.
36 changes: 20 additions & 16 deletions sarah/bot/base.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
# -*- coding: utf-8 -*-
import abc
from collections import OrderedDict
from concurrent.futures import ThreadPoolExecutor, Future
from functools import wraps
import imp
import importlib
import inspect
import logging
import re
import sys
from collections import OrderedDict
from concurrent.futures import ThreadPoolExecutor, Future
from functools import wraps

from apscheduler.schedulers.background import BackgroundScheduler

from typing import Sequence, Optional, Callable, Union
from typing import Optional, Callable, Union, Iterable

from sarah.bot.types import PluginConfig, AnyFunction, CommandFunction
from sarah.bot.values import Command, CommandMessage, UserContext, \
Expand All @@ -25,7 +25,7 @@ class Base(object, metaclass=abc.ABCMeta):
__instances = {}

def __init__(self,
plugins: Sequence[PluginConfig] = None,
plugins: Iterable[PluginConfig] = None,
max_workers: Optional[int] = None) -> None:
if not plugins:
plugins = ()
Expand Down Expand Up @@ -214,17 +214,19 @@ def wrapper(func: CommandFunction) -> None:
def wrapped_function(*args, **kwargs) -> str:
return func(*args, **kwargs)

# Register only if bot is instantiated.
module = inspect.getmodule(func)
self = cls.__instances.get(cls.__name__, None)
if self:
config = self.plugin_config.get(func.__module__, {})
# Register only if bot is instantiated.
if self and module:
module_name = module.__name__
config = self.plugin_config.get(module_name, {})
schedule_config = config.get('schedule', None)
if schedule_config:
# If command name duplicates, update with the later one.
# The order stays.
command = ScheduledCommand(name,
wrapped_function,
func.__module__,
module_name,
config,
schedule_config)
try:
Expand All @@ -238,14 +240,14 @@ def wrapped_function(*args, **kwargs) -> str:
else:
logging.warning(
'Missing configuration for schedule job. %s. '
'Skipping.' % func.__module__)
'Skipping.' % module_name)

# To ease plugin's unit test
return wrapped_function

return wrapper

def add_schedule_jobs(self, commands: Sequence[ScheduledCommand]) -> None:
def add_schedule_jobs(self, commands: Iterable[ScheduledCommand]) -> None:
for command in commands:
# self.add_schedule_job(command)
job_function = self.generate_schedule_job(command)
Expand Down Expand Up @@ -273,14 +275,16 @@ def wrapper(func: CommandFunction) -> CommandFunction:
def wrapped_function(*args, **kwargs) -> Union[str, UserContext]:
return func(*args, **kwargs)

# Register only if bot is instantiated.
module = inspect.getmodule(func)
self = cls.__instances.get(cls.__name__, None)
if self:
config = self.plugin_config.get(func.__module__, {})
# Register only if bot is instantiated.
if self and module:
module_name = module.__name__
config = self.plugin_config.get(module_name, {})
# If command name duplicates, update with the later one.
# The order stays.

command = Command(name, func, func.__module__, config)
command = Command(name, func, module_name, config)
try:
# If command is already registered, updated it.
idx = [c.name for c in cls.__commands[cls.__name__]] \
Expand Down
30 changes: 14 additions & 16 deletions sarah/bot/hipchat.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,38 @@
# -*- coding: utf-8 -*-
from concurrent.futures import Future
import logging
from concurrent.futures import Future

from sleekxmpp import ClientXMPP, Message
from sleekxmpp.exceptions import IqTimeout, IqError
from typing import Dict, Optional, Sequence, Callable
from typing import Dict, Optional, Callable, Iterable

from sarah.exceptions import SarahException
from sarah.bot import Base, concurrent
from sarah.bot.values import ScheduledCommand
from sarah.bot.types import PluginConfig
from sarah.bot.values import ScheduledCommand
from sarah.exceptions import SarahException


class HipChat(Base):
def __init__(self,
plugins: Sequence[PluginConfig]=None,
jid: str='',
password: str='',
rooms: Sequence[str]=None,
nick: str='',
proxy: Dict=None,
max_workers: int=None) -> None:
plugins: Iterable[PluginConfig] = None,
jid: str = '',
password: str = '',
rooms: Iterable[str] = None,
nick: str = '',
proxy: Dict = None,
max_workers: int = None) -> None:

super().__init__(plugins=plugins, max_workers=max_workers)

if not rooms:
rooms = []
self.rooms = rooms
self.rooms = rooms if rooms else [] # type: Iterable[str]
self.nick = nick
self.client = self.setup_xmpp_client(jid, password, proxy)

def generate_schedule_job(self,
command: ScheduledCommand) -> Optional[Callable]:
# pop room configuration to leave minimal information for command
# argument
rooms = command.schedule_config.pop('rooms', None)
rooms = command.schedule_config.pop('rooms', [])
if not rooms:
logging.warning(
'Missing rooms configuration for schedule job. %s. '
Expand All @@ -61,7 +59,7 @@ def connect(self) -> None:
def setup_xmpp_client(self,
jid: str,
password: str,
proxy: Dict=None) -> ClientXMPP:
proxy: Dict = None) -> ClientXMPP:
client = ClientXMPP(jid, password)

if proxy:
Expand Down
4 changes: 2 additions & 2 deletions sarah/bot/plugins/bmw_quotes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
import random

from typing import Dict
from sarah.bot.values import CommandMessage

from sarah.bot.hipchat import HipChat
from sarah.bot.slack import Slack, SlackMessage, MessageAttachment

from sarah.bot.values import CommandMessage

# http://www.imdb.com/title/tt0105958/quotes
quotes = ([('Eric', "So i said to myself, 'Kyle'"),
Expand Down
3 changes: 2 additions & 1 deletion sarah/bot/plugins/echo.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
from typing import Dict
from sarah.bot.values import CommandMessage

from sarah.bot.hipchat import HipChat
from sarah.bot.slack import Slack
from sarah.bot.values import CommandMessage


# noinspection PyUnusedLocal
Expand Down
2 changes: 1 addition & 1 deletion sarah/bot/plugins/hello.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from typing import Dict
from sarah.bot.values import CommandMessage, UserContext, InputOption

from sarah.bot.hipchat import HipChat
from sarah.bot.values import CommandMessage, UserContext, InputOption


# noinspection PyUnusedLocal
Expand Down
2 changes: 1 addition & 1 deletion sarah/bot/plugins/simple_counter.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
from typing import Dict
from sarah.bot.values import CommandMessage

from sarah.bot.hipchat import HipChat
from sarah.bot.slack import Slack
from sarah.bot.values import CommandMessage

__stash = {'hipchat': {},
'slack': {}}
Expand Down
72 changes: 36 additions & 36 deletions sarah/bot/slack.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
# -*- coding: utf-8 -*-
# https://api.slack.com/rtm
from concurrent.futures import Future
import json
import logging
from concurrent.futures import Future

from typing import Optional, Dict, Sequence, Callable
import requests
from typing import Optional, Dict, Callable, Iterable
from websocket import WebSocketApp
from sarah import ValueObject

from sarah.exceptions import SarahException
from sarah import ValueObject
from sarah.bot import Base, concurrent
from sarah.bot.values import RichMessage, ScheduledCommand
from sarah.bot.types import PluginConfig
from sarah.bot.values import RichMessage, ScheduledCommand
from sarah.exceptions import SarahException


class SlackClient(object):
def __init__(self,
token: str,
base_url: str='https://slack.com/api/') -> None:
base_url: str = 'https://slack.com/api/') -> None:
self.base_url = base_url
self.token = token

Expand All @@ -36,8 +36,8 @@ def post(self, method, params=None, data=None) -> Dict:
def request(self,
http_method: str,
method: str,
params: Dict=None,
data: Dict=None) -> Dict:
params: Dict = None,
data: Dict = None) -> Dict:
http_method = http_method.upper()
endpoint = self.generate_endpoint(method)

Expand All @@ -61,7 +61,7 @@ def request(self,


class AttachmentField(ValueObject):
def __init__(self, title: str, value: str, short: bool=None):
def __init__(self, title: str, value: str, short: bool = None):
pass

def to_dict(self):
Expand All @@ -81,15 +81,15 @@ class MessageAttachment(ValueObject):
def __init__(self,
fallback: str,
title: str,
title_link: str=None,
author_name: str=None,
author_link: str=None,
author_icon: str=None,
fields: Sequence[AttachmentField]=None,
image_url: str=None,
thumb_url: str=None,
pretext: str=None,
color: str=None):
title_link: str = None,
author_name: str = None,
author_link: str = None,
author_icon: str = None,
fields: Iterable[AttachmentField] = None,
image_url: str = None,
thumb_url: str = None,
pretext: str = None,
color: str = None):
pass

def to_dict(self):
Expand All @@ -109,16 +109,16 @@ def to_dict(self):

class SlackMessage(RichMessage):
def __init__(self,
text: str=None,
as_user: bool=True,
username: str=None,
parse: str="full",
link_names: int=1,
unfurl_links: bool=True,
unfurl_media: bool=False,
icon_url: str=None,
icon_emoji: str=None,
attachments: Sequence[MessageAttachment]=None):
text: str = None,
as_user: bool = True,
username: str = None,
parse: str = "full",
link_names: int = 1,
unfurl_links: bool = True,
unfurl_media: bool = False,
icon_url: str = None,
icon_emoji: str = None,
attachments: Iterable[MessageAttachment] = None):
pass

def __str__(self) -> str:
Expand All @@ -135,7 +135,7 @@ def to_dict(self):

return params

def to_request_params(self):
def to_request_params(self) -> Dict:
params = self.to_dict()

if 'attachments' in params:
Expand All @@ -147,9 +147,9 @@ def to_request_params(self):

class Slack(Base):
def __init__(self,
token: str='',
plugins: Sequence[PluginConfig]=None,
max_workers: int=None) -> None:
token: str = '',
plugins: Iterable[PluginConfig] = None,
max_workers: int = None) -> None:

super().__init__(plugins=plugins, max_workers=max_workers)

Expand Down Expand Up @@ -181,7 +181,7 @@ def connect(self) -> None:

def generate_schedule_job(self,
command: ScheduledCommand) -> Optional[Callable]:
channels = command.schedule_config.pop('channels', None)
channels = command.schedule_config.pop('channels', [])
if not channels:
logging.warning(
'Missing channels configuration for schedule job. %s. '
Expand All @@ -193,7 +193,7 @@ def job_function() -> None:
if isinstance(ret, SlackMessage):
for channel in channels:
# TODO Error handling
data = dict({'channel': channel})
data = {'channel': channel}
data.update(ret.to_request_params())
self.client.post('chat.postMessage', data=data)
else:
Expand Down Expand Up @@ -280,7 +280,7 @@ def handle_message(self, content: Dict) -> Optional[Future]:
ret = self.respond(content['user'], content['text'])
if isinstance(ret, SlackMessage):
# TODO Error handling
data = dict({'channel': content["channel"]})
data = {'channel': content["channel"]}
data.update(ret.to_request_params())
self.client.post('chat.postMessage', data=data)
elif isinstance(ret, str):
Expand All @@ -300,7 +300,7 @@ def on_close(self, _: WebSocketApp) -> None:
def send_message(self,
channel: str,
text: str,
message_type: str='message') -> None:
message_type: str = 'message') -> None:
params = {'channel': channel,
'text': text,
'type': message_type,
Expand Down
Loading

0 comments on commit 11c7e38

Please sign in to comment.