The message your user in inputting is "somewhere" split into parameters that then call the async method you posted. The "splitting" of the user input is NOT done in the code you showed.
If you want to handle '1d 3hours 52sec Check StackOverflow for answers.'
as user input you need to change the way this message is split
before calling async def reminder(ctx, time, *, reminder)
with the split parameters.
You need to change it so that time
gets provided as '1d 3hours 52sec'
and reminder
is provided as 'Check StackOverflow for answers.'
:
# correctly proivided params
reminder(ctx, "1d 3hours 52sec", *, reminder="Check StackOverflow for answers")
If you are unable to change this splitting behaviour, forbid spaces inside the time-component of the message the user uses:
It seems that your users text is currently split at spaces and the first is provided for time
and the remainder as reminder
message.
If you forbid spaces inside time-components you can change your method to parse the time correctly for inputs like '1d3hours52sec Check StackOverflow for answers.'
.
This could be a -non async- implementation of a method that handles above messages:
Some helper methods and imports:
imort time
def format_seconds(secs):
# mildly adapted from source: https://stackoverflow.com/a/13756038/7505395
# by Adam Jacob Muller
"""Accepts an integer of seconds and returns a minimal string formatted into
'a years, b months, c days, d hours, e minutes, f seconds' as needed."""
periods = [
('year', 60*60*24*365),
('month', 60*60*24*30),
('day', 60*60*24),
('hour', 60*60),
('minute', 60),
('second', 1)
]
strings=[]
for period_name, period_seconds in periods:
if secs > period_seconds:
period_value , secs = divmod(secs, period_seconds)
has_s = 's' if period_value > 1 else ''
strings.append("%s %s%s" % (period_value, period_name, has_s))
return ", ".join(strings)
def convert_timestring_to_seconds(time):
"""Convert a math expression to integer,only allows [0..9+* ] as chars."""
if not all(c in "1234567890+* " for c in time):
raise Exception()
# this are seconds - using eval as we can be sure nothing harmful can be in it
# if you are paranoid, use https://stackoverflow.com/a/33030616/7505395 instead
count = eval(time)
if type(count) != int:
raise Exception()
return count
a mock for your methods context object:
class MockContext:
def __init__(self):
class User:
def __init__(self):
self.id = "mee-id"
def __str__(self):
return "mee"
class Message:
def __init__(self):
self.author = User()
self.message = Message()
self.send = print
and your changed-up method (non-async and mocked for minimal reproducible example purposes):
def reminder(ctx, time, *, reminder):
user = ctx.message.author
if not time:
ctx.send("Please, tell me WHEN you want me to remind you!")
return
elif not reminder:
ctx.send("Please, tell me WHAT you want me to remind you about!")
return
# order and 3.7+ is important - (else use the sorting one down below)
replacer = {"days":24*60*60, "hours":60*60, "minutes":60, "min":60,
"seconds":1, "sec":1, "d":24*60*60, "h":60, "m":60, "s":1}
safe_time = time # for error output we remember the original input for time
for unit in replacer: # or sorted(replacer, key=len, reverse=True) below 3.8
time = time.replace(unit, f"*{replacer[unit]}+")
time = time.rstrip("+")
try:
count = convert_timestring_to_seconds(time)
except Exception as ex:
ctx.send(f"Unable to understand the time of '{safe_time}'!", ex)
return
if count == 0:
ctx.send("You can't tell me that!")
else:
counter = format_seconds(count)
ctx.send(f"Alright, I will remind you about '{reminder}' in '{counter}'.")
import time
time.sleep(2)
ctx.send(f"Hi, <@{user.id}>, you asked me to remind you about '{reminder}' some '{counter}' ago.")
This is callable like so:
context_mock = MockContext()
reminder(context_mock, "1d5min270seconds", reminder = "abouth this")
reminder(context_mock, "1d5min270seconds", reminder = "")
reminder(context_mock, "", reminder = "")
reminder(context_mock, "buffalo", reminder = "abouth this")
and produces the following outputs:
# reminder(context_mock, "1d5min270seconds", reminder = "abouth this")
Alright, I will remind you about 'abouth this' in '1 day, 9 minutes, 30 seconds'.
<2s delay>
Hi, <@mee-id>, you asked me to remind you about 'abouth this' some '1 day, 9 minutes, 30 seconds' ago.
# reminder(context_mock, "1d5min270seconds", reminder = "")
Please, tell me WHAT you want me to remind you about!
# reminder(context_mock, "", reminder = "")
Please, tell me WHEN you want me to remind you!
# reminder(context_mock, "buffalo", reminder = "abouth this")
Unable to understand the time of 'buffalo'!