redditadmin 0.0.6__tar.gz → 0.1.0__tar.gz
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-0.0.6 → redditadmin-0.1.0}/.idea/inspectionProfiles/profiles_settings.xml +1 -0
- {redditadmin-0.0.6 → redditadmin-0.1.0}/.idea/reddit-admin.iml +3 -1
- {redditadmin-0.0.6 → redditadmin-0.1.0}/.idea/workspace.xml +32 -3
- {redditadmin-0.0.6 → redditadmin-0.1.0}/PKG-INFO +12 -8
- {redditadmin-0.0.6 → redditadmin-0.1.0}/README.md +11 -7
- {redditadmin-0.0.6 → redditadmin-0.1.0}/pyproject.toml +1 -1
- {redditadmin-0.0.6 → redditadmin-0.1.0}/src/redditadmin/core.py +27 -67
- redditadmin-0.1.0/src/redditadmin/plugin/__init__.py +5 -0
- {redditadmin-0.0.6 → redditadmin-0.1.0}/src/redditadmin/plugin/asynchronouspluginsexecutor.py +3 -8
- {redditadmin-0.0.6 → redditadmin-0.1.0}/src/redditadmin/plugin/plugin.py +29 -17
- {redditadmin-0.0.6 → redditadmin-0.1.0}/src/redditadmin/plugin/pluginsexecutor.py +37 -17
- redditadmin-0.1.0/src/redditadmin/plugin/redditinterfacefactory.py +47 -0
- redditadmin-0.1.0/src/redditadmin/program/__init__.py +5 -0
- {redditadmin-0.0.6 → redditadmin-0.1.0}/src/redditadmin/program/program.py +30 -17
- {redditadmin-0.0.6 → redditadmin-0.1.0}/src/redditadmin/program/streamprocessingprogram.py +22 -21
- redditadmin-0.1.0/src/redditadmin/utility/__init__.py +9 -0
- redditadmin-0.1.0/src/redditadmin/utility/botcredentials.py +83 -0
- redditadmin-0.0.6/src/redditadmin/utility/contributionsutility.py → redditadmin-0.1.0/src/redditadmin/utility/contributions.py +1 -1
- {redditadmin-0.0.6 → redditadmin-0.1.0}/src/redditadmin/utility/decorators.py +3 -4
- redditadmin-0.1.0/src/redditadmin/utility/miscellaneous.py +28 -0
- redditadmin-0.1.0/src/redditadmin/utility/redditinterface.py +27 -0
- redditadmin-0.1.0/src/redditadmin/utility/redditsubmission.py +44 -0
- redditadmin-0.0.6/src/redditadmin/plugin/__init__.py +0 -3
- redditadmin-0.0.6/src/redditadmin/plugin/exceptions.py +0 -11
- redditadmin-0.0.6/src/redditadmin/plugin/redditinterfacefactory.py +0 -49
- redditadmin-0.0.6/src/redditadmin/program/__init__.py +0 -3
- redditadmin-0.0.6/src/redditadmin/utility/__init__.py +0 -5
- redditadmin-0.0.6/src/redditadmin/utility/botcredentials.py +0 -63
- redditadmin-0.0.6/src/redditadmin/utility/exceptions.py +0 -28
- redditadmin-0.0.6/src/redditadmin/utility/redditinterface.py +0 -19
- redditadmin-0.0.6/src/redditadmin/utility/redditsubmission.py +0 -36
- {redditadmin-0.0.6 → redditadmin-0.1.0}/.gitignore +0 -0
- {redditadmin-0.0.6 → redditadmin-0.1.0}/.idea/.gitignore +0 -0
- {redditadmin-0.0.6 → redditadmin-0.1.0}/.idea/misc.xml +0 -0
- {redditadmin-0.0.6 → redditadmin-0.1.0}/.idea/modules.xml +0 -0
- {redditadmin-0.0.6 → redditadmin-0.1.0}/.idea/vcs.xml +0 -0
- {redditadmin-0.0.6 → redditadmin-0.1.0}/.prettierrc +0 -0
- {redditadmin-0.0.6 → redditadmin-0.1.0}/.vscode/settings.json +0 -0
- {redditadmin-0.0.6 → redditadmin-0.1.0}/LICENSE +0 -0
- {redditadmin-0.0.6 → redditadmin-0.1.0}/praw.ini +0 -0
- {redditadmin-0.0.6 → redditadmin-0.1.0}/requirements.txt +0 -0
- {redditadmin-0.0.6 → redditadmin-0.1.0}/src/__init__.py +0 -0
- {redditadmin-0.0.6 → redditadmin-0.1.0}/src/redditadmin/__init__.py +0 -0
@@ -1,7 +1,9 @@
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
2
2
|
<module type="PYTHON_MODULE" version="4">
|
3
3
|
<component name="NewModuleRootManager">
|
4
|
-
<content url="file://$MODULE_DIR$"
|
4
|
+
<content url="file://$MODULE_DIR$">
|
5
|
+
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
6
|
+
</content>
|
5
7
|
<orderEntry type="jdk" jdkName="Python 3.11 (reddit-admin)" jdkType="Python SDK" />
|
6
8
|
<orderEntry type="sourceFolder" forTests="false" />
|
7
9
|
</component>
|
@@ -4,7 +4,28 @@
|
|
4
4
|
<option name="autoReloadType" value="SELECTIVE" />
|
5
5
|
</component>
|
6
6
|
<component name="ChangeListManager">
|
7
|
-
<list default="true" id="195f63d3-192c-4e64-8cd8-909be23b7f21" name="Changes" comment=""
|
7
|
+
<list default="true" id="195f63d3-192c-4e64-8cd8-909be23b7f21" name="Changes" comment="">
|
8
|
+
<change beforePath="$PROJECT_DIR$/.idea/inspectionProfiles/profiles_settings.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/inspectionProfiles/profiles_settings.xml" afterDir="false" />
|
9
|
+
<change beforePath="$PROJECT_DIR$/.idea/reddit-admin.iml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/reddit-admin.iml" afterDir="false" />
|
10
|
+
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
|
11
|
+
<change beforePath="$PROJECT_DIR$/src/redditadmin/core.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/redditadmin/core.py" afterDir="false" />
|
12
|
+
<change beforePath="$PROJECT_DIR$/src/redditadmin/plugin/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/redditadmin/plugin/__init__.py" afterDir="false" />
|
13
|
+
<change beforePath="$PROJECT_DIR$/src/redditadmin/plugin/asynchronouspluginsexecutor.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/redditadmin/plugin/asynchronouspluginsexecutor.py" afterDir="false" />
|
14
|
+
<change beforePath="$PROJECT_DIR$/src/redditadmin/plugin/exceptions.py" beforeDir="false" />
|
15
|
+
<change beforePath="$PROJECT_DIR$/src/redditadmin/plugin/plugin.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/redditadmin/plugin/plugin.py" afterDir="false" />
|
16
|
+
<change beforePath="$PROJECT_DIR$/src/redditadmin/plugin/pluginsexecutor.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/redditadmin/plugin/pluginsexecutor.py" afterDir="false" />
|
17
|
+
<change beforePath="$PROJECT_DIR$/src/redditadmin/plugin/redditinterfacefactory.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/redditadmin/plugin/redditinterfacefactory.py" afterDir="false" />
|
18
|
+
<change beforePath="$PROJECT_DIR$/src/redditadmin/program/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/redditadmin/program/__init__.py" afterDir="false" />
|
19
|
+
<change beforePath="$PROJECT_DIR$/src/redditadmin/program/program.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/redditadmin/program/program.py" afterDir="false" />
|
20
|
+
<change beforePath="$PROJECT_DIR$/src/redditadmin/program/streamprocessingprogram.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/redditadmin/program/streamprocessingprogram.py" afterDir="false" />
|
21
|
+
<change beforePath="$PROJECT_DIR$/src/redditadmin/utility/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/redditadmin/utility/__init__.py" afterDir="false" />
|
22
|
+
<change beforePath="$PROJECT_DIR$/src/redditadmin/utility/botcredentials.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/redditadmin/utility/botcredentials.py" afterDir="false" />
|
23
|
+
<change beforePath="$PROJECT_DIR$/src/redditadmin/utility/contributionsutility.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/redditadmin/utility/contributions.py" afterDir="false" />
|
24
|
+
<change beforePath="$PROJECT_DIR$/src/redditadmin/utility/decorators.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/redditadmin/utility/decorators.py" afterDir="false" />
|
25
|
+
<change beforePath="$PROJECT_DIR$/src/redditadmin/utility/exceptions.py" beforeDir="false" />
|
26
|
+
<change beforePath="$PROJECT_DIR$/src/redditadmin/utility/redditinterface.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/redditadmin/utility/redditinterface.py" afterDir="false" />
|
27
|
+
<change beforePath="$PROJECT_DIR$/src/redditadmin/utility/redditsubmission.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/redditadmin/utility/redditsubmission.py" afterDir="false" />
|
28
|
+
</list>
|
8
29
|
<option name="SHOW_DIALOG" value="false" />
|
9
30
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
10
31
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
@@ -20,6 +41,14 @@
|
|
20
41
|
<component name="Git.Settings">
|
21
42
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
22
43
|
</component>
|
44
|
+
<component name="GitSEFilterConfiguration">
|
45
|
+
<file-type-list>
|
46
|
+
<filtered-out-file-type name="LOCAL_BRANCH" />
|
47
|
+
<filtered-out-file-type name="REMOTE_BRANCH" />
|
48
|
+
<filtered-out-file-type name="TAG" />
|
49
|
+
<filtered-out-file-type name="COMMIT_BY_MESSAGE" />
|
50
|
+
</file-type-list>
|
51
|
+
</component>
|
23
52
|
<component name="MarkdownSettingsMigration">
|
24
53
|
<option name="stateVersion" value="1" />
|
25
54
|
</component>
|
@@ -34,8 +63,8 @@
|
|
34
63
|
<component name="PropertiesComponent">
|
35
64
|
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
36
65
|
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
|
37
|
-
<property name="last_opened_file_path" value="$PROJECT_DIR
|
38
|
-
<property name="settings.editor.selected.configurable" value="
|
66
|
+
<property name="last_opened_file_path" value="$PROJECT_DIR$/src/redditadmin/utility/contributionsutility.py" />
|
67
|
+
<property name="settings.editor.selected.configurable" value="Errors" />
|
39
68
|
</component>
|
40
69
|
<component name="RecentsManager">
|
41
70
|
<key name="MoveFile.RECENT_KEYS">
|
@@ -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
|
@@ -130,17 +130,21 @@ Plugin:
|
|
130
130
|
|
131
131
|
```py
|
132
132
|
class MyPlugin[Plugin[MyProgram]]
|
133
|
-
"""The plugin for our program"""
|
134
133
|
|
135
|
-
def __init__():
|
136
|
-
super().__init__("myprogram")
|
137
134
|
|
138
|
-
|
139
|
-
"""Overriden from Plugin superclass"""
|
135
|
+
"""The plugin for our program"""
|
140
136
|
|
141
|
-
praw_reddit = reddit_interface.get_praw_reddit
|
142
137
|
|
143
|
-
|
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)
|
144
148
|
```
|
145
149
|
|
146
150
|
Voila! We may now supply our plugin to the bot and run it just as we did before
|
@@ -116,17 +116,21 @@ Plugin:
|
|
116
116
|
|
117
117
|
```py
|
118
118
|
class MyPlugin[Plugin[MyProgram]]
|
119
|
-
"""The plugin for our program"""
|
120
119
|
|
121
|
-
def __init__():
|
122
|
-
super().__init__("myprogram")
|
123
120
|
|
124
|
-
|
125
|
-
"""Overriden from Plugin superclass"""
|
121
|
+
"""The plugin for our program"""
|
126
122
|
|
127
|
-
praw_reddit = reddit_interface.get_praw_reddit
|
128
123
|
|
129
|
-
|
124
|
+
def __init__():
|
125
|
+
super().__init__("myprogram")
|
126
|
+
|
127
|
+
|
128
|
+
def get_program(self, reddit_interface):
|
129
|
+
"""Overriden from Plugin superclass"""
|
130
|
+
|
131
|
+
praw_reddit = reddit_interface.praw_reddit
|
132
|
+
|
133
|
+
return MyProgram(praw_reddit)
|
130
134
|
```
|
131
135
|
|
132
136
|
Voila! We may now supply our plugin to the bot and run it just as we did before
|
@@ -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)
|
@@ -0,0 +1,5 @@
|
|
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
|
{redditadmin-0.0.6 → redditadmin-0.1.0}/src/redditadmin/plugin/asynchronouspluginsexecutor.py
RENAMED
@@ -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():
|
@@ -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)
|
@@ -0,0 +1,47 @@
|
|
1
|
+
from abc import ABCMeta, abstractmethod
|
2
|
+
|
3
|
+
import praw
|
4
|
+
|
5
|
+
from ..utility.botcredentials import BotCredentials, InvalidBotCredentialsError
|
6
|
+
from ..utility.miscellaneous import is_reddit_authenticated
|
7
|
+
from ..utility.redditinterface import RedditInterface, RedditInterfaceImplementation
|
8
|
+
|
9
|
+
|
10
|
+
class RedditInterfaceFactory(metaclass=ABCMeta):
|
11
|
+
"""Factory for RedditInterface objects"""
|
12
|
+
|
13
|
+
@abstractmethod
|
14
|
+
def get_reddit_interface(self) -> RedditInterface:
|
15
|
+
"""Retrieve new Reddit Interface"""
|
16
|
+
...
|
17
|
+
|
18
|
+
|
19
|
+
class DefaultRedditInterfaceFactory(RedditInterfaceFactory):
|
20
|
+
|
21
|
+
def __init__(
|
22
|
+
self,
|
23
|
+
bot_credentials: BotCredentials
|
24
|
+
):
|
25
|
+
praw_reddit = praw.Reddit(
|
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
|
31
|
+
)
|
32
|
+
if not is_reddit_authenticated(praw_reddit):
|
33
|
+
raise InvalidBotCredentialsError
|
34
|
+
|
35
|
+
self.__botCredentials = bot_credentials
|
36
|
+
|
37
|
+
def get_reddit_interface(self):
|
38
|
+
|
39
|
+
bot_credentials = self.__botCredentials
|
40
|
+
praw_reddit = praw.Reddit(
|
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
|
46
|
+
)
|
47
|
+
return RedditInterfaceImplementation(praw_reddit)
|
@@ -0,0 +1,5 @@
|
|
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
|