Skip to content

Commit 6ba818d

Browse files
committed
Merge branch 'gonzobot' into gonzobot+outgoing-sieves
2 parents 8d0f0ee + 4ea66d8 commit 6ba818d

14 files changed

Lines changed: 249 additions & 119 deletions

File tree

cloudbot/__main__.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
import signal
77

88
# store the original working directory, for use when restarting
9+
from functools import partial
10+
11+
from cloudbot.util import async_util
12+
913
original_wd = os.path.realpath(".")
1014

1115
# set up environment - we need to make sure we are in the install directory
@@ -47,9 +51,10 @@ def exit_gracefully(signum, frame):
4751
stopped_while_restarting = True
4852
else:
4953
_bot.loop.call_soon_threadsafe(
50-
lambda: asyncio.async(_bot.stop("Killed (Received SIGINT {})".format(signum)), loop=_bot.loop))
54+
partial(async_util.wrap_future, _bot.stop("Killed (Received SIGINT {})".format(signum)), loop=_bot.loop)
55+
)
5156

52-
logger.warn("Bot received Signal Interrupt ({})".format(signum))
57+
logger.warning("Bot received Signal Interrupt ({})".format(signum))
5358

5459
# restore the original handler so if they do it again it triggers
5560
signal.signal(signal.SIGINT, original_sigint)

cloudbot/clients/irc.py

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from cloudbot.client import Client
99
from cloudbot.event import Event, EventType, IrcOutEvent
10-
from cloudbot.util.parsers.irc import Message
10+
from cloudbot.util import async_util
1111

1212
logger = logging.getLogger("cloudbot")
1313

@@ -19,8 +19,10 @@
1919
irc_bad_chars = ''.join([chr(x) for x in list(range(0, 1)) + list(range(4, 32)) + list(range(127, 160))])
2020
irc_clean_re = re.compile('[{}]'.format(re.escape(irc_bad_chars)))
2121

22+
2223
def irc_clean(dirty):
23-
return irc_clean_re.sub('',dirty)
24+
return irc_clean_re.sub('', dirty)
25+
2426

