vcon 0.1__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.
vcon/cli.py ADDED
@@ -0,0 +1,337 @@
1
+ """
2
+ Module for vcon command line interface script functions. Pulled out of vcon CLI
3
+ script file so that it coould more easily be tested with pytest.
4
+ """
5
+
6
+ import sys
7
+ import pathlib
8
+ import typing
9
+ import contextlib
10
+ import vcon
11
+
12
+ def get_mime_type(file_name):
13
+ """ derive mimetype from fle extension """
14
+ path = pathlib.PurePath(file_name)
15
+ extension = path.suffix.lower()
16
+
17
+ print("extension: {}".format(extension), file=sys.stderr)
18
+
19
+ if(extension == ".wav"):
20
+ mimetype = vcon.Vcon.MIMETYPE_AUDIO_WAV
21
+
22
+ else:
23
+ raise Exception("MIME type not defined for extension: {}".format(extension))
24
+
25
+ return(mimetype)
26
+
27
+ def main(argv : typing.Optional[typing.Sequence[str]] = None) -> int:
28
+ import argparse
29
+ import json
30
+ import sox
31
+ import email
32
+ import email.utils
33
+ import time
34
+ import socket
35
+
36
+ parser = argparse.ArgumentParser("vCon operations such as construction, signing, encryption, verification, decrytpion, filtering")
37
+ input_group = parser.add_mutually_exclusive_group()
38
+ input_group.add_argument("-i", "--infile", metavar='infile', nargs='?', type=argparse.FileType('r'), default=sys.stdin)
39
+ input_group.add_argument("-n", "--newvcon", action="store_true")
40
+
41
+ parser.add_argument("-o", "--outfile", metavar='outfile', nargs='?', type=argparse.FileType('w'), default=sys.stdout)
42
+
43
+ parser.add_argument("-r", "--register-filter-plugin", nargs=3,
44
+ action="append", type=str, default=[])
45
+
46
+ subparsers_command = parser.add_subparsers(dest="command")
47
+
48
+ addparser = subparsers_command.add_parser("add")
49
+ subparsers_add = addparser.add_subparsers(dest="add_command")
50
+ add_in_recording_subparsers = subparsers_add.add_parser("in-recording")
51
+ add_in_recording_subparsers.add_argument("recfile", metavar='recording_file', nargs=1, type=pathlib.Path, default=None)
52
+ add_in_recording_subparsers.add_argument("start", metavar='start_time', nargs=1, type=str, default=None)
53
+ add_in_recording_subparsers.add_argument("parties", metavar='parties', nargs=1, type=str, default=None)
54
+
55
+ add_ex_recording_subparsers = subparsers_add.add_parser("ex-recording")
56
+ add_ex_recording_subparsers.add_argument("recfile", metavar='recording_file', nargs=1, type=pathlib.Path, default=None)
57
+ add_ex_recording_subparsers.add_argument("start", metavar='start_time', nargs=1, type=str, default=None)
58
+ add_ex_recording_subparsers.add_argument("parties", metavar='parties', nargs=1, type=str, default=None)
59
+ add_ex_recording_subparsers.add_argument("url", metavar='url', nargs=1, type=str, default=None)
60
+
61
+ add_in_email_subparsers = subparsers_add.add_parser("in-email")
62
+ add_in_email_subparsers.add_argument("emailfile", metavar='email_file', nargs=1, type=pathlib.Path, default=None)
63
+ add_in_email_subparsers.add_argument("start", metavar='start_time', nargs="?", type=str, default=None)
64
+ add_in_email_subparsers.add_argument("parties", metavar='parties', nargs="?", type=str, default=None)
65
+
66
+ extractparser = subparsers_command.add_parser("extract")
67
+ subparsers_extract = extractparser.add_subparsers(dest="extract_command")
68
+ extract_dialog_subparsers = subparsers_extract.add_parser("dialog")
69
+ extract_dialog_subparsers.add_argument("index", metavar='dialog_index', nargs=1, type=int, default=None)
70
+
71
+ filter_parser = subparsers_command.add_parser("filter")
72
+ fn_help = "Name of filter plugin or default type filter plugin name"
73
+ filter_parser.add_argument("filter_name", metavar="filter_plugin_name", nargs=1, type=str, help=fn_help, default=None, action="append")
74
+ fo_help="JSON object (kwargs) with key name values which are options passed to the filter. (e.g. \'{\"a\" : 1, \"b\" : \"two\"}\' )"
75
+ filter_parser.add_argument("-fo", "--filter-options", metavar='filter_options', nargs=1, type=str, help=fo_help, action="append")
76
+
77
+ sign_parser = subparsers_command.add_parser("sign")
78
+ sign_parser.add_argument("privkey", metavar='private_key_file', nargs=1, type=pathlib.Path, default=None)
79
+ sign_parser.add_argument("pubkey", metavar='public_key_file', nargs='+', type=pathlib.Path, default=None)
80
+
81
+ verify_parser = subparsers_command.add_parser("verify")
82
+ verify_parser.add_argument("pubkey", metavar='public_key_file', nargs='+', type=pathlib.Path, default=None)
83
+
84
+ encrypt_parser = subparsers_command.add_parser("encrypt")
85
+ encrypt_parser.add_argument("pubkey", metavar='public_key_file', nargs='+', type=pathlib.Path, default=None)
86
+
87
+ decrypt_parser = subparsers_command.add_parser("decrypt")
88
+ decrypt_parser.add_argument("privkey", metavar='private_key_file', nargs=1, type=pathlib.Path, default=None)
89
+ decrypt_parser.add_argument("pubkey", metavar='public_key_file', nargs=1, type=pathlib.Path, default=None)
90
+
91
+ args = parser.parse_args(argv)
92
+
93
+ print("args: {}".format(args), file=sys.stderr)
94
+ print("args dir: {}".format(dir(args)), file=sys.stderr)
95
+
96
+ print("command: {}".format(args.command), file=sys.stderr)
97
+
98
+ for filter_plugin_registration in args.register_filter_plugin:
99
+ vcon.filter_plugins.FilterPluginRegistry.register(
100
+ filter_plugin_registration[0],
101
+ filter_plugin_registration[1],
102
+ filter_plugin_registration[2],
103
+ filter_plugin_registration[0],
104
+ replace=True)
105
+
106
+ if(args.command == "sign"):
107
+ print("priv key files: {}".format(len(args.privkey)), file=sys.stderr)
108
+ if(args.privkey[0].exists()):
109
+ print("priv key: {} exists".format(str(args.privkey[0])), file=sys.stderr)
110
+ else:
111
+ print("priv key: {} does NOT exist".format(str(args.privkey[0])), file=sys.stderr)
112
+
113
+ print("pub key files: {}".format(len(args.pubkey)), file=sys.stderr)
114
+
115
+ if(args.command == "verify"):
116
+ if(args.pubkey[0].exists()):
117
+ print("pub key: {} exists".format(str(args.pubkey[0])), file=sys.stderr)
118
+ else:
119
+ print("pub key: {} does NOT exist".format(str(args.pubkey[0])), file=sys.stderr)
120
+
121
+ if(args.command == "encrypt"):
122
+ if(args.pubkey[0].exists()):
123
+ print("pub key: {} exists".format(str(args.pubkey[0])), file=sys.stderr)
124
+ else:
125
+ print("pub key: {} does NOT exist".format(str(args.pubkey[0])), file=sys.stderr)
126
+
127
+ if(args.command == "decrypt"):
128
+ if(args.pubkey[0].exists()):
129
+ print("pub key: {} exists".format(str(args.pubkey[0])), file=sys.stderr)
130
+ else:
131
+ print("pub key: {} does NOT exist".format(str(args.pubkey[0])), file=sys.stderr)
132
+ if(args.privkey[0].exists()):
133
+ print("priv key: {} exists".format(str(args.privkey[0])), file=sys.stderr)
134
+ else:
135
+ print("priv key: {} does NOT exist".format(str(args.privkey[0])), file=sys.stderr)
136
+
137
+ if(args.command == "add"):
138
+ print("add: {}".format(args.add_command), file=sys.stderr)
139
+
140
+ """
141
+ Options:
142
+ [-n | -i <file_name>][-o <file_name>][-r filter_plugin_name plugin_module plugin_class_name [-r ...]]
143
+
144
+ Commands:
145
+ add in-recording <file_name> <start_date> <parties>
146
+ add ex-recording <file_name> <start_date> <parties> <url>
147
+
148
+ filter filter-name [-fo filter-options-dict]
149
+
150
+ sign private_key x5c1[, x5c2]...
151
+
152
+ verify ca_cert
153
+
154
+ encrypt x5c1[, x5c2]... signing_private_key
155
+
156
+ decrypt private_key, ca_cert
157
+
158
+ """
159
+
160
+ print("reading", file=sys.stderr)
161
+
162
+ print("out: {}".format(type(args.outfile)), file=sys.stderr)
163
+ print("in: {}".format(type(args.infile)), file=sys.stderr)
164
+ print("new in {}".format(args.newvcon), file=sys.stderr)
165
+ print("filter plugin registrations in {}".format(args.register_filter_plugin), file=sys.stderr)
166
+ in_vcon = vcon.Vcon()
167
+ if(not args.newvcon):
168
+ in_vcon_json = args.infile.read()
169
+ if(in_vcon_json is not None and len(in_vcon_json) > 0):
170
+ in_vcon.loads(in_vcon_json)
171
+ else:
172
+ pass
173
+
174
+ # Use default serialization for state of vCon
175
+ signed_json = True
176
+
177
+ # By default we output the vCon at the end
178
+ stdout_vcon = True
179
+
180
+ if(args.command == "sign"):
181
+ in_vcon.sign(args.privkey[0], args.pubkey)
182
+
183
+ elif(args.command == "verify"):
184
+ print("state: {}".format(in_vcon._state), file=sys.stderr)
185
+ in_vcon.verify(args.pubkey)
186
+
187
+ # Assuming that generally if someone is verifying the vCon, they want the
188
+ # unsigned JSON version as output.
189
+ signed_json = False
190
+
191
+ elif(args.command == "filter"):
192
+ plugin_name = args.filter_name[0][0].strip(" '\"")
193
+ print("filter name: \"{}\"".format(plugin_name), file=sys.stderr)
194
+ if(args.filter_options is not None):
195
+ try:
196
+ filter_options_dict = json.loads(args.filter_options[0][0].strip(" '\""))
197
+ except Exception as opt_error:
198
+ print(opt_error, file=sys.stderr)
199
+ print("filter options: {}".format(args.filter_options))
200
+ filter_options_dict = None
201
+ if(not isinstance(filter_options_dict, dict)):
202
+ print("filter_options should be a well formed dict. Got: {}".format(args.filter_options[0][0]), file=sys.stderr)
203
+ sys.exit(2)
204
+ else:
205
+ filter_options_dict = {}
206
+ print("filter options: \"{}\"".format(filter_options_dict), file=sys.stderr)
207
+ try:
208
+ plugin = vcon.filter_plugins.FilterPluginRegistry.get(plugin_name)
209
+ print("got plugin for: {}".format(plugin), file=sys.stderr)
210
+ except Exception as pname_error:
211
+ try:
212
+ default_type = vcon.filter_plugins.FilterPluginRegistry.get_type_default_name(plugin_name)
213
+ print("got default type {} plugin for: {}".format(default_type, plugin_name), file=sys.stderr)
214
+ except Exception as ptype_error:
215
+ raise Exception(
216
+ "{} is neither a registered filter plugin name or a default filter plugin type name".format(
217
+ plugin_name)) from pname_error
218
+
219
+ # send print statements that we want to go to stderr
220
+ #
221
+ # Leaving this here commented out for diagnostic purposes. I kind of
222
+ # like it that the unit test fails if there is any print to stdout
223
+ # noise to force clean up.
224
+ #with contextlib.redirect_stdout(sys.stderr):
225
+ in_vcon = in_vcon.filter(plugin_name, **filter_options_dict)
226
+
227
+ elif(args.command == "encrypt"):
228
+ print("state: {}".format(in_vcon._state), file=sys.stderr)
229
+ in_vcon.encrypt(args.pubkey[0])
230
+
231
+ elif(args.command == "decrypt"):
232
+ print("state: {}".format(in_vcon._state), file=sys.stderr)
233
+ in_vcon.decrypt(args.privkey[0], args.pubkey[0])
234
+
235
+ elif(args.command == "add"):
236
+ if(args.add_command in ["in-recording", "ex-recording"]):
237
+ if(not args.recfile[0].exists()):
238
+ raise Exception("Recording file: {} does not exist".format(args.recfile[0]))
239
+
240
+ sox_info = sox.file_info.info(str(args.recfile[0]))
241
+ duration = sox_info["duration"]
242
+ mimetype = get_mime_type(args.recfile[0])
243
+
244
+ with open(args.recfile[0], 'rb') as file_handle:
245
+ body = file_handle.read()
246
+
247
+ parties_object = json.loads(args.parties[0])
248
+
249
+ if(args.add_command == "in-recording"):
250
+ in_vcon.add_dialog_inline_recording(body, args.start[0], duration, parties_object,
251
+ mimetype, str(args.recfile[0]))
252
+
253
+ elif(args.add_command == "ex-recording"):
254
+ in_vcon.add_dialog_external_recording(body, args.start[0], duration, parties_object,
255
+ args.url[0], mimetype, str(args.recfile[0]))
256
+
257
+ elif(args.add_command == "in-email"):
258
+ if(not args.emailfile[0].exists()):
259
+ raise Exception("Email file: {} does not exist".format(args.emailfile[0]))
260
+
261
+ email_message = email.message_from_file(args.emailfile[0].open("r"))
262
+
263
+ # Set subject if its not already set
264
+ if(in_vcon.subject is None or len(in_vcon.subject) == 0):
265
+ subject = email_message.get("subject")
266
+ in_vcon.set_subject(subject)
267
+
268
+ # Get tuple(s) of (name, email_uri) for sender and recipients
269
+ sender = email.utils.parseaddr(email_message.get("from"))
270
+ recipients = email.utils.getaddresses(email_message.get_all("to", []) +
271
+ email_message.get_all("cc", []) +
272
+ email_message.get_all("recent-to", []) +
273
+ email_message.get_all("recent-cc", []))
274
+
275
+ party_indices = []
276
+ for email_address in [sender] + recipients:
277
+ print("email name: {} mailto: {}".format(email_address[0], email_address[1]), file=sys.stderr)
278
+ parties_found = in_vcon.find_parties_by_parameter("mailto", email_address[1])
279
+ if(len(parties_found) == 0):
280
+ parties_found = in_vcon.find_parties_by_parameter("name", email_address[0])
281
+
282
+ if(len(parties_found) == 0):
283
+ party_index = in_vcon.set_party_parameter("mailto", email_address[1])
284
+ in_vcon.set_party_parameter("name", email_address[0], party_index)
285
+ parties_found = [party_index]
286
+
287
+ party_indices.extend(parties_found)
288
+
289
+ if(len(parties_found) > 1):
290
+ print("Warning: multiple parties found matching {}: at indices: {}".format(email_address, parties_found), file=sys.stderr)
291
+
292
+ content_type = email_message.get("content-type")
293
+ file_name = email_message.get_filename()
294
+ #date = time.mktime(email.utils.parsedate(email_message.get("date")))
295
+ date = email.utils.parsedate_to_datetime(email_message.get("date"))
296
+
297
+ email_body = ""
298
+
299
+ if(email_message.is_multipart()):
300
+ body_start = False
301
+ for line in str(email_message).splitlines():
302
+ if(body_start):
303
+ email_body = email_body + line + "\n\r"
304
+
305
+ elif(len(line) == 0):
306
+ body_start = True
307
+
308
+ else:
309
+ email_body = email_message.get_payload()
310
+
311
+ in_vcon.add_dialog_inline_text(email_body, date, 0, party_indices, content_type, file_name)
312
+
313
+ elif(args.command == "extract"):
314
+ if(args.extract_command == "dialog"):
315
+ if(not isinstance(args.index[0], int)):
316
+ raise AttributeError("Dialog index should be type int, not {}".format(type(args.index[0])))
317
+
318
+ dialog_index = args.index[0]
319
+ num_dialogs = len(in_vcon.dialog)
320
+ if(dialog_index > num_dialogs):
321
+ raise AttributeError("Dialog index: {} must be less than the number of dialog in the vCon: {}".format(dialog_index, num_dialogs))
322
+
323
+ recording_bytes = in_vcon.decode_dialog_inline_body(dialog_index)
324
+ stdout_vcon = False
325
+ if(isinstance(recording_bytes, bytes)):
326
+ args.outfile.buffer.write(recording_bytes)
327
+ else:
328
+ args.outfile.write(recording_bytes)
329
+
330
+ #print("vcon._vcon_dict: {}".format(in_vcon._vcon_dict))
331
+ if(stdout_vcon):
332
+ if(in_vcon._state == vcon.VconStates.UNSIGNED and (in_vcon.uuid is None or len(in_vcon.uuid) < 1)):
333
+ in_vcon.set_uuid(socket.gethostname() + ".vcon.dev")
334
+ out_vcon_json = in_vcon.dumps(signed=signed_json)
335
+ args.outfile.write(out_vcon_json)
336
+
337
+ return(0)
@@ -0,0 +1,268 @@
1
+ """ Vcon module providing frameword for filter plugins which take a Von in and provide a Vcon output """
2
+ from __future__ import annotations
3
+ import importlib
4
+ import typing
5
+ import sys
6
+ import os
7
+ import traceback
8
+ import logging
9
+ import pythonjsonlogger.jsonlogger
10
+
11
+
12
+ # This package is dependent upon the vcon package only for typing purposes.
13
+ # This creates a circular dependency which we avoid by importing annotations
14
+ # above and importing vcon only if typing.TYPE_CHECKING
15
+ if typing.TYPE_CHECKING:
16
+ from vcon import Vcon
17
+
18
+ # This is cloned from vcon package as we cannot import vcon here due to
19
+ # cyclical import.
20
+ def build_logger(name : str) -> logging.Logger:
21
+ logger = logging.getLogger(name)
22
+
23
+ log_config_filename = "./logging.conf"
24
+ if(os.path.isfile(log_config_filename)):
25
+ logging.config.fileConfig(log_config_filename)
26
+ #print("got logging config", file=sys.stderr)
27
+ else:
28
+ logger.setLevel(logging.DEBUG)
29
+
30
+ # Output to stdout WILL BREAK the Vcon CLI.
31
+ # MUST use stderr.
32
+ handler = logging.StreamHandler(sys.stderr)
33
+ handler.setLevel(logging.DEBUG)
34
+ formatter = pythonjsonlogger.jsonlogger.JsonFormatter( "%(timestamp)s %(levelname)s %(message)s ", timestamp=True)
35
+ handler.setFormatter(formatter)
36
+ logger.addHandler(handler)
37
+
38
+ return(logger)
39
+ logger = build_logger(__name__)
40
+
41
+ class PluginModuleNotFound(Exception):
42
+ """ Thrown when plugin modeule fails to load """
43
+
44
+ class PluginClassNotFound(Exception):
45
+ """ Thrown when plugin class is not found in plugin module """
46
+
47
+ class PluginFilterNotImplemented(Exception):
48
+ """ Thrown when plugin modeule and class are found, but methods are not implemented on filter"""
49
+
50
+ class PluginFilterNotRegistered(Exception):
51
+ """ Thrown when plugin is not found in the FilterPluginRegistry """
52
+
53
+ class PluginFilterAlreadyRegistered(Exception):
54
+ """ Thrown when plugin already exists in the FilterPluginRegistry """
55
+
56
+ class FilterPlugin:
57
+ """ Abstract Vcon filter plugin class. Implementations derive from this clss and must implement the filter method """
58
+ def __init__(self, **options):
59
+ pass
60
+
61
+ def filter(self, in_vcon: Vcon, **options) -> Vcon:
62
+ """
63
+ Abstract method which performs an operation on an input Vcon and
64
+ provides the modified Vcon as output.
65
+
66
+ Parameters:
67
+ in_vcon (vcon.Vcon) - input Vcon upon which an operation is to be performed by the plugin.
68
+ options (kwargs) - opaque options to the filter method/opearation
69
+
70
+ Returns:
71
+ vcon.Vcon - the modified Vcon
72
+ """
73
+ raise PluginFilterNotImplemented("{}.filter not implemented".format(type(self)))
74
+
75
+ def __del__(self):
76
+ """ Teardown/uninitialization method for the plugin """
77
+ print("deleting {}".format(self.__class__))
78
+
79
+ class FilterPluginRegistration:
80
+ """ Class containing info and heloer methods on the registration for a single named plugin filter """
81
+ def __init__(self, name: str, module_name: str, class_name: str, description: str):
82
+ self.name = name
83
+ self._module_name = module_name
84
+ self._module_load_attempted = False
85
+ self._module_not_found = False
86
+ self._class_not_found = False
87
+ self._class_name = class_name
88
+ self.description = description
89
+ self._plugin : typing.Union[FilterPlugin, None] = None
90
+
91
+ def import_plugin(self, **options) -> bool:
92
+ """
93
+ Import the package which contains the implementation for the filter
94
+ plugin and instantiate the plugin class.
95
+
96
+ filter plugins are registered and later if used, they are imported.
97
+ When registered, a filter plugin has a name, an implementation module,
98
+ and a class which gets instantiated upon import of the package.
99
+
100
+ Parameters:
101
+ options (kwargs) - options input to the plugin class constructor
102
+
103
+ Returns:
104
+ True/False if the plugin module imported successfully and the
105
+ class was instantiated.
106
+ """
107
+ succeed = False
108
+ if(not self._module_load_attempted):
109
+ try:
110
+ logger.info("importing: {} for registered filter plugin: {}".format(self._module_name, self.name))
111
+ module = importlib.import_module(self._module_name)
112
+ self._module_load_attempted = True
113
+ self._module_not_found = False
114
+
115
+ try:
116
+ class_ = getattr(module, self._class_name)
117
+ self._plugin = class_(**options)
118
+ self._class_not_found = False
119
+ succeed = True
120
+
121
+ except AttributeError as ae:
122
+ logger.warning(ae)
123
+ self._class_not_found = True
124
+
125
+ except ModuleNotFoundError as mod_error:
126
+ logger.warning(mod_error)
127
+ logger.warning(traceback.format_exc(limit=-1))
128
+ self._module_not_found = True
129
+
130
+ elif(self._plugin is not None):
131
+ succeed = True
132
+
133
+ return(succeed)
134
+
135
+ def plugin(self, **options) -> typing.Union[FilterPlugin, None]:
136
+ """ Return the plugin filter class for this registration """
137
+ if(not self._module_load_attempted):
138
+ self.import_plugin(**options)
139
+
140
+ return(self._plugin)
141
+
142
+ def filter(self, in_vcon : vcon.Vcon, **options) -> vcon.Vcon:
143
+ if(not self._module_load_attempted):
144
+ self.import_plugin(**options)
145
+
146
+ if(self._module_not_found is True):
147
+ message = "plugin: {} not loaded as module: {} was not found".format(self.name, self._module_name)
148
+ raise PluginModuleNotFound(message)
149
+
150
+ if(self._class_not_found is True):
151
+ message = "plugin: {} not loaded as class: {} not found in module: {}".format(self.name, self._class_name, self._module_name)
152
+ raise PluginClassNotFound(message)
153
+
154
+ plugin = self.plugin(**options)
155
+ if(plugin is None):
156
+ raise Exception("plugin: {} from class: {} module: {} load failed".format(self.name, self._class_name, self._module_name))
157
+
158
+ return(plugin.filter(in_vcon, **options))
159
+
160
+ class FilterPluginRegistry:
161
+ """ class/scope for Vcon filter plugin registrations and defaults for plugin types """
162
+ _registry: typing.Dict[str, FilterPluginRegistration] = {}
163
+ _defaults: typing.Dict[str, str] = {}
164
+
165
+ @staticmethod
166
+ def __add_plugin(plugin: FilterPluginRegistration, replace=False):
167
+
168
+ name_registered = FilterPluginRegistry._registry.get(plugin.name)
169
+ if(name_registered is None):
170
+ # TODO: fix circular import dependency problem
171
+ #import vcon
172
+ #if(vcon.Vcon.attribute_exists(plugin.name)):
173
+ # raise AttributeError("{} is a reserved name already used as a Vcon class or instance name".format(plugin.name))
174
+ pass
175
+
176
+ if(name_registered is None or replace):
177
+
178
+ FilterPluginRegistry._registry[plugin.name] = plugin
179
+ else:
180
+ raise PluginFilterAlreadyRegistered("Plugin {} already registered".format(plugin.name))
181
+
182
+
183
+ @staticmethod
184
+ def register(name: str, module_name: str, class_name: str, description: str, replace: bool = False) -> None:
185
+ """
186
+ Register a named filter plugin.
187
+
188
+ Parameters:
189
+ name (str) - the name to register the plugin
190
+
191
+ module_name (str) - the module name to import where the plugin class is implmented
192
+
193
+ class_name (str) - the class name for the plugin implementation in the named module
194
+
195
+ description (str) - a text description of what the plugin does
196
+
197
+ replace (bool) - if True replace the already registered plugin of the same name
198
+ if False throw an exception if a plugin of the same name is already register
199
+ """
200
+ logger.info("Registering FilterPlugin: {}".format(locals()))
201
+ entry = FilterPluginRegistration(name, module_name, class_name, description)
202
+ FilterPluginRegistry.__add_plugin(entry, replace)
203
+
204
+
205
+ @staticmethod
206
+ def get(name: str) -> FilterPluginRegistration:
207
+ """
208
+ Returns registration for named plugin
209
+ """
210
+ plugin_reg = FilterPluginRegistry._registry.get(name, None)
211
+ if(plugin_reg is None):
212
+ raise PluginFilterNotRegistered("Filter plugin {} is not registered".format(name))
213
+
214
+ return(plugin_reg)
215
+
216
+ @staticmethod
217
+ def get_names() -> typing.List[str]:
218
+ """
219
+ Returns list of plugin names
220
+ """
221
+ return(FilterPluginRegistry._registry.keys())
222
+
223
+ @staticmethod
224
+ def set_type_default_name(plugin_type: str, name: str) -> None:
225
+ """ Set the default filter name for the given filter type """
226
+ FilterPluginRegistry._defaults[plugin_type] = name
227
+
228
+ @staticmethod
229
+ def get_type_default_name(plugin_type: str) -> typing.Union[str, None]:
230
+ """ Get the default plugin name for the given filter type """
231
+ return(FilterPluginRegistry._defaults.get(plugin_type, None))
232
+
233
+ @staticmethod
234
+ def get_types() -> typing.List[str]:
235
+ """
236
+ Get the set of FilterPlugin types.
237
+
238
+ Returns:
239
+ list(str) - names of all the types for which a default is set.
240
+ """
241
+ return(FilterPluginRegistry._defaults.keys())
242
+
243
+ @staticmethod
244
+ def get_type_default_plugin(plugin_type: str) -> typing.Union[FilterPluginRegistration, None]:
245
+ """ Get the default FilterPlauginRegistration for the named filter type """
246
+ if(not isinstance(plugin_type, str)):
247
+ raise AttributeError("plugin_type argument should be a string, not {}".format(type(plugin_type)))
248
+
249
+ name = FilterPluginRegistry.get_type_default_name(plugin_type)
250
+ if(name is None):
251
+ raise PluginFilterNotRegistered("Filter plugin default type name {} is not set".format(plugin_type))
252
+ return(FilterPluginRegistry.get(name))
253
+
254
+ class TranscriptionFilter(FilterPlugin):
255
+ # TODO abstraction of transcription filters, iterates through dialogs
256
+ def __init__(self, **options):
257
+ super().__init__(**options)
258
+
259
+ def iterateDialogs(self, in_vcon: Vcon, scope: str ="new"):
260
+ """
261
+ Iterate through the dialogs in the given vCon
262
+
263
+ Parameters:
264
+ scope = "all", "new"
265
+ "new" = dialogs containing a recording for which there is no transcript
266
+ "all" = all dialogs which contain a recording
267
+ """
268
+