1
- '''
1
+ """
2
2
UserFriendlyTime by Rapptz
3
3
Source:
4
4
https://github.com/Rapptz/RoboDanny/blob/rewrite/cogs/utils/time.py
5
- '''
5
+ """
6
6
7
7
import datetime
8
8
import parsedatetime as pdt
9
9
from dateutil .relativedelta import relativedelta
10
10
from discord .ext import commands
11
11
import re
12
12
13
+
13
14
class ShortTime :
14
- compiled = re .compile ("""(?:(?P<years>[0-9])(?:years?|y))? # e.g. 2y
15
- (?:(?P<months>[0-9]{1,2})(?:months?|mo))? # e.g. 2months
16
- (?:(?P<weeks>[0-9]{1,4})(?:weeks?|w))? # e.g. 10w
17
- (?:(?P<days>[0-9]{1,5})(?:days?|d))? # e.g. 14d
18
- (?:(?P<hours>[0-9]{1,5})(?:hours?|h))? # e.g. 12h
19
- (?:(?P<minutes>[0-9]{1,5})(?:minutes?|m))? # e.g. 10m
20
- (?:(?P<seconds>[0-9]{1,5})(?:seconds?|s))? # e.g. 15s
15
+ compiled = re .compile ("""
16
+ (?:(?P<years>[0-9])(?:years?|y))? # e.g. 2y
17
+ (?:(?P<months>[0-9]{1,2})(?:months?|mo))? # e.g. 9mo
18
+ (?:(?P<weeks>[0-9]{1,4})(?:weeks?|w))? # e.g. 10w
19
+ (?:(?P<days>[0-9]{1,5})(?:days?|d))? # e.g. 14d
20
+ (?:(?P<hours>[0-9]{1,5})(?:hours?|h))? # e.g. 12h
21
+ (?:(?P<minutes>[0-9]{1,5})(?:minutes?|m))? # e.g. 10m
22
+ (?:(?P<seconds>[0-9]{1,5})(?:seconds?|s))? # e.g. 15s
21
23
""" , re .VERBOSE )
22
24
23
25
def __init__ (self , argument ):
24
26
match = self .compiled .fullmatch (argument )
25
27
if match is None or not match .group (0 ):
26
28
raise commands .BadArgument ('invalid time provided' )
27
29
28
- data = { k : int (v ) for k , v in match .groupdict (default = 0 ).items () }
30
+ data = {k : int (v ) for k , v in match .groupdict (default = '0' ).items ()}
29
31
now = datetime .datetime .utcnow ()
30
32
self .dt = now + relativedelta (** data )
31
33
34
+
32
35
class HumanTime :
33
36
calendar = pdt .Calendar (version = pdt .VERSION_CONTEXT_STYLE )
34
37
35
38
def __init__ (self , argument ):
36
39
now = datetime .datetime .utcnow ()
37
40
dt , status = self .calendar .parseDT (argument , sourceTime = now )
38
41
if not status .hasDateOrTime :
39
- raise commands .BadArgument ('invalid time provided, try e.g. "tomorrow" or "3 days"' )
42
+ raise commands .BadArgument (
43
+ 'invalid time provided, try e.g. "tomorrow" or "3 days"'
44
+ )
40
45
41
46
if not status .hasTime :
42
47
# replace it with the current time
43
- dt = dt .replace (hour = now .hour , minute = now .minute , second = now .second , microsecond = now .microsecond )
48
+ dt = dt .replace (hour = now .hour ,
49
+ minute = now .minute ,
50
+ second = now .second ,
51
+ microsecond = now .microsecond )
44
52
45
53
self .dt = dt
46
54
self ._past = dt < now
47
55
56
+
48
57
class Time (HumanTime ):
49
58
def __init__ (self , argument ):
50
59
try :
51
60
o = ShortTime (argument )
52
- except Exception as e :
61
+ except :
53
62
super ().__init__ (argument )
54
63
else :
55
64
self .dt = o .dt
56
65
self ._past = False
57
66
67
+
58
68
class FutureTime (Time ):
59
69
def __init__ (self , argument ):
60
70
super ().__init__ (argument )
61
71
62
72
if self ._past :
63
73
raise commands .BadArgument ('this time is in the past' )
64
74
75
+
65
76
class UserFriendlyTime (commands .Converter ):
66
77
"""That way quotes aren't absolutely necessary."""
67
78
def __init__ (self , converter = None ):
68
- if isinstance (converter , type ) and issubclass (converter , commands .Converter ):
79
+ if isinstance (converter , type ) and issubclass (converter ,
80
+ commands .Converter ):
69
81
converter = converter ()
70
82
71
- if converter is not None and not isinstance (converter , commands .Converter ):
83
+ if converter is not None and not isinstance (converter ,
84
+ commands .Converter ):
72
85
raise TypeError ('commands.Converter subclass necessary.' )
73
-
86
+ self . dt = self . arg = None
74
87
self .converter = converter
75
88
76
89
async def check_constraints (self , ctx , now , remaining ):
@@ -84,21 +97,23 @@ async def check_constraints(self, ctx, now, remaining):
84
97
return self
85
98
86
99
async def convert (self , ctx , argument ):
100
+ remaining = ''
87
101
try :
88
102
calendar = HumanTime .calendar
89
103
regex = ShortTime .compiled
90
104
self .dt = now = datetime .datetime .utcnow ()
91
105
92
106
match = regex .match (argument )
93
107
if match is not None and match .group (0 ):
94
- data = { k : int (v ) for k , v in match .groupdict (default = 0 ).items () }
108
+ data = {k : int (v ) for k , v in
109
+ match .groupdict (default = '0' ).items ()}
95
110
remaining = argument [match .end ():].strip ()
96
111
self .dt = now + relativedelta (** data )
97
112
return await self .check_constraints (ctx , now , remaining )
98
113
99
-
100
114
# apparently nlp does not like "from now"
101
- # it likes "from x" in other cases though so let me handle the 'now' case
115
+ # it likes "from x" in other cases though
116
+ # so let me handle the 'now' case
102
117
if argument .endswith ('from now' ):
103
118
argument = argument [:- 8 ].strip ()
104
119
@@ -123,28 +138,36 @@ async def convert(self, ctx, argument):
123
138
return await self .check_constraints (ctx , now , argument )
124
139
125
140
if begin not in (0 , 1 ) and end != len (argument ):
126
- raise commands .BadArgument ('Time is either in an inappropriate location, which ' \
127
- 'must be either at the end or beginning of your input, ' \
128
- 'or I just flat out did not understand what you meant. Sorry.' )
141
+ raise commands .BadArgument (
142
+ 'Time is either in an inappropriate location, which must '
143
+ 'be either at the end or beginning of your input, or I '
144
+ 'just flat out did not understand what you meant. Sorry.' )
129
145
130
146
if not status .hasTime :
131
147
# replace it with the current time
132
- dt = dt .replace (hour = now .hour , minute = now .minute , second = now .second , microsecond = now .microsecond )
148
+ dt = dt .replace (hour = now .hour ,
149
+ minute = now .minute ,
150
+ second = now .second ,
151
+ microsecond = now .microsecond )
133
152
134
153
# if midnight is provided, just default to next day
135
154
if status .accuracy == pdt .pdtContext .ACU_HALFDAY :
136
155
dt = dt .replace (day = now .day + 1 )
137
156
138
- self .dt = dt
157
+ self .dt = dt
139
158
140
159
if begin in (0 , 1 ):
141
160
if begin == 1 :
142
161
# check if it's quoted:
143
162
if argument [0 ] != '"' :
144
- raise commands .BadArgument ('Expected quote before time input...' )
163
+ raise commands .BadArgument (
164
+ 'Expected quote before time input...'
165
+ )
145
166
146
167
if not (end < len (argument ) and argument [end ] == '"' ):
147
- raise commands .BadArgument ('If the time is quoted, you must unquote it.' )
168
+ raise commands .BadArgument (
169
+ 'If the time is quoted, you must unquote it.'
170
+ )
148
171
149
172
remaining = argument [end + 1 :].lstrip (' ,.!' )
150
173
else :
@@ -158,6 +181,7 @@ async def convert(self, ctx, argument):
158
181
traceback .print_exc ()
159
182
raise
160
183
184
+
161
185
def human_timedelta (dt , * , source = None ):
162
186
now = source or datetime .datetime .utcnow ()
163
187
if dt > now :
@@ -190,4 +214,4 @@ def human_timedelta(dt, *, source=None):
190
214
elif len (output ) == 2 :
191
215
return f'{ output [0 ]} and { output [1 ]} { suffix } '
192
216
else :
193
- return f'{ output [0 ]} , { output [1 ]} and { output [2 ]} { suffix } '
217
+ return f'{ output [0 ]} , { output [1 ]} and { output [2 ]} { suffix } '
0 commit comments