redditadmin 0.0.5__py3-none-any.whl → 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- redditadmin/core.py +27 -67
- redditadmin/plugin/__init__.py +5 -3
- redditadmin/plugin/asynchronouspluginsexecutor.py +3 -8
- redditadmin/plugin/plugin.py +29 -17
- redditadmin/plugin/pluginsexecutor.py +37 -17
- redditadmin/plugin/redditinterfacefactory.py +26 -28
- redditadmin/program/__init__.py +5 -3
- redditadmin/program/program.py +30 -17
- redditadmin/program/streamprocessingprogram.py +22 -21
- redditadmin/utility/__init__.py +8 -4
- redditadmin/utility/botcredentials.py +49 -29
- redditadmin/utility/{contributionsutility.py → contributions.py} +1 -1
- redditadmin/utility/decorators.py +3 -4
- redditadmin/utility/miscellaneous.py +28 -0
- redditadmin/utility/redditinterface.py +13 -5
- redditadmin/utility/redditsubmission.py +17 -9
- {redditadmin-0.0.5.dist-info → redditadmin-0.1.0.dist-info}/METADATA +21 -9
- redditadmin-0.1.0.dist-info/RECORD +21 -0
- redditadmin/plugin/exceptions.py +0 -11
- redditadmin/utility/exceptions.py +0 -28
- redditadmin-0.0.5.dist-info/RECORD +0 -22
- {redditadmin-0.0.5.dist-info → redditadmin-0.1.0.dist-info}/WHEEL +0 -0
- {redditadmin-0.0.5.dist-info → redditadmin-0.1.0.dist-info}/licenses/LICENSE +0 -0
redditadmin/core.py
CHANGED
@@ -1,43 +1,36 @@
|
|
1
1
|
import logging
|
2
2
|
import os
|
3
3
|
import signal
|
4
|
-
import sys
|
5
4
|
import time
|
6
|
-
from abc import
|
5
|
+
from abc import ABCMeta, abstractmethod
|
7
6
|
from logging.handlers import TimedRotatingFileHandler
|
8
7
|
from pathlib import Path
|
9
8
|
from typing import List
|
10
9
|
|
11
|
-
from .utility.botcredentials import BotCredentials
|
12
|
-
|
10
|
+
from .utility.botcredentials import InvalidBotCredentialsError, BotCredentials,\
|
11
|
+
BotCredentialsImplementation
|
12
|
+
from .utility.miscellaneous import BotInitializationError
|
13
13
|
from .plugin.asynchronouspluginsexecutor import AsynchronousPluginsExecutor
|
14
|
-
from .plugin.exceptions import PluginsExecutorInitializationError
|
15
14
|
from .plugin.plugin import Plugin
|
16
|
-
from .plugin.pluginsexecutor import PluginsExecutor
|
17
|
-
from .plugin.redditinterfacefactory import RedditInterfaceFactory
|
15
|
+
from .plugin.pluginsexecutor import PluginsExecutor, PluginsExecutorInitializationError
|
16
|
+
from .plugin.redditinterfacefactory import RedditInterfaceFactory, DefaultRedditInterfaceFactory
|
18
17
|
|
19
18
|
|
20
|
-
class RedditAdmin(
|
21
|
-
"""
|
22
|
-
|
23
|
-
def __init__(self, *args):
|
24
|
-
pass
|
19
|
+
class RedditAdmin(metaclass=ABCMeta):
|
20
|
+
"""Encapsulates RedditAdmin bot"""
|
25
21
|
|
26
22
|
@abstractmethod
|
27
23
|
def run(self, bot_credentials: BotCredentials, listen: bool = False):
|
28
24
|
"""Run the bot"""
|
29
|
-
|
30
|
-
raise NotImplementedError
|
25
|
+
...
|
31
26
|
|
32
27
|
@abstractmethod
|
33
|
-
def stop(self):
|
28
|
+
def stop(self, wait: bool):
|
34
29
|
"""Shutdown the bot"""
|
30
|
+
...
|
35
31
|
|
36
|
-
raise NotImplementedError
|
37
32
|
|
38
|
-
|
39
|
-
class RedditAdminImplementation(RedditAdmin):
|
40
|
-
"""Reddit Admin Bot"""
|
33
|
+
class _RedditAdminImplementation(RedditAdmin):
|
41
34
|
|
42
35
|
__plugins: List[Plugin]
|
43
36
|
__pluginsExecutor: PluginsExecutor
|
@@ -106,7 +99,7 @@ class RedditAdminImplementation(RedditAdmin):
|
|
106
99
|
# Setting the default console logging level global variable
|
107
100
|
self.__defaultConsoleLoggingLevel = console_handler.level
|
108
101
|
|
109
|
-
def
|
102
|
+
def __get_new_bot_credentials(self) -> BotCredentials:
|
110
103
|
"""Convenience method to retrieve bot credentials from user input"""
|
111
104
|
|
112
105
|
try:
|
@@ -125,7 +118,7 @@ class RedditAdminImplementation(RedditAdmin):
|
|
125
118
|
# Resume console logging
|
126
119
|
self.__resume_console_logging()
|
127
120
|
|
128
|
-
return
|
121
|
+
return BotCredentialsImplementation(
|
129
122
|
user_agent, client_id,
|
130
123
|
client_secret, username,
|
131
124
|
password
|
@@ -144,7 +137,7 @@ class RedditAdminImplementation(RedditAdmin):
|
|
144
137
|
# instance from provided credentials
|
145
138
|
|
146
139
|
try:
|
147
|
-
reddit_interface_factory =
|
140
|
+
reddit_interface_factory = DefaultRedditInterfaceFactory(
|
148
141
|
bot_credentials
|
149
142
|
)
|
150
143
|
# Handle if credential authentication fails
|
@@ -154,7 +147,7 @@ class RedditAdminImplementation(RedditAdmin):
|
|
154
147
|
"Please enter new valid credentials"
|
155
148
|
)
|
156
149
|
try:
|
157
|
-
new_bot_credentials = self.
|
150
|
+
new_bot_credentials = self.__get_new_bot_credentials()
|
158
151
|
reddit_interface_factory = self.__get_reddit_interface_factory(new_bot_credentials)
|
159
152
|
except (KeyboardInterrupt, EOFError):
|
160
153
|
raise BotInitializationError(
|
@@ -206,6 +199,7 @@ class RedditAdminImplementation(RedditAdmin):
|
|
206
199
|
self.__pluginsExecutor = self.__initialize_plugins_executor(
|
207
200
|
bot_credentials
|
208
201
|
)
|
202
|
+
self.__mainLogger.info("Bot successfully initialized")
|
209
203
|
|
210
204
|
# -------------------------------------------------------------------------------
|
211
205
|
|
@@ -213,13 +207,10 @@ class RedditAdminImplementation(RedditAdmin):
|
|
213
207
|
except BotInitializationError as er:
|
214
208
|
self.__mainLogger.critical(
|
215
209
|
"A fatal error occurred during the "
|
216
|
-
"bot's initialization.
|
217
|
-
"will now exit. Error(s): " + str(er),
|
210
|
+
"bot's initialization. Error(s): " + str(er),
|
218
211
|
exc_info=True
|
219
212
|
)
|
220
|
-
|
221
|
-
|
222
|
-
self.__mainLogger.info("Bot successfully initialized")
|
213
|
+
raise er
|
223
214
|
|
224
215
|
# -------------------------------------------------------------------------------
|
225
216
|
|
@@ -310,21 +301,7 @@ class RedditAdminImplementation(RedditAdmin):
|
|
310
301
|
"'{}' is not a valid bot command".format(command)
|
311
302
|
)
|
312
303
|
|
313
|
-
|
314
|
-
def __kill_bot():
|
315
|
-
"""Forcefully shut down the bot"""
|
316
|
-
|
317
|
-
# Windows kill command
|
318
|
-
if (
|
319
|
-
sys.platform.startswith('win32') or
|
320
|
-
sys.platform.startswith('cygwin')
|
321
|
-
):
|
322
|
-
os.kill(os.getpid(), signal.CTRL_BREAK_EVENT)
|
323
|
-
|
324
|
-
# Linux kill command
|
325
|
-
os.kill(os.getpid(), signal.SIGKILL)
|
326
|
-
|
327
|
-
def __shut_down_bot(self, wait=True, shutdown_exit_code=0):
|
304
|
+
def __shut_down_bot(self, wait=True):
|
328
305
|
"""Shut down the bot"""
|
329
306
|
|
330
307
|
if wait:
|
@@ -342,30 +319,13 @@ class RedditAdminImplementation(RedditAdmin):
|
|
342
319
|
)
|
343
320
|
)
|
344
321
|
)
|
345
|
-
|
346
|
-
|
347
|
-
self.__mainLogger.info('Bot successfully shut down')
|
348
|
-
if shutdown_exit_code != 0:
|
349
|
-
sys.exit(shutdown_exit_code)
|
350
|
-
|
351
|
-
# Handle keyboard interrupt midway through graceful shutdown
|
352
|
-
except KeyboardInterrupt:
|
353
|
-
|
354
|
-
self.__mainLogger.warning(
|
355
|
-
'Graceful shutdown aborted.'
|
356
|
-
)
|
357
|
-
self.__pluginsExecutor.shut_down(False)
|
358
|
-
self.__mainLogger.info('Bot shut down')
|
359
|
-
|
360
|
-
# Killing the process (only way to essentially stop all threads)
|
361
|
-
self.__kill_bot()
|
322
|
+
self.__pluginsExecutor.shut_down(True)
|
323
|
+
self.__mainLogger.info('Bot successfully shut down')
|
362
324
|
|
363
325
|
else:
|
364
326
|
self.__pluginsExecutor.shut_down(False)
|
365
327
|
self.__mainLogger.info('Bot shut down')
|
366
328
|
|
367
|
-
self.__kill_bot()
|
368
|
-
|
369
329
|
def __is_bot_shut_down(self):
|
370
330
|
"""Check if bot is shutdown"""
|
371
331
|
|
@@ -389,7 +349,7 @@ class RedditAdminImplementation(RedditAdmin):
|
|
389
349
|
'a graceful shutdown is attempted or press '
|
390
350
|
'Ctrl+C to exit immediately'
|
391
351
|
)
|
392
|
-
self.__shut_down_bot(True
|
352
|
+
self.__shut_down_bot(True)
|
393
353
|
|
394
354
|
# Handle unknown exception while bot is running
|
395
355
|
except BaseException as ex:
|
@@ -399,7 +359,7 @@ class RedditAdminImplementation(RedditAdmin):
|
|
399
359
|
"a graceful shutdown is attempted or press "
|
400
360
|
"Ctrl+C to exit immediately: " + str(ex.args), exc_info=True
|
401
361
|
)
|
402
|
-
self.__shut_down_bot(True
|
362
|
+
self.__shut_down_bot(True)
|
403
363
|
|
404
364
|
def run(self, bot_credentials: BotCredentials, listen: bool = False):
|
405
365
|
|
@@ -427,9 +387,9 @@ class RedditAdminImplementation(RedditAdmin):
|
|
427
387
|
if not self.__is_bot_shut_down():
|
428
388
|
self.__shut_down_bot()
|
429
389
|
|
430
|
-
def stop(self):
|
390
|
+
def stop(self, wait: bool):
|
431
391
|
|
432
|
-
self.__shut_down_bot()
|
392
|
+
self.__shut_down_bot(wait=wait)
|
433
393
|
|
434
394
|
# -------------------------------------------------------------------------------
|
435
395
|
|
@@ -437,4 +397,4 @@ class RedditAdminImplementation(RedditAdmin):
|
|
437
397
|
def get_reddit_admin(plugins: List[Plugin]) -> RedditAdmin:
|
438
398
|
"""Get a Reddit Admin instance"""
|
439
399
|
|
440
|
-
return
|
400
|
+
return _RedditAdminImplementation(plugins=plugins)
|
redditadmin/plugin/__init__.py
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
-
from .plugin import Plugin
|
2
|
-
from .pluginsexecutor import PluginsExecutor
|
3
|
-
|
1
|
+
from .plugin import Plugin as IPlugin, AbstractPlugin as Plugin, PluginInitializationError
|
2
|
+
from .pluginsexecutor import PluginsExecutor as IPluginsExecutor, \
|
3
|
+
AbstractPluginsExecutor as PluginsExecutor, PluginsExecutorInitializationError
|
4
|
+
from .redditinterfacefactory import RedditInterfaceFactory as IRedditInterfaceFactory,\
|
5
|
+
DefaultRedditInterfaceFactory as RedditInterfaceFactory
|
@@ -3,22 +3,19 @@
|
|
3
3
|
import concurrent.futures
|
4
4
|
from concurrent.futures import ThreadPoolExecutor, Future
|
5
5
|
from typing import Dict, List
|
6
|
-
from .pluginsexecutor import
|
6
|
+
from .pluginsexecutor import AbstractPluginsExecutor, PluginsExecutorInitializationError
|
7
7
|
from .redditinterfacefactory import RedditInterfaceFactory
|
8
8
|
from .plugin import Plugin
|
9
|
-
from .exceptions import PluginsExecutorInitializationError
|
10
9
|
|
11
10
|
|
12
|
-
class AsynchronousPluginsExecutor(
|
11
|
+
class AsynchronousPluginsExecutor(AbstractPluginsExecutor):
|
13
12
|
"""
|
14
|
-
|
15
|
-
multiple plugins in different threads
|
13
|
+
Executes multiple plugins in different threads
|
16
14
|
"""
|
17
15
|
|
18
16
|
__executor: ThreadPoolExecutor
|
19
17
|
__plugins: Dict[str, Plugin]
|
20
18
|
__executedPrograms: Dict[str, Future]
|
21
|
-
__redditInterfaceFactory: RedditInterfaceFactory
|
22
19
|
|
23
20
|
def __init__(
|
24
21
|
self,
|
@@ -182,7 +179,6 @@ class AsynchronousPluginsExecutor(PluginsExecutor):
|
|
182
179
|
)
|
183
180
|
|
184
181
|
def get_program_statuses(self):
|
185
|
-
"""Get the executed program statuses"""
|
186
182
|
|
187
183
|
program_statuses = \
|
188
184
|
{
|
@@ -192,7 +188,6 @@ class AsynchronousPluginsExecutor(PluginsExecutor):
|
|
192
188
|
return program_statuses
|
193
189
|
|
194
190
|
def shut_down(self, wait):
|
195
|
-
"""Shut down the plugin executor"""
|
196
191
|
|
197
192
|
super().shut_down()
|
198
193
|
for plugin in self.__plugins.values():
|
redditadmin/plugin/plugin.py
CHANGED
@@ -1,20 +1,42 @@
|
|
1
1
|
import logging
|
2
|
-
from abc import
|
2
|
+
from abc import ABCMeta, abstractmethod
|
3
3
|
from typing import TypeVar, Generic
|
4
4
|
|
5
5
|
from ..program.program import Program
|
6
6
|
from ..utility.redditinterface import RedditInterface
|
7
|
-
from ..utility.
|
7
|
+
from ..utility.miscellaneous import InitializationError
|
8
8
|
|
9
9
|
T = TypeVar("T", bound=Program)
|
10
10
|
|
11
11
|
|
12
|
-
class Plugin(Generic[T],
|
12
|
+
class Plugin(Generic[T], metaclass=ABCMeta):
|
13
13
|
"""
|
14
|
-
|
15
|
-
instances of a specific program
|
14
|
+
Generates multiple instances of a specific program
|
16
15
|
"""
|
17
16
|
|
17
|
+
@abstractmethod
|
18
|
+
def get_program(self, reddit_interface: RedditInterface) -> T:
|
19
|
+
"""Get new program instance"""
|
20
|
+
...
|
21
|
+
|
22
|
+
@abstractmethod
|
23
|
+
def get_program_command(self) -> str:
|
24
|
+
"""Get the program command string"""
|
25
|
+
...
|
26
|
+
|
27
|
+
@abstractmethod
|
28
|
+
def is_shut_down(self) -> bool:
|
29
|
+
"""Check if plugin is shut down"""
|
30
|
+
...
|
31
|
+
|
32
|
+
@abstractmethod
|
33
|
+
def shut_down(self):
|
34
|
+
"""Shut down the plugin"""
|
35
|
+
...
|
36
|
+
|
37
|
+
|
38
|
+
class AbstractPlugin(Generic[T], Plugin, metaclass=ABCMeta):
|
39
|
+
|
18
40
|
_programCommand: str
|
19
41
|
_pluginLogger: logging.Logger
|
20
42
|
_isPluginShutDown: bool
|
@@ -29,33 +51,23 @@ class Plugin(Generic[T], ABC):
|
|
29
51
|
)
|
30
52
|
self._isPluginShutDown = False
|
31
53
|
|
32
|
-
@abstractmethod
|
33
|
-
def get_program(self, reddit_interface: RedditInterface) -> T:
|
34
|
-
"""Get new program instance"""
|
35
|
-
|
36
|
-
raise NotImplementedError
|
37
|
-
|
38
54
|
def get_program_command(self) -> str:
|
39
|
-
"""Get the program command string"""
|
40
55
|
return self._programCommand
|
41
56
|
|
42
57
|
def is_shut_down(self) -> bool:
|
43
|
-
"""Check if plugin is shut down"""
|
44
58
|
return self._isPluginShutDown
|
45
59
|
|
46
60
|
def shut_down(self):
|
47
|
-
"""Shut down the plugin"""
|
48
61
|
self._isPluginShutDown = True
|
49
62
|
|
50
63
|
def __eq__(self, value) -> bool:
|
51
|
-
return isinstance(value,
|
64
|
+
return isinstance(value, AbstractPlugin) and \
|
52
65
|
self.get_program_command() == value.get_program_command()
|
53
66
|
|
54
67
|
|
55
68
|
class PluginInitializationError(InitializationError):
|
56
69
|
"""
|
57
|
-
|
58
|
-
of a plugin module
|
70
|
+
Raised when initialization of a plugin module fails
|
59
71
|
"""
|
60
72
|
|
61
73
|
def __init__(self, *args):
|
@@ -1,43 +1,54 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
|
3
3
|
import logging
|
4
|
-
from abc import
|
4
|
+
from abc import ABCMeta, abstractmethod
|
5
5
|
from typing import Dict
|
6
6
|
|
7
|
+
from src.redditadmin.utility.miscellaneous import InitializationError
|
7
8
|
|
8
|
-
|
9
|
+
|
10
|
+
class PluginsExecutor(metaclass=ABCMeta):
|
9
11
|
"""
|
10
|
-
|
12
|
+
Executes plugins
|
11
13
|
"""
|
12
14
|
|
13
|
-
_isPluginsExecutorShutDown: bool
|
14
|
-
_pluginsExecutorLogger: logging.Logger
|
15
|
-
|
16
|
-
def __init__(self, plugins_executor_name: str):
|
17
|
-
self._pluginsExecutorLogger = logging.getLogger(
|
18
|
-
plugins_executor_name
|
19
|
-
)
|
20
|
-
self._isPluginsExecutorShutDown = False
|
21
|
-
|
22
15
|
@abstractmethod
|
23
16
|
def execute_program(self, program_command):
|
24
17
|
"""Execute the provided program command"""
|
25
|
-
|
26
|
-
raise NotImplementedError
|
18
|
+
...
|
27
19
|
|
28
20
|
@abstractmethod
|
29
21
|
def get_program_statuses(self) -> Dict[str, str]:
|
30
22
|
"""Get the executed program statuses"""
|
23
|
+
...
|
31
24
|
|
32
|
-
|
33
|
-
|
25
|
+
@abstractmethod
|
34
26
|
def shut_down(self, *args):
|
35
27
|
"""Shut down the plugins executor"""
|
28
|
+
...
|
29
|
+
|
30
|
+
@abstractmethod
|
31
|
+
def is_shut_down(self) -> bool:
|
32
|
+
"""Check if the Plugins Executor is shut down"""
|
33
|
+
...
|
34
|
+
|
35
|
+
|
36
|
+
class AbstractPluginsExecutor(PluginsExecutor, metaclass=ABCMeta):
|
37
|
+
|
38
|
+
_isPluginsExecutorShutDown: bool
|
39
|
+
_pluginsExecutorLogger: logging.Logger
|
40
|
+
|
41
|
+
def __init__(self, plugins_executor_name: str):
|
42
|
+
self._pluginsExecutorLogger = logging.getLogger(
|
43
|
+
plugins_executor_name
|
44
|
+
)
|
45
|
+
self._isPluginsExecutorShutDown = False
|
46
|
+
|
47
|
+
def shut_down(self, *args):
|
36
48
|
|
37
49
|
self._isPluginsExecutorShutDown = True
|
38
50
|
|
39
51
|
def is_shut_down(self) -> bool:
|
40
|
-
"""Check if the Plugins Executor is shut down"""
|
41
52
|
|
42
53
|
return self._isPluginsExecutorShutDown
|
43
54
|
|
@@ -52,3 +63,12 @@ class PluginsExecutor(ABC):
|
|
52
63
|
"The plugins executor cannot execute any more program "
|
53
64
|
"after it has been shut down"
|
54
65
|
)
|
66
|
+
|
67
|
+
|
68
|
+
class PluginsExecutorInitializationError(InitializationError):
|
69
|
+
"""
|
70
|
+
Raised when initialization of a Plugins Executor module fails
|
71
|
+
"""
|
72
|
+
|
73
|
+
def __init__(self, *args):
|
74
|
+
super().__init__(*args)
|
@@ -1,49 +1,47 @@
|
|
1
|
+
from abc import ABCMeta, abstractmethod
|
2
|
+
|
1
3
|
import praw
|
2
4
|
|
3
|
-
from ..utility.botcredentials import BotCredentials
|
4
|
-
from ..utility.
|
5
|
-
from ..utility.redditinterface import RedditInterface
|
5
|
+
from ..utility.botcredentials import BotCredentials, InvalidBotCredentialsError
|
6
|
+
from ..utility.miscellaneous import is_reddit_authenticated
|
7
|
+
from ..utility.redditinterface import RedditInterface, RedditInterfaceImplementation
|
6
8
|
|
7
9
|
|
8
|
-
class RedditInterfaceFactory:
|
10
|
+
class RedditInterfaceFactory(metaclass=ABCMeta):
|
9
11
|
"""Factory for RedditInterface objects"""
|
10
12
|
|
11
|
-
|
13
|
+
@abstractmethod
|
14
|
+
def get_reddit_interface(self) -> RedditInterface:
|
15
|
+
"""Retrieve new Reddit Interface"""
|
16
|
+
...
|
17
|
+
|
18
|
+
|
19
|
+
class DefaultRedditInterfaceFactory(RedditInterfaceFactory):
|
12
20
|
|
13
21
|
def __init__(
|
14
22
|
self,
|
15
23
|
bot_credentials: BotCredentials
|
16
24
|
):
|
17
25
|
praw_reddit = praw.Reddit(
|
18
|
-
user_agent=bot_credentials.
|
19
|
-
client_id=bot_credentials.
|
20
|
-
client_secret=bot_credentials.
|
21
|
-
username=bot_credentials.
|
22
|
-
password=bot_credentials.
|
26
|
+
user_agent=bot_credentials.user_agent,
|
27
|
+
client_id=bot_credentials.client_id,
|
28
|
+
client_secret=bot_credentials.client_secret,
|
29
|
+
username=bot_credentials.username,
|
30
|
+
password=bot_credentials.password
|
23
31
|
)
|
24
|
-
if not
|
32
|
+
if not is_reddit_authenticated(praw_reddit):
|
25
33
|
raise InvalidBotCredentialsError
|
26
34
|
|
27
35
|
self.__botCredentials = bot_credentials
|
28
36
|
|
29
|
-
|
30
|
-
def __authenticated(praw_reddit_instance: praw.Reddit) -> bool:
|
31
|
-
"""
|
32
|
-
Convenience method to authenticate bot credentials
|
33
|
-
provided to Reddit instance
|
34
|
-
"""
|
35
|
-
|
36
|
-
return not praw_reddit_instance.read_only
|
37
|
-
|
38
|
-
def get_reddit_interface(self) -> RedditInterface:
|
39
|
-
"""Retrieve new Reddit Interface"""
|
37
|
+
def get_reddit_interface(self):
|
40
38
|
|
41
39
|
bot_credentials = self.__botCredentials
|
42
40
|
praw_reddit = praw.Reddit(
|
43
|
-
user_agent=bot_credentials.
|
44
|
-
client_id=bot_credentials.
|
45
|
-
client_secret=bot_credentials.
|
46
|
-
username=bot_credentials.
|
47
|
-
password=bot_credentials.
|
41
|
+
user_agent=bot_credentials.user_agent,
|
42
|
+
client_id=bot_credentials.client_id,
|
43
|
+
client_secret=bot_credentials.client_secret,
|
44
|
+
username=bot_credentials.username,
|
45
|
+
password=bot_credentials.password
|
48
46
|
)
|
49
|
-
return
|
47
|
+
return RedditInterfaceImplementation(praw_reddit)
|
redditadmin/program/__init__.py
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
-
from .program import Program,
|
2
|
-
|
3
|
-
|
1
|
+
from .program import Program as IProgram, AbstractProgram as Program,\
|
2
|
+
RecurringProgram as IRecurringProgram, AbstractRecurringProgram as RecurringProgram
|
3
|
+
from .streamprocessingprogram import StreamProcessingProgram as IStreamProcessingProgram,\
|
4
|
+
AbstractStreamProcessingProgram as StreamProcessingProgram,\
|
5
|
+
StreamFactory, SubmissionStreamFactory, CommentStreamFactory, CustomStreamFactory
|
redditadmin/program/program.py
CHANGED
@@ -1,26 +1,45 @@
|
|
1
1
|
import logging
|
2
2
|
import time
|
3
|
-
from abc import
|
3
|
+
from abc import ABCMeta, abstractmethod
|
4
4
|
from typing import Callable
|
5
5
|
|
6
6
|
|
7
|
-
class Program(
|
8
|
-
"""
|
7
|
+
class Program(metaclass=ABCMeta):
|
8
|
+
"""Encapsulates a simple program/script"""
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
@property
|
11
|
+
@abstractmethod
|
12
|
+
def program_name(self):
|
13
|
+
...
|
14
14
|
|
15
15
|
@abstractmethod
|
16
16
|
def execute(self, *args, **kwargs):
|
17
17
|
"""Execute the program"""
|
18
|
+
...
|
18
19
|
|
19
|
-
raise NotImplementedError()
|
20
20
|
|
21
|
+
class RecurringProgram(metaclass=ABCMeta, Program):
|
22
|
+
"""Encapsulates a looping program type"""
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
+
@abstractmethod
|
25
|
+
def _run_nature_core(self, *args, **kwargs):
|
26
|
+
"""Run core program"""
|
27
|
+
...
|
28
|
+
|
29
|
+
|
30
|
+
class AbstractProgram(Program, metaclass=ABCMeta):
|
31
|
+
|
32
|
+
def __init__(self, program_name: str):
|
33
|
+
self.__program_name = program_name
|
34
|
+
self._programLogger = logging.getLogger(
|
35
|
+
program_name
|
36
|
+
)
|
37
|
+
|
38
|
+
def program_name(self):
|
39
|
+
return self.__program_name
|
40
|
+
|
41
|
+
|
42
|
+
class AbstractRecurringProgram(RecurringProgram, AbstractProgram, metaclass=ABCMeta):
|
24
43
|
|
25
44
|
def __init__(
|
26
45
|
self,
|
@@ -28,7 +47,7 @@ class RecurringProgram(Program, ABC):
|
|
28
47
|
stop_condition: Callable[..., bool],
|
29
48
|
cooldown: float = 0
|
30
49
|
):
|
31
|
-
super().__init__(program_name)
|
50
|
+
super().__init__(program_name=program_name)
|
32
51
|
self._stopCondition = stop_condition
|
33
52
|
self._cooldown = cooldown
|
34
53
|
|
@@ -37,9 +56,3 @@ class RecurringProgram(Program, ABC):
|
|
37
56
|
self._run_nature_core(*args, **kwargs)
|
38
57
|
if self._cooldown and self._cooldown > 0:
|
39
58
|
time.sleep(self._cooldown)
|
40
|
-
|
41
|
-
@abstractmethod
|
42
|
-
def _run_nature_core(self, *args, **kwargs):
|
43
|
-
"""Run core program"""
|
44
|
-
|
45
|
-
raise NotImplementedError()
|
@@ -1,39 +1,47 @@
|
|
1
|
-
from abc import
|
1
|
+
from abc import ABCMeta, abstractmethod
|
2
2
|
from typing import Generator, Callable
|
3
3
|
|
4
4
|
from praw.models import Subreddit, ListingGenerator
|
5
5
|
from praw.models.util import stream_generator
|
6
6
|
|
7
|
-
from .program import RecurringProgram
|
7
|
+
from .program import RecurringProgram, AbstractRecurringProgram
|
8
8
|
from ..utility.decorators import consumestransientapierrors
|
9
9
|
|
10
10
|
|
11
|
-
class StreamFactory(
|
11
|
+
class StreamFactory(metaclass=ABCMeta):
|
12
12
|
"""
|
13
|
-
|
14
|
-
new Reddit Object streams at request
|
13
|
+
Produces new Reddit Object streams at request
|
15
14
|
"""
|
16
15
|
|
17
16
|
@abstractmethod
|
18
17
|
def get_new_stream(self) -> Generator:
|
19
18
|
"""Produce new stream"""
|
19
|
+
...
|
20
20
|
|
21
|
-
raise NotImplementedError()
|
22
21
|
|
23
|
-
|
24
|
-
class StreamProcessingProgram(RecurringProgram, ABC):
|
22
|
+
class StreamProcessingProgram(RecurringProgram, metaclass=ABCMeta):
|
25
23
|
"""
|
26
|
-
|
27
|
-
program
|
24
|
+
Encapsulates a stream processing program
|
28
25
|
"""
|
29
26
|
|
27
|
+
@abstractmethod
|
28
|
+
def _run_pause_handler(self, *args):
|
29
|
+
"""Execute when stream is paused"""
|
30
|
+
...
|
31
|
+
|
32
|
+
|
33
|
+
class AbstractStreamProcessingProgram(StreamProcessingProgram, AbstractRecurringProgram, metaclass=ABCMeta):
|
34
|
+
|
30
35
|
def __init__(
|
31
36
|
self,
|
32
37
|
stream_factory: StreamFactory,
|
33
38
|
stop_condition: Callable[..., bool],
|
34
39
|
program_name: str
|
35
40
|
):
|
36
|
-
super().__init__(
|
41
|
+
super().__init__(
|
42
|
+
program_name=program_name,
|
43
|
+
stop_condition=stop_condition
|
44
|
+
)
|
37
45
|
self.__streamFactory = stream_factory
|
38
46
|
|
39
47
|
@consumestransientapierrors
|
@@ -60,15 +68,10 @@ class StreamProcessingProgram(RecurringProgram, ABC):
|
|
60
68
|
|
61
69
|
self._run_nature_core(streamItem)
|
62
70
|
|
63
|
-
def _run_pause_handler(self, *args):
|
64
|
-
"""Execute when stream is paused"""
|
65
|
-
pass
|
66
|
-
|
67
71
|
|
68
72
|
class SubmissionStreamFactory(StreamFactory):
|
69
73
|
"""
|
70
|
-
|
71
|
-
new Submission streams at request
|
74
|
+
Produces new Submission streams at request
|
72
75
|
"""
|
73
76
|
|
74
77
|
def __init__(
|
@@ -91,8 +94,7 @@ class SubmissionStreamFactory(StreamFactory):
|
|
91
94
|
|
92
95
|
class CommentStreamFactory(StreamFactory):
|
93
96
|
"""
|
94
|
-
|
95
|
-
new Comment streams at request
|
97
|
+
Produces new Comment streams at request
|
96
98
|
"""
|
97
99
|
|
98
100
|
def __init__(
|
@@ -115,8 +117,7 @@ class CommentStreamFactory(StreamFactory):
|
|
115
117
|
|
116
118
|
class CustomStreamFactory(StreamFactory):
|
117
119
|
"""
|
118
|
-
|
119
|
-
stream of custom Reddit objects according to
|
120
|
+
Produces new stream of custom Reddit objects according to
|
120
121
|
the provided Listing Generator
|
121
122
|
"""
|
122
123
|
|
redditadmin/utility/__init__.py
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
-
from .botcredentials import BotCredentials
|
2
|
-
|
1
|
+
from .botcredentials import BotCredentials as IBotCredentials,\
|
2
|
+
BotCredentialsImplementation as BotCredentials, InvalidBotCredentialsError
|
3
|
+
from .contributions import retrieve_submissions_from_subreddit, retrieve_select_submissions, is_removed
|
3
4
|
from .decorators import consumestransientapierrors
|
4
|
-
from .
|
5
|
-
from .
|
5
|
+
from .miscellaneous import is_reddit_authenticated, BotInitializationError, InitializationError
|
6
|
+
from .redditinterface import RedditInterface as IRedditInterface,\
|
7
|
+
RedditInterfaceImplementation as RedditInterface
|
8
|
+
from .redditsubmission import RedditSubmission as IRedditSubmission,\
|
9
|
+
RedditSubmissionImplementation as RedditSubmission
|
@@ -1,13 +1,43 @@
|
|
1
|
-
|
1
|
+
from abc import ABCMeta, abstractmethod
|
2
|
+
|
3
|
+
|
4
|
+
class BotCredentials(metaclass=ABCMeta):
|
2
5
|
"""
|
3
|
-
|
6
|
+
Encapsulates the bot's credentials
|
4
7
|
"""
|
5
8
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
@property
|
10
|
+
@abstractmethod
|
11
|
+
def password(self) -> str:
|
12
|
+
"""Retrieve the bot's Password"""
|
13
|
+
...
|
14
|
+
|
15
|
+
@property
|
16
|
+
@abstractmethod
|
17
|
+
def client_secret(self) -> str:
|
18
|
+
"""Retrieve the bot's Client Secret"""
|
19
|
+
...
|
20
|
+
|
21
|
+
@property
|
22
|
+
@abstractmethod
|
23
|
+
def client_id(self) -> str:
|
24
|
+
"""Retrieve the bot's Client ID"""
|
25
|
+
...
|
26
|
+
|
27
|
+
@property
|
28
|
+
@abstractmethod
|
29
|
+
def user_agent(self) -> str:
|
30
|
+
"""Retrieve the bot's User Agent"""
|
31
|
+
...
|
32
|
+
|
33
|
+
@property
|
34
|
+
@abstractmethod
|
35
|
+
def username(self) -> str:
|
36
|
+
"""Retrieve the bot's Username"""
|
37
|
+
...
|
38
|
+
|
39
|
+
|
40
|
+
class BotCredentialsImplementation(BotCredentials):
|
11
41
|
|
12
42
|
def __init__(
|
13
43
|
self,
|
@@ -24,40 +54,30 @@ class BotCredentials:
|
|
24
54
|
self.__password = password
|
25
55
|
|
26
56
|
@property
|
27
|
-
def
|
28
|
-
"""Retrieve the bot's User Agent"""
|
29
|
-
|
57
|
+
def user_agent(self) -> str:
|
30
58
|
return self.__user_agent
|
31
59
|
|
32
60
|
@property
|
33
|
-
def
|
34
|
-
"""Retrieve the bot's Client ID"""
|
35
|
-
|
61
|
+
def client_id(self):
|
36
62
|
return self.__client_id
|
37
63
|
|
38
64
|
@property
|
39
|
-
def
|
40
|
-
"""Retrieve the bot's Client Secret"""
|
41
|
-
|
65
|
+
def client_secret(self):
|
42
66
|
return self.__client_secret
|
43
67
|
|
44
68
|
@property
|
45
|
-
def
|
46
|
-
"""Retrieve the bot's Username"""
|
47
|
-
|
69
|
+
def username(self):
|
48
70
|
return self.__username
|
49
71
|
|
50
72
|
@property
|
51
|
-
def
|
52
|
-
"""Retrieve the bot's Password"""
|
53
|
-
|
73
|
+
def password(self):
|
54
74
|
return self.__password
|
55
75
|
|
56
|
-
def clear_credentials(self):
|
57
|
-
"""Convenience method to clear the bot's credentials"""
|
58
76
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
77
|
+
class InvalidBotCredentialsError(Exception):
|
78
|
+
"""
|
79
|
+
Raised when provided bot credentials are invalid
|
80
|
+
"""
|
81
|
+
|
82
|
+
def __init__(self, *args):
|
83
|
+
super().__init__(self, args)
|
@@ -11,10 +11,9 @@ from prawcore.exceptions import RequestException, ServerError
|
|
11
11
|
|
12
12
|
def consumestransientapierrors(_execute_function=None, *, timeout: int = 30):
|
13
13
|
"""
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
program
|
14
|
+
Consumes common transient errors which may
|
15
|
+
occur while connecting to the Reddit API during
|
16
|
+
the running of the provided program
|
18
17
|
"""
|
19
18
|
|
20
19
|
def subsuming_function(execute_function):
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import praw
|
2
|
+
|
3
|
+
|
4
|
+
class InitializationError(Exception):
|
5
|
+
"""
|
6
|
+
Raised when the initialization of a module fails
|
7
|
+
"""
|
8
|
+
|
9
|
+
def __init__(self, *args):
|
10
|
+
super().__init__(self, args)
|
11
|
+
|
12
|
+
|
13
|
+
class BotInitializationError(InitializationError):
|
14
|
+
"""
|
15
|
+
Raised when the initialization of a bot module fails
|
16
|
+
"""
|
17
|
+
|
18
|
+
def __init__(self, *args):
|
19
|
+
super().__init__(*args)
|
20
|
+
|
21
|
+
|
22
|
+
def is_reddit_authenticated(praw_reddit_instance: praw.Reddit) -> bool:
|
23
|
+
"""
|
24
|
+
Convenience method to authenticate bot credentials
|
25
|
+
provided to Reddit instance
|
26
|
+
"""
|
27
|
+
|
28
|
+
return not praw_reddit_instance.read_only
|
@@ -1,19 +1,27 @@
|
|
1
1
|
# -*- coding: utf-8 -*
|
2
|
+
from abc import ABCMeta, abstractmethod
|
3
|
+
|
2
4
|
from praw import Reddit
|
3
5
|
|
4
6
|
|
5
|
-
class RedditInterface:
|
7
|
+
class RedditInterface(metaclass=ABCMeta):
|
6
8
|
"""
|
7
|
-
|
9
|
+
Encapsulates tools to interface with the Reddit API
|
8
10
|
"""
|
9
11
|
|
10
|
-
|
12
|
+
@property
|
13
|
+
@abstractmethod
|
14
|
+
def praw_reddit(self):
|
15
|
+
"""Retrieve the interface's PrawReddit instance"""
|
16
|
+
...
|
17
|
+
|
18
|
+
|
19
|
+
class RedditInterfaceImplementation(RedditInterface):
|
11
20
|
|
12
21
|
def __init__(self, praw_reddit: Reddit):
|
13
22
|
self.__prawReddit = praw_reddit
|
14
23
|
|
15
24
|
@property
|
16
|
-
def
|
17
|
-
"""Retrieve the interface's PrawReddit instance"""
|
25
|
+
def praw_reddit(self):
|
18
26
|
|
19
27
|
return self.__prawReddit
|
@@ -1,18 +1,26 @@
|
|
1
|
+
from abc import abstractmethod, ABCMeta
|
2
|
+
|
1
3
|
from praw.models import Submission
|
2
4
|
|
3
5
|
|
4
|
-
class RedditSubmission:
|
6
|
+
class RedditSubmission(metaclass=ABCMeta):
|
5
7
|
"""
|
6
|
-
|
8
|
+
Encapsulates a submission
|
7
9
|
"""
|
8
10
|
|
9
|
-
|
11
|
+
@property
|
12
|
+
@abstractmethod
|
13
|
+
def submission_id(self):
|
14
|
+
...
|
15
|
+
|
16
|
+
|
17
|
+
class RedditSubmissionImplementation(RedditSubmission):
|
10
18
|
|
11
19
|
def __init__(self, submission_id):
|
12
20
|
self.__submissionId = submission_id
|
13
21
|
|
14
22
|
@property
|
15
|
-
def
|
23
|
+
def submission_id(self):
|
16
24
|
return self.__submissionId
|
17
25
|
|
18
26
|
@classmethod
|
@@ -20,17 +28,17 @@ class RedditSubmission:
|
|
20
28
|
cls, submission_id: str
|
21
29
|
):
|
22
30
|
"""
|
23
|
-
Returns a
|
24
|
-
the provided
|
31
|
+
Returns a RedditSubmission object from
|
32
|
+
the provided submission_id
|
25
33
|
"""
|
26
|
-
return
|
34
|
+
return RedditSubmissionImplementation(submission_id)
|
27
35
|
|
28
36
|
@classmethod
|
29
37
|
def get_submission_from_praw_submission(
|
30
38
|
cls, praw_submission: Submission
|
31
39
|
):
|
32
40
|
"""
|
33
|
-
Returns a
|
41
|
+
Returns a RedditSubmission object from
|
34
42
|
the provided PRAW submission
|
35
43
|
"""
|
36
|
-
return
|
44
|
+
return RedditSubmissionImplementation(praw_submission.id)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: redditadmin
|
3
|
-
Version: 0.0
|
3
|
+
Version: 0.1.0
|
4
4
|
Summary: Extensible Python administrative bot
|
5
5
|
Project-URL: Homepage, https://github.com/Grod56/reddit-admin
|
6
6
|
Project-URL: Issues, https://github.com/Grod56/reddit-admin/issues
|
@@ -70,7 +70,15 @@ _NOTE: `RedditAdmin.run()` is a blocking command, meaning that no further code w
|
|
70
70
|
Console output:
|
71
71
|
|
72
72
|
```
|
73
|
-
redditadmin.core : Initializing the bot
|
73
|
+
redditadmin.core : Initializing the bot
|
74
|
+
Asynchronous Plugins Executor : Initializing Plugins Executor
|
75
|
+
Asynchronous Plugins Executor : Retrieving initial program commands
|
76
|
+
Asynchronous Plugins Executor : Executing initial program commands
|
77
|
+
Asynchronous Plugins Executor : Running program 'plugin1_program'
|
78
|
+
Asynchronous Plugins Executor : Running program 'plugin2_program'
|
79
|
+
Asynchronous Plugins Executor : Programs Executor initialized
|
80
|
+
redditadmin.core : Bot successfully initialized
|
81
|
+
redditadmin.core : The bot is now running
|
74
82
|
```
|
75
83
|
|
76
84
|
### Bot modes
|
@@ -122,17 +130,21 @@ Plugin:
|
|
122
130
|
|
123
131
|
```py
|
124
132
|
class MyPlugin[Plugin[MyProgram]]
|
125
|
-
"""The plugin for our program"""
|
126
133
|
|
127
|
-
def __init__():
|
128
|
-
super().__init__("myprogram")
|
129
134
|
|
130
|
-
|
131
|
-
"""Overriden from Plugin superclass"""
|
135
|
+
"""The plugin for our program"""
|
132
136
|
|
133
|
-
praw_reddit = reddit_interface.get_praw_reddit
|
134
137
|
|
135
|
-
|
138
|
+
def __init__():
|
139
|
+
super().__init__("myprogram")
|
140
|
+
|
141
|
+
|
142
|
+
def get_program(self, reddit_interface):
|
143
|
+
"""Overriden from Plugin superclass"""
|
144
|
+
|
145
|
+
praw_reddit = reddit_interface.praw_reddit
|
146
|
+
|
147
|
+
return MyProgram(praw_reddit)
|
136
148
|
```
|
137
149
|
|
138
150
|
Voila! We may now supply our plugin to the bot and run it just as we did before
|
@@ -0,0 +1,21 @@
|
|
1
|
+
redditadmin/__init__.py,sha256=H9tJpqCduGTfE__euVT9Qp5vWzS6VI3iXmGfbl_cixw,120
|
2
|
+
redditadmin/core.py,sha256=eV_5JAZ_KvqVDxRkqrzzMumVkxs8SZecsiv3j9P5d20,14012
|
3
|
+
redditadmin/plugin/__init__.py,sha256=aFjHxkbg-7X3NTdl0TeVWIbtkc-Efzz2iZPvV--UdNg,395
|
4
|
+
redditadmin/plugin/asynchronouspluginsexecutor.py,sha256=n83iXNygrn8l0DnkEt0jb1UbOV1VtzxTV7OD3sJDsuQ,6897
|
5
|
+
redditadmin/plugin/plugin.py,sha256=qJFmmruUn-CiKZcw6Vl13EpHm1bAd9D0CwKnqqDsYoU,1906
|
6
|
+
redditadmin/plugin/pluginsexecutor.py,sha256=5iBcYDsk_MEN5DdO95T_Lb3nDwF1pBkRKoddmAY-jF4,1948
|
7
|
+
redditadmin/plugin/redditinterfacefactory.py,sha256=QIyN0PIuzEAMPAlxD58UE6MMpGxMM08Xb_V9rCtkrJU,1587
|
8
|
+
redditadmin/program/__init__.py,sha256=Vu_AxIUS4U2-6dAIGlzeQNvLtS1mY_5wDxUB5xGVV_k,406
|
9
|
+
redditadmin/program/program.py,sha256=U4vKd1EJI6ee37InFHuvLwsYQG7WtDzRoti9Y_i5URA,1524
|
10
|
+
redditadmin/program/streamprocessingprogram.py,sha256=DVWURQiQNtGPOlsiCDG5Abmw3_GvAPKEGJI19AtUcP8,3995
|
11
|
+
redditadmin/utility/__init__.py,sha256=7-MxaEvDEoozvwWO56r75wgabuKQuI4jtdl2JhrmRFE,648
|
12
|
+
redditadmin/utility/botcredentials.py,sha256=g9wkkPy2XUe7zDV6Mtzpxljr7BclsjPzbu2W6Uiy7J4,1801
|
13
|
+
redditadmin/utility/contributions.py,sha256=dPU0OA0PBxh5ktHJtiLizYM5xtqPd-9VhOzRkvdw4iI,1490
|
14
|
+
redditadmin/utility/decorators.py,sha256=yk2ZQXA2sLRBIZRl8nvHzeyM5DjMYHwtCZcnNOz2wxY,1629
|
15
|
+
redditadmin/utility/miscellaneous.py,sha256=8FaWN6RyxGqCvM8Y1_Ud09mQMll8TpVU9WyYe-9np0w,632
|
16
|
+
redditadmin/utility/redditinterface.py,sha256=Nd9cZEyS0tRtJWpy_QO0TsfQzG5LK_K5hSokl3Hu2IA,582
|
17
|
+
redditadmin/utility/redditsubmission.py,sha256=SshPTHHCFLrBOMudKNc8P_kn9oVXUdbyxwnaV54xQnE,1057
|
18
|
+
redditadmin-0.1.0.dist-info/METADATA,sha256=CXWrGFLOZpl55AZvwowwrF5Q8Iv515oN0glfnLgMDR0,5338
|
19
|
+
redditadmin-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
20
|
+
redditadmin-0.1.0.dist-info/licenses/LICENSE,sha256=kieFEKjHWxFgNnmvKA_eXHmaQQZ9ZgEI_5m14IiVzAo,1091
|
21
|
+
redditadmin-0.1.0.dist-info/RECORD,,
|
redditadmin/plugin/exceptions.py
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
from ..utility.exceptions import InitializationError
|
2
|
-
|
3
|
-
|
4
|
-
class PluginsExecutorInitializationError(InitializationError):
|
5
|
-
"""
|
6
|
-
Class to encapsulate an error in the initialization
|
7
|
-
of a Plugins Executor module
|
8
|
-
"""
|
9
|
-
|
10
|
-
def __init__(self, *args):
|
11
|
-
super().__init__(*args)
|
@@ -1,28 +0,0 @@
|
|
1
|
-
class InitializationError(Exception):
|
2
|
-
"""
|
3
|
-
Class to encapsulate an error in the
|
4
|
-
initialization of a module
|
5
|
-
"""
|
6
|
-
|
7
|
-
def __init__(self, *args):
|
8
|
-
super().__init__(self, args)
|
9
|
-
|
10
|
-
|
11
|
-
class BotInitializationError(InitializationError):
|
12
|
-
"""
|
13
|
-
Class to encapsulate an error in the
|
14
|
-
initialization of a bot module
|
15
|
-
"""
|
16
|
-
|
17
|
-
def __init__(self, *args):
|
18
|
-
super().__init__(*args)
|
19
|
-
|
20
|
-
|
21
|
-
class InvalidBotCredentialsError(Exception):
|
22
|
-
"""
|
23
|
-
Class encapsulating an exception raised
|
24
|
-
when provided bot credentials are invalid
|
25
|
-
"""
|
26
|
-
|
27
|
-
def __init__(self, *args):
|
28
|
-
super().__init__(self, args)
|
@@ -1,22 +0,0 @@
|
|
1
|
-
redditadmin/__init__.py,sha256=H9tJpqCduGTfE__euVT9Qp5vWzS6VI3iXmGfbl_cixw,120
|
2
|
-
redditadmin/core.py,sha256=iGgN74nYgRLvrkAue9hk-Ptdmpr0oUCx8xWdW5ROBaY,15173
|
3
|
-
redditadmin/plugin/__init__.py,sha256=qHKyhBz5ovgef0lcXtIUsP7ZbryDrXCxRylyGJJjgTo,134
|
4
|
-
redditadmin/plugin/asynchronouspluginsexecutor.py,sha256=WkEbTFciqgJ2cQ59AgXJBsPpPntugJxF2KapB1NNmwY,7096
|
5
|
-
redditadmin/plugin/exceptions.py,sha256=tNwWiitjeCXVFTL9_y3fXF_Dzjk-CUHd2uqvl0_UUmI,298
|
6
|
-
redditadmin/plugin/plugin.py,sha256=_Zr1mhTP6y1cZDxxd8vcRYodSeiOViprmZ7TGJwaA6A,1673
|
7
|
-
redditadmin/plugin/pluginsexecutor.py,sha256=i758rqdlFysJh63ZzVY3fqQJriH2hc-gubiuK9wa24Y,1496
|
8
|
-
redditadmin/plugin/redditinterfacefactory.py,sha256=20RInQUmvHFnbE7-SttjfYa1dsRTD0lgdh5mQVieFUw,1654
|
9
|
-
redditadmin/program/__init__.py,sha256=86ezrveWRark-dpsSjuD_dPvsxDbh7uqHE-Porlhd_E,200
|
10
|
-
redditadmin/program/program.py,sha256=pGvx03PWkfQsfdRfQ-g5DbXSG0NjDuGQBrTU3baQJaE,1205
|
11
|
-
redditadmin/program/streamprocessingprogram.py,sha256=r-VuHmNdEiJq6sAoDDUub-VlX04lVCjgYCBfiiw9gPE,3888
|
12
|
-
redditadmin/utility/__init__.py,sha256=bZlqoWdMCmR7COJiiSY6RamzyqQSvbLHyifdvrBW4Ac,302
|
13
|
-
redditadmin/utility/botcredentials.py,sha256=qkrKtqXvA0h1NSwy70ESxsZyyXwXPiB5USpMt-56UwY,1462
|
14
|
-
redditadmin/utility/contributionsutility.py,sha256=FHOlMJE3Vdk5H2j-_b0TzGP9rhGn-tAxQqx4_-hk8mg,1492
|
15
|
-
redditadmin/utility/decorators.py,sha256=T0Mir1zX3_tHVDuU3UaQ1Mg1ayapaL84_GSbuifg5lY,1661
|
16
|
-
redditadmin/utility/exceptions.py,sha256=8XliprLrcYtKYji6JPYw6nfC3yA0i551iOSV3Op06A4,652
|
17
|
-
redditadmin/utility/redditinterface.py,sha256=kWmUrdQffujf3j9bDE9wCH3FAmvckeaOWcl9NV3MRy0,415
|
18
|
-
redditadmin/utility/redditsubmission.py,sha256=tB830FGKmnFMBg5GXrMcGKYdGtSSYgt_uCCaLnNYlC4,862
|
19
|
-
redditadmin-0.0.5.dist-info/METADATA,sha256=mLWRqDtbpk_vjz1Q3zZkqV1oOVtw2bvXatUvquP7x1w,5842
|
20
|
-
redditadmin-0.0.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
21
|
-
redditadmin-0.0.5.dist-info/licenses/LICENSE,sha256=kieFEKjHWxFgNnmvKA_eXHmaQQZ9ZgEI_5m14IiVzAo,1091
|
22
|
-
redditadmin-0.0.5.dist-info/RECORD,,
|
File without changes
|
File without changes
|