2527
irc_command_to_event_type = {
2628
"PRIVMSG": EventType.message,
@@ -219,8 +221,7 @@ def _send(self, line):
219221
:type line: str
220222
"""
221223
logger.info("[{}] >> {}".format(self.name, line))
222-
asyncio.async(self._protocol.send(line), loop=self.loop)
223-
224+
async_util.wrap_future(self._protocol.send(line), loop=self.loop)
224225

225226
@property
226227
def connected(self):
@@ -273,14 +274,14 @@ def connection_lost(self, exc):
273274
# we've been closed intentionally, so don't reconnect
274275
return
275276
logger.error("[{}] Connection lost: {}".format(self.conn.name, exc))
276-
asyncio.async(self.conn.connect(), loop=self.loop)
277+
async_util.wrap_future(self.conn.connect(), loop=self.loop)
277278

278279
def eof_received(self):
279280
self._connected = False
280281
# create a new connected_future for when we are connected.
281282
self._connected_future = asyncio.Future(loop=self.loop)
282283
logger.info("[{}] EOF received.".format(self.conn.name))
283-
asyncio.async(self.conn.connect(), loop=self.loop)
284+
async_util.wrap_future(self.conn.connect(), loop=self.loop)
284285
return True
285286

286287
@asyncio.coroutine
@@ -370,7 +371,7 @@ def data_received(self, data):
370371
# Reply to pings immediately
371372

372373
if command == "PING":
373-
asyncio.async(self.send("PONG " + command_params[-1]), loop=self.loop)
374+
async_util.wrap_future(self.send("PONG " + command_params[-1]), loop=self.loop)
374375

375376
# Parse the command and params
376377

@@ -437,13 +438,4 @@ def data_received(self, data):
437438
irc_prefix=prefix, irc_command=command, irc_paramlist=command_params, irc_ctcp_text=ctcp_text)
438439

439440
# handle the message, async
440-
asyncio.async(self.bot.process(event), loop=self.loop)
441-
442-
# Channel Commands
443-
# NOTICE #chan :Text
444-
# PRIVMSG #chan :Text
445-
# KICK #chan nick :reason
446-
# JOIN #chan
447-
# PART #chan :reason
448-
# MODE #chan +<modes>
449-
# INVITE nick :#chan
441+
async_util.wrap_future(self.bot.process(event), loop=self.loop)

cloudbot/event.py

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
import concurrent.futures
33
import enum
44
import logging
5+
import warnings
6+
from functools import partial
7+
8+
import sys
59

610
from cloudbot.util.parsers.irc import Message
711

@@ -155,7 +159,7 @@ def prepare(self):
155159
# we're running a coroutine hook with a db, so initialise an executor pool
156160
self.db_executor = concurrent.futures.ThreadPoolExecutor(1)
157161
# be sure to initialize the db in the database executor, so it will be accessible in that thread.
158-
self.db = yield from self.async(self.bot.db_session)
162+
self.db = yield from self.async_call(self.bot.db_session)
159163

160164
def prepare_threaded(self):
161165
"""
@@ -191,7 +195,7 @@ def close(self):
191195
if self.db is not None:
192196
#logger.debug("Closing database session for {}:threaded=False".format(self.hook.description))
193197
# be sure the close the database in the database executor, as it is only accessable in that one thread
194-
yield from self.async(self.db.close)
198+
yield from self.async_call(self.db.close)
195199
self.db = None
196200

197201
def close_threaded(self):
@@ -312,17 +316,34 @@ def has_permission(self, permission, notice=True):
312316
return self.conn.permissions.has_perm_mask(self.mask, permission, notice=notice)
313317

314318
@asyncio.coroutine
315-
def async(self, function, *args, **kwargs):
319+
def async_call(self, func, *args, **kwargs):
316320
if self.db_executor is not None:
317321
executor = self.db_executor
318322
else:
319323
executor = None
320-
if kwargs:
321-
result = yield from self.loop.run_in_executor(executor, function, *args)
322-
else:
323-
result = yield from self.loop.run_in_executor(executor, lambda: function(*args, **kwargs))
324+
325+
part = partial(func, *args, **kwargs)
326+
result = yield from self.loop.run_in_executor(executor, part)
324327
return result
325328

329+
if sys.version_info < (3, 7, 0):
330+
# noinspection PyCompatibility
331+
@asyncio.coroutine
332+
def async_(self, function, *args, **kwargs):
333+
warnings.warn(
334+
"event.async() is deprecated, use event.async_call() instead.",
335+
DeprecationWarning, stacklevel=2
336+
)
337+
result = yield from self.async_call(function, *args, **kwargs)
338+
return result
339+
340+
341+
# Silence deprecation warnings about use of the 'async' name as a function
342+
try:
343+
setattr(Event, 'async', getattr(Event, 'async_'))
344+
except AttributeError:
345+
pass
346+
326347

327348
class CommandEvent(Event):
328349
"""

cloudbot/hook.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ def sieve(param=None, **kwargs):
309309
"""
310310

311311
def _sieve_hook(func):
312-
assert len(inspect.getargspec(func).args) == 3, \
312+
assert len(inspect.getfullargspec(func).args) == 3, \
313313
"Sieve plugin has incorrect argument count. Needs params: bot, input, plugin"
314314

315315
hook = _get_hook(func, "sieve")

cloudbot/plugin.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,19 @@
55
import logging
66
import os
77
import re
8+
import warnings
89
from collections import defaultdict
910
from itertools import chain
1011
from operator import attrgetter
1112

1213
import sqlalchemy
14+
import sys
15+
16+
import time
1317

1418
from cloudbot.event import Event
1519
from cloudbot.hook import Priority, Action
16-
from cloudbot.util import database
20+
from cloudbot.util import database, async_util
1721

1822
logger = logging.getLogger("cloudbot")
1923

@@ -202,7 +206,7 @@ def load_plugin(self, path):
202206
self._log_hook(on_cap_ack_hook)
203207

204208
for periodic_hook in plugin.periodic:
205-
task = asyncio.async(self._start_periodic(periodic_hook))
209+
task = async_util.wrap_future(self._start_periodic(periodic_hook))
206210
plugin.tasks.append(task)
207211
self._log_hook(periodic_hook)
208212

@@ -654,12 +658,18 @@ def __init__(self, _type, plugin, func_hook):
654658
self.function = func_hook.function
655659
self.function_name = self.function.__name__
656660

657-
self.required_args = inspect.getargspec(self.function)[0]
658-
if self.required_args is None:
659-
self.required_args = []
661+
sig = inspect.signature(self.function)
660662

661663
# don't process args starting with "_"
662-
self.required_args = [arg for arg in self.required_args if not arg.startswith("_")]
664+
self.required_args = [arg for arg in sig.parameters.keys() if not arg.startswith('_')]
665+
if sys.version_info < (3, 7, 0):
666+
if "async" in self.required_args:
667+
logger.warning("Use of deprecated function 'async' in %s", self.description)
668+
time.sleep(1)
669+
warnings.warn(
670+
"event.async() is deprecated, use event.async_call() instead.",
671+
DeprecationWarning, stacklevel=2
672+
)
663673

664674
if asyncio.iscoroutine(self.function) or asyncio.iscoroutinefunction(self.function):
665675
self.threaded = False

cloudbot/reloader.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import asyncio
22
import os.path
3+
from functools import partial
34

45
from watchdog.observers import Observer
56
from watchdog.events import PatternMatchingEventHandler
67

8+
from cloudbot.util import async_util
9+
710

811
class PluginReloader(object):
912
def __init__(self, bot):
@@ -38,7 +41,8 @@ def reload(self, path):
3841

3942
if isinstance(path, bytes):
4043
path = path.decode()
41-
self.bot.loop.call_soon_threadsafe(lambda: asyncio.async(self._reload(path), loop=self.bot.loop))
44+
45+
self.bot.loop.call_soon_threadsafe(partial(async_util.wrap_future, self._reload(path), loop=self.bot.loop))
4246

4347
def unload(self, path):
4448
"""
@@ -48,7 +52,8 @@ def unload(self, path):
4852
"""
4953
if isinstance(path, bytes):
5054
path = path.decode()
51-
self.bot.loop.call_soon_threadsafe(lambda: asyncio.async(self._unload(path), loop=self.bot.loop))
55+
56+
self.bot.loop.call_soon_threadsafe(partial(async_util.wrap_future, self._unload(path), loop=self.bot.loop))
5257

5358
@asyncio.coroutine
5459
def _reload(self, path):

cloudbot/util/async_util.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"""
2+
Wraps various asyncio functions
3+
"""
4+
5+
import asyncio
6+
7+
import sys
8+
9+
10+
def wrap_future(fut, *, loop=None):
11+
"""
12+
Wraps asyncio.async()/asyncio.ensure_future() depending on the python version
13+
:param fut: The awaitable, future, or coroutine to wrap
14+
:param loop: The loop to run in
15+
:return: The wrapped future
16+
"""
17+
if sys.version_info < (3, 4, 4):
18+
return asyncio.async(fut, loop=loop)
19+
20+
return asyncio.ensure_future(fut, loop=loop)

data/kero.txt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
PRIUS JIMMY BUFFET!!!
2+
DISNEY APPLE BEARDS, FUCK COFFEE!
3+
FUCK THINGS THAT ARE GOOD AND NICE!
4+
RED ZONE SCHMED ZONE!
5+
i DONT USE APPLE CPMPUTERS!!!!
6+
???!??!? YOU CLEARLY DONT LISTEN!
7+
WHY ARE PEOPLE CALLING ME A NERD I WAS ON THE iPHONE AND DONT GET IT!!!!
8+
OH MAN FUCK BEARDS!
9+
I AM GOING DOWN THE HALL TO A MEETING UNDER MY OWN POWER RIGHT NOW!!!
10+
NOT A VEGETABLE!!!!!!!
11+
i think thats a vulva euphemism, PW.
12+
THEY START SHOVING CAKES IN EACH OTHERS FACES LIKE ITS A MANATEE WEDDING HOLY SHIT!
13+
I DONT MAKE THE NEWS I JUST REPORT IT!
14+
HURR DURR YOU ARE OLD WITH PRINTED PAGES
15+
pants on head mouthbreather.
16+
HELLO I AM BACK WHAT IS NEW?
17+
YOU ARE A HORRIBLE DEAD FAN!
18+
i try not to be racist, but seriously. there's a mexican guy in our neighborhood. on the 4th like 40 people in his family came over and shot off fireworks and they sat in lawn chairs in the front yard.
19+
there's an old asian woman in our neighborhood who hides in her house and walks 10 feet behind her husband and is a bad driver.
20+
HOW AM I NOT SUPPOSED TO BE RACIST WITH THAT OVERWHELMING EVIDENCE EXACTLY!?!?
21+
???? WTF IS
22+
NO I NEVER THINK THAT I AM VERY HAPPY
23+
HORSES CANT TALK IDIOTS
24+
I WENT TO ZERO STRIP CLUBS AND HAD ZERO STREET BEER
25+
I FUCKING WRITE CURRICULUM ON HOW TO SELL AND NETWORK AND RUN A BUSINESS ALL FUCKING DAY LONG
26+
you gentlemen are hilarious. theres certainly nothing in what you're doing that could be considered "ball busting" or "trolling."
27+
YOU CAN EMAIL FROM YOUR PHONE? MAGIC MAN FROM THE FUTURE, DO THEY HAVE RUBBER VAGINAS MEN CAN PUT THEIR DICKS INTO AS WELL?
28+
really who the fuck cares who the third president was?
29+
why dont you just bore your candidat to tears with talk about subarus and guns and talk about the recruiters that have been calling *you*? Itll be just like irc.
30+
DONT TAKE AWAY MY FUN.
31+
I may beat off on the notes afterward because that turns me on, DONT JUDGE ME ITS NORMAL.
32+
wtf is a homeless guyy gonna do with a speaker SURE WOULD LIKE TO EAT BUT AT LEAST I HAVE MY KOOL JAMZ
33+
thanks for overexplaining that one
34+
Really. I say ejaculating on pictures is weird and somehow that translates to OMG WAT A PRUDE
35+
Had someone ejaculate on a picture of me. Gotta try it once.
36+
apparently theres a thing where people ejaculate on pictures i bet you could monetize that.
37+
'Hey you can talk to this chick and maybe get laid or cum on a picture,' only complete social retards pick the latter.
38+
Hahaha those weirdos with tentacle porn excuse me I need to whack it on a picture and put it on the Internet.
39+
enjoy your penis salad sandwich
40+
im pretty sure ive never said 'OH MY GOODNESS LOOK AT HIS PENIS I WISH I HAD THAT PENIS' then went searching for it to show someone else 24 hours later because i couldn't stop thinking about teddy bridgewater's beautiful penis <3
41+
i don't think "we" have ever "talked a lot of dick."
42+
OMG DID YOU SEE THE BALLS TOO?
43+
be as weird as you want. i dont understand why its so cool now to go "OOOO THATS JUST WHO HE IS DONT JUDGE." if you like to have your balls hit with a hammer while you ejaculate onto pictures of horses i think you should be called fucking weird.

plugins/autojoin.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ def get_channels(db, conn):
2121

2222
@asyncio.coroutine
2323
@hook.irc_raw('004')
24-
def do_joins(db, conn, async):
25-
chans = yield from async(get_channels, db, conn)
24+
def do_joins(db, conn, async_call):
25+
chans = yield from async_call(get_channels, db, conn)
2626
join_throttle = conn.config.get("join_throttle", 0.4)
2727
for chan in chans:
2828
conn.join(chan[1])

plugins/geoip.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import geoip2.errors
1111

1212
from cloudbot import hook
13+
from cloudbot.util import async_util
1314

1415
logger = logging.getLogger("cloudbot")
1516

@@ -52,6 +53,7 @@ def update_db():
5253
return geoip2.database.Reader(PATH)
5354

5455

56+
@asyncio.coroutine
5557
def check_db(loop):
5658
"""
5759
runs update_db in an executor thread and sets geoip_reader to the result
@@ -68,7 +70,7 @@ def check_db(loop):
6870
@asyncio.coroutine
6971
@hook.on_start
7072
def load_geoip(loop):
71-
asyncio.async(check_db(loop), loop=loop)
73+
async_util.wrap_future(check_db(loop), loop=loop)
7274

7375

7476
@asyncio.coroutine

0 commit comments

Comments
 (0)