plover 5.0.0.dev2__py3-none-any.whl → 5.0.0rc1__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.
Files changed (145) hide show
  1. plover/__init__.py +8 -7
  2. plover/__main__.py +1 -1
  3. plover/command/set_config.py +7 -4
  4. plover/config.py +177 -74
  5. plover/dictionary/base.py +21 -9
  6. plover/dictionary/helpers.py +6 -4
  7. plover/dictionary/json_dict.py +10 -12
  8. plover/dictionary/loading_manager.py +8 -10
  9. plover/dictionary/rtfcre_dict.py +46 -43
  10. plover/dictionary/rtfcre_parse.py +116 -100
  11. plover/engine.py +112 -96
  12. plover/exception.py +4 -1
  13. plover/formatting.py +198 -140
  14. plover/gui_none/add_translation.py +17 -16
  15. plover/gui_none/engine.py +1 -3
  16. plover/gui_none/main.py +2 -2
  17. plover/gui_qt/about_dialog.py +17 -17
  18. plover/gui_qt/about_dialog_ui.py +1 -1
  19. plover/gui_qt/add_translation_dialog.py +8 -9
  20. plover/gui_qt/add_translation_dialog_ui.py +1 -1
  21. plover/gui_qt/add_translation_widget.py +66 -63
  22. plover/gui_qt/add_translation_widget_ui.py +1 -1
  23. plover/gui_qt/config_file_widget_ui.py +1 -1
  24. plover/gui_qt/config_keyboard_widget_ui.py +1 -1
  25. plover/gui_qt/config_serial_widget_ui.py +1 -1
  26. plover/gui_qt/config_window.py +274 -154
  27. plover/gui_qt/config_window_ui.py +1 -1
  28. plover/gui_qt/console_widget.py +9 -13
  29. plover/gui_qt/console_widget_ui.py +1 -1
  30. plover/gui_qt/dictionaries_widget.py +140 -119
  31. plover/gui_qt/dictionaries_widget_ui.py +1 -1
  32. plover/gui_qt/dictionary_editor.py +60 -61
  33. plover/gui_qt/dictionary_editor_ui.py +1 -1
  34. plover/gui_qt/engine.py +3 -3
  35. plover/gui_qt/info_browser.py +50 -4
  36. plover/gui_qt/log_qt.py +3 -2
  37. plover/gui_qt/lookup_dialog.py +9 -9
  38. plover/gui_qt/lookup_dialog_ui.py +1 -1
  39. plover/gui_qt/machine_options.py +38 -37
  40. plover/gui_qt/main.py +19 -19
  41. plover/gui_qt/main_window.py +88 -71
  42. plover/gui_qt/main_window_ui.py +1 -1
  43. plover/gui_qt/paper_tape.py +69 -52
  44. plover/gui_qt/paper_tape_ui.py +1 -4
  45. plover/gui_qt/plugins_manager.py +47 -43
  46. plover/gui_qt/plugins_manager_ui.py +1 -1
  47. plover/gui_qt/resources_rc.py +29 -29
  48. plover/gui_qt/run_dialog.py +7 -6
  49. plover/gui_qt/run_dialog_ui.py +1 -1
  50. plover/gui_qt/steno_validator.py +2 -3
  51. plover/gui_qt/suggestions_dialog.py +34 -38
  52. plover/gui_qt/suggestions_dialog_ui.py +1 -1
  53. plover/gui_qt/suggestions_widget.py +22 -16
  54. plover/gui_qt/tool.py +1 -3
  55. plover/gui_qt/trayicon.py +19 -19
  56. plover/gui_qt/utils.py +19 -9
  57. plover/i18n.py +9 -8
  58. plover/key_combo.py +130 -130
  59. plover/log.py +26 -26
  60. plover/machine/base.py +40 -35
  61. plover/machine/geminipr.py +7 -7
  62. plover/machine/keyboard.py +16 -14
  63. plover/machine/keyboard_capture/__init__.py +0 -1
  64. plover/machine/keymap.py +24 -20
  65. plover/machine/passport.py +6 -5
  66. plover/machine/procat.py +12 -16
  67. plover/machine/stentura.py +45 -29
  68. plover/machine/txbolt.py +5 -3
  69. plover/macro/repeat.py +0 -1
  70. plover/macro/retro.py +9 -9
  71. plover/macro/undo.py +4 -3
  72. plover/meta/attach.py +12 -10
  73. plover/meta/case.py +2 -1
  74. plover/meta/conditional.py +3 -3
  75. plover/meta/currency.py +4 -4
  76. plover/meta/mode.py +15 -15
  77. plover/meta/punctuation.py +1 -0
  78. plover/misc.py +21 -17
  79. plover/orthography.py +12 -10
  80. plover/oslayer/__init__.py +7 -5
  81. plover/oslayer/config.py +16 -15
  82. plover/oslayer/controller.py +13 -13
  83. plover/oslayer/linux/i18n.py +2 -1
  84. plover/oslayer/linux/keyboardcontrol.py +2 -2
  85. plover/oslayer/linux/keyboardcontrol_uinput.py +182 -37
  86. plover/oslayer/linux/keyboardcontrol_x11.py +860 -851
  87. plover/oslayer/linux/log.py +1 -1
  88. plover/oslayer/linux/log_dbus.py +97 -65
  89. plover/oslayer/linux/serial.py +2 -2
  90. plover/oslayer/linux/wmctrl_x11.py +11 -15
  91. plover/oslayer/osx/keyboardcontrol.py +194 -99
  92. plover/oslayer/osx/keyboardlayout.py +138 -119
  93. plover/oslayer/osx/log.py +14 -8
  94. plover/oslayer/osx/serial.py +1 -1
  95. plover/oslayer/osx/wmctrl.py +6 -1
  96. plover/oslayer/windows/keyboardcontrol.py +195 -89
  97. plover/oslayer/windows/keyboardlayout.py +367 -334
  98. plover/oslayer/windows/log.py +5 -3
  99. plover/oslayer/windows/serial.py +4 -5
  100. plover/oslayer/windows/wmctrl.py +1 -1
  101. plover/output/__init__.py +1 -2
  102. plover/output/keyboard.py +15 -15
  103. plover/plugins_manager/__main__.py +42 -39
  104. plover/plugins_manager/global_registry.py +2 -5
  105. plover/plugins_manager/local_registry.py +11 -13
  106. plover/plugins_manager/package_index.py +12 -18
  107. plover/plugins_manager/pip_wrapper.py +5 -5
  108. plover/plugins_manager/plugin_metadata.py +17 -9
  109. plover/plugins_manager/registry.py +39 -28
  110. plover/plugins_manager/requests.py +2 -4
  111. plover/plugins_manager/utils.py +9 -7
  112. plover/registry.py +28 -26
  113. plover/resource.py +13 -10
  114. plover/scripts/dist_main.py +7 -7
  115. plover/scripts/main.py +57 -34
  116. plover/scripts/send_command.py +13 -7
  117. plover/steno.py +16 -9
  118. plover/steno_dictionary.py +47 -21
  119. plover/suggestions.py +11 -11
  120. plover/system/__init__.py +39 -23
  121. plover/system/english_stenotype.py +231 -229
  122. plover/translation.py +67 -51
  123. {plover-5.0.0.dev2.dist-info → plover-5.0.0rc1.dist-info}/METADATA +1 -1
  124. plover-5.0.0rc1.dist-info/RECORD +216 -0
  125. plover_build_utils/check_requirements.py +5 -6
  126. plover_build_utils/download.py +10 -8
  127. plover_build_utils/get_pip.py +10 -5
  128. plover_build_utils/install_wheels.py +33 -31
  129. plover_build_utils/pyqt.py +24 -22
  130. plover_build_utils/setup.py +64 -54
  131. plover_build_utils/source_less.py +6 -6
  132. plover_build_utils/testing/blackbox.py +31 -31
  133. plover_build_utils/testing/dict.py +3 -3
  134. plover_build_utils/testing/output.py +5 -6
  135. plover_build_utils/testing/parametrize.py +5 -3
  136. plover_build_utils/testing/steno_dictionary.py +145 -124
  137. plover_build_utils/tree.py +21 -19
  138. plover_build_utils/trim.py +5 -5
  139. plover_build_utils/zipdir.py +3 -3
  140. plover-5.0.0.dev2.dist-info/RECORD +0 -216
  141. {plover-5.0.0.dev2.dist-info → plover-5.0.0rc1.dist-info}/WHEEL +0 -0
  142. {plover-5.0.0.dev2.dist-info → plover-5.0.0rc1.dist-info}/entry_points.txt +0 -0
  143. {plover-5.0.0.dev2.dist-info → plover-5.0.0rc1.dist-info}/licenses/LICENSE.txt +0 -0
  144. {plover-5.0.0.dev2.dist-info → plover-5.0.0rc1.dist-info}/top_level.txt +0 -0
  145. {plover-5.0.0.dev2.dist-info → plover-5.0.0rc1.dist-info}/zip-safe +0 -0
plover/__init__.py CHANGED
@@ -3,8 +3,9 @@
3
3
 
4
4
  """Plover: Open Source Stenography Software"""
5
5
 
6
- if __name__ == 'plover':
6
+ if __name__ == "plover":
7
7
  from plover.i18n import Translator
8
+
8
9
  _ = Translator(__package__)
9
10
  else:
10
11
  # exec from `setup.py`, package data
@@ -12,10 +13,10 @@ else:
12
13
  # want to translate anyway.
13
14
  _ = lambda s: s
14
15
 
15
- __version__ = '5.0.0.dev2'
16
- __copyright__ = '(C) Open Steno Project'
17
- __url__ = 'http://www.openstenoproject.org/'
18
- __download_url__ = 'http://www.openstenoproject.org/plover'
16
+ __version__ = "5.0.0rc1"
17
+ __copyright__ = "(C) Open Steno Project"
18
+ __url__ = "http://www.openstenoproject.org/"
19
+ __download_url__ = "http://www.openstenoproject.org/plover"
19
20
  __credits__ = _("""\
20
21
  Founded by stenographer Mirabai Knight.
21
22
 
@@ -30,9 +31,9 @@ Martin Koerner
30
31
 
31
32
  and many more on GitHub:
32
33
  <https://github.com/openstenoproject/plover>""")
33
- __license__ = 'GNU General Public License v2 or later (GPLv2+)'
34
+ __license__ = "GNU General Public License v2 or later (GPLv2+)"
34
35
  # i18n: Short description for Plover, currently not used in the interface.
35
- __description__ = _('Open Source Stenography Software')
36
+ __description__ = _("Open Source Stenography Software")
36
37
  __long_description__ = _("""\
37
38
  Plover is a free open source program intended to bring realtime
38
39
  stenographic technology not just to stenographers, but also to
plover/__main__.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from plover.scripts.main import main
2
2
 
3
3
 
4
- if __name__ == '__main__':
4
+ if __name__ == "__main__":
5
5
  main()
@@ -22,11 +22,14 @@ def set_config(engine, cmdline):
22
22
 
23
23
 
24
24
  def _cmdline_to_dict(cmdline):
25
- """ Add braces and parse the entire command line as a Python dict literal. """
25
+ """Add braces and parse the entire command line as a Python dict literal."""
26
26
  try:
27
- opt_dict = ast.literal_eval('{'+cmdline+'}')
27
+ opt_dict = ast.literal_eval("{" + cmdline + "}")
28
28
  assert isinstance(opt_dict, dict)
29
29
  return opt_dict
30
30
  except (AssertionError, SyntaxError, ValueError) as e:
31
- raise ValueError('Bad command string "%s" for PLOVER:SET_CONFIG.\n' % cmdline
32
- + 'See for reference:\n\n' + set_config.__doc__) from e
31
+ raise ValueError(
32
+ 'Bad command string "%s" for PLOVER:SET_CONFIG.\n' % cmdline
33
+ + "See for reference:\n\n"
34
+ + set_config.__doc__
35
+ ) from e
plover/config.py CHANGED
@@ -17,26 +17,25 @@ from plover import log
17
17
 
18
18
 
19
19
  # General configuration sections, options and defaults.
20
- MACHINE_CONFIG_SECTION = 'Machine Configuration'
20
+ MACHINE_CONFIG_SECTION = "Machine Configuration"
21
21
 
22
- LEGACY_DICTIONARY_CONFIG_SECTION = 'Dictionary Configuration'
22
+ LEGACY_DICTIONARY_CONFIG_SECTION = "Dictionary Configuration"
23
23
 
24
- LOGGING_CONFIG_SECTION = 'Logging Configuration'
24
+ LOGGING_CONFIG_SECTION = "Logging Configuration"
25
25
 
26
- OUTPUT_CONFIG_SECTION = 'Output Configuration'
26
+ OUTPUT_CONFIG_SECTION = "Output Configuration"
27
27
  DEFAULT_UNDO_LEVELS = 100
28
28
  MINIMUM_UNDO_LEVELS = 1
29
29
  DEFAULT_TIME_BETWEEN_KEY_PRESSES = 0
30
30
  MINIMUM_TIME_BETWEEN_KEY_PRESSES = 0
31
31
 
32
- DEFAULT_SYSTEM_NAME = 'English Stenotype'
32
+ DEFAULT_SYSTEM_NAME = "English Stenotype"
33
33
 
34
- SYSTEM_CONFIG_SECTION = 'System: %s'
35
- SYSTEM_KEYMAP_OPTION = 'keymap[%s]'
34
+ SYSTEM_CONFIG_SECTION = "System: %s"
35
+ SYSTEM_KEYMAP_OPTION = "keymap[%s]"
36
36
 
37
37
 
38
- class DictionaryConfig(namedtuple('DictionaryConfig', 'path enabled')):
39
-
38
+ class DictionaryConfig(namedtuple("DictionaryConfig", "path enabled")):
40
39
  def __new__(cls, path, enabled=True):
41
40
  return super().__new__(cls, expand_path(path), enabled)
42
41
 
@@ -48,8 +47,8 @@ class DictionaryConfig(namedtuple('DictionaryConfig', 'path enabled')):
48
47
  # Note: do not use _asdict because of
49
48
  # https://bugs.python.org/issue24931
50
49
  return {
51
- 'path': self.short_path,
52
- 'enabled': self.enabled,
50
+ "path": self.short_path,
51
+ "enabled": self.enabled,
53
52
  }
54
53
 
55
54
  def replace(self, **kwargs):
@@ -60,17 +59,20 @@ class DictionaryConfig(namedtuple('DictionaryConfig', 'path enabled')):
60
59
  return DictionaryConfig(**d)
61
60
 
62
61
  def __repr__(self):
63
- return 'DictionaryConfig(%r, %r)' % (self.short_path, self.enabled)
62
+ return "DictionaryConfig(%r, %r)" % (self.short_path, self.enabled)
64
63
 
65
64
 
66
- ConfigOption = namedtuple('ConfigOption', '''
65
+ ConfigOption = namedtuple(
66
+ "ConfigOption",
67
+ """
67
68
  name default
68
69
  getter setter
69
70
  validate full_key
70
- ''')
71
+ """,
72
+ )
71
73
 
72
- class InvalidConfigOption(ValueError):
73
74
 
75
+ class InvalidConfigOption(ValueError):
74
76
  def __init__(self, raw_value, fixed_value, message=None):
75
77
  super().__init__(raw_value)
76
78
  self.raw_value = raw_value
@@ -83,118 +85,161 @@ class InvalidConfigOption(ValueError):
83
85
 
84
86
  def raw_option(name, default, section, option, validate):
85
87
  option = option or name
88
+
86
89
  def getter(config, key):
87
90
  return config._config[section][option]
91
+
88
92
  def setter(config, key, value):
89
93
  config._set(section, option, value)
94
+
90
95
  return ConfigOption(name, lambda c, k: default, getter, setter, validate, None)
91
96
 
97
+
92
98
  def json_option(name, default, section, option, validate):
93
99
  option = option or name
100
+
94
101
  def getter(config, key):
95
102
  value = config._config[section][option]
96
103
  try:
97
104
  return json.loads(value)
98
105
  except json.JSONDecodeError as e:
99
106
  raise InvalidConfigOption(value, default) from e
107
+
100
108
  def setter(config, key, value):
101
109
  if isinstance(value, set):
102
110
  # JSON does not support sets.
103
111
  value = list(sorted(value))
104
- config._set(section, option, json.dumps(value, sort_keys=True, ensure_ascii=False))
112
+ config._set(
113
+ section, option, json.dumps(value, sort_keys=True, ensure_ascii=False)
114
+ )
115
+
105
116
  return ConfigOption(name, default, getter, setter, validate, None)
106
117
 
118
+
107
119
  def int_option(name, default, minimum, maximum, section, option=None):
108
120
  option = option or name
121
+
109
122
  def getter(config, key):
110
123
  return config._config[section][option]
124
+
111
125
  def setter(config, key, value):
112
126
  config._set(section, option, str(value))
127
+
113
128
  def validate(config, key, value):
114
129
  try:
115
130
  value = int(value)
116
131
  except ValueError as e:
117
132
  raise InvalidConfigOption(value, default) from e
118
- if (minimum is not None and value < minimum) or \
119
- (maximum is not None and value > maximum):
120
- message = '%s not in [%s, %s]' % (value, minimum or '-∞', maximum or '∞')
133
+ if (minimum is not None and value < minimum) or (
134
+ maximum is not None and value > maximum
135
+ ):
136
+ message = "%s not in [%s, %s]" % (value, minimum or "-∞", maximum or "∞")
121
137
  raise InvalidConfigOption(value, default, message)
122
138
  return value
139
+
123
140
  return ConfigOption(name, lambda c, k: default, getter, setter, validate, None)
124
141
 
142
+
125
143
  def boolean_option(name, default, section, option=None):
126
144
  option = option or name
145
+
127
146
  def getter(config, key):
128
147
  return config._config[section][option]
148
+
129
149
  def setter(config, key, value):
130
150
  config._set(section, option, str(value))
151
+
131
152
  def validate(config, key, value):
132
153
  try:
133
154
  return boolean(value)
134
155
  except ValueError as e:
135
156
  raise InvalidConfigOption(value, default) from e
157
+
136
158
  return ConfigOption(name, lambda c, k: default, getter, setter, validate, None)
137
159
 
160
+
138
161
  def choice_option(name, choices, section, option=None):
139
162
  default = choices[0]
163
+
140
164
  def validate(config, key, value):
141
165
  if value not in choices:
142
166
  raise InvalidConfigOption(value, default)
143
167
  return value
168
+
144
169
  return raw_option(name, default, section, option, validate)
145
170
 
171
+
146
172
  def plugin_option(name, plugin_type, default, section, option=None):
147
173
  def validate(config, key, value):
148
174
  try:
149
175
  return registry.get_plugin(plugin_type, value).name
150
176
  except KeyError as e:
151
177
  raise InvalidConfigOption(value, default) from e
178
+
152
179
  return raw_option(name, default, section, option, validate)
153
180
 
181
+
154
182
  def opacity_option(name, section, option=None):
155
183
  return int_option(name, 100, 0, 100, section, option)
156
184
 
185
+
157
186
  def path_option(name, default, section, option=None):
158
187
  option = option or name
188
+
159
189
  def getter(config, key):
160
190
  return expand_path(config._config[section][option])
191
+
161
192
  def setter(config, key, value):
162
193
  config._set(section, option, shorten_path(value))
194
+
163
195
  def validate(config, key, value):
164
196
  if not isinstance(value, str):
165
197
  raise InvalidConfigOption(value, default)
166
198
  return value
199
+
167
200
  return ConfigOption(name, lambda c, k: default, getter, setter, validate, None)
168
201
 
202
+
169
203
  def enabled_extensions_option():
170
204
  def validate(config, key, value):
171
205
  if not isinstance(value, (list, set, tuple)):
172
206
  raise InvalidConfigOption(value, ())
173
207
  return set(value)
174
- return json_option('enabled_extensions', lambda c, k: set(), 'Plugins', 'enabled_extensions', validate)
208
+
209
+ return json_option(
210
+ "enabled_extensions",
211
+ lambda c, k: set(),
212
+ "Plugins",
213
+ "enabled_extensions",
214
+ validate,
215
+ )
216
+
175
217
 
176
218
  def machine_specific_options():
177
219
  def full_key(config, key):
178
220
  if isinstance(key, tuple):
179
221
  assert len(key) == 2
180
222
  return key
181
- return (key, config['machine_type'])
223
+ return (key, config["machine_type"])
224
+
182
225
  def default(config, key):
183
- machine_class = registry.get_plugin('machine', key[1]).obj
226
+ machine_class = registry.get_plugin("machine", key[1]).obj
184
227
  return {
185
- name: params[0]
186
- for name, params in machine_class.get_option_info().items()
228
+ name: params[0] for name, params in machine_class.get_option_info().items()
187
229
  }
230
+
188
231
  def getter(config, key):
189
232
  return config._config[key[1]]
233
+
190
234
  def setter(config, key, value):
191
235
  config._config[key[1]] = value
236
+
192
237
  def validate(config, key, raw_options):
193
238
  if not isinstance(raw_options, (dict, configparser.SectionProxy)):
194
239
  raise InvalidConfigOption(raw_options, default(config, key))
195
240
  machine_options = OrderedDict()
196
241
  invalid_options = OrderedDict()
197
- machine_class = registry.get_plugin('machine', key[1]).obj
242
+ machine_class = registry.get_plugin("machine", key[1]).obj
198
243
  for name, params in sorted(machine_class.get_option_info().items()):
199
244
  fallback, convert = params
200
245
  try:
@@ -211,78 +256,102 @@ def machine_specific_options():
211
256
  if invalid_options:
212
257
  raise InvalidConfigOption(invalid_options, machine_options)
213
258
  return machine_options
214
- return ConfigOption('machine_specific_options', default, getter, setter, validate, full_key)
259
+
260
+ return ConfigOption(
261
+ "machine_specific_options", default, getter, setter, validate, full_key
262
+ )
263
+
215
264
 
216
265
  def system_keymap_option():
217
266
  def full_key(config, key):
218
267
  if isinstance(key, tuple):
219
268
  assert len(key) == 3
220
269
  return key
221
- return (key, config['system_name'], config['machine_type'])
270
+ return (key, config["system_name"], config["machine_type"])
271
+
222
272
  def location(config, key):
223
273
  return SYSTEM_CONFIG_SECTION % key[1], SYSTEM_KEYMAP_OPTION % key[2]
274
+
224
275
  def build_keymap(config, key, mappings=None):
225
- system = registry.get_plugin('system', key[1]).obj
226
- machine_class = registry.get_plugin('machine', key[2]).obj
227
- keymap = Keymap(machine_class.get_keys(), system.KEYS + machine_class.get_actions())
276
+ system = registry.get_plugin("system", key[1]).obj
277
+ machine_class = registry.get_plugin("machine", key[2]).obj
278
+ keymap = Keymap(
279
+ machine_class.get_keys(), system.KEYS + machine_class.get_actions()
280
+ )
228
281
  if mappings is None:
229
282
  mappings = system.KEYMAPS.get(key[2])
230
283
  if mappings is None:
231
284
  if machine_class.KEYMAP_MACHINE_TYPE is not None:
232
285
  # Try fallback.
233
- return build_keymap(config, (key[0], key[1], machine_class.KEYMAP_MACHINE_TYPE))
286
+ return build_keymap(
287
+ config, (key[0], key[1], machine_class.KEYMAP_MACHINE_TYPE)
288
+ )
234
289
  # No fallback...
235
290
  mappings = {}
236
291
  keymap.set_mappings(mappings)
237
292
  return keymap
293
+
238
294
  def default(config, key):
239
295
  return build_keymap(config, key)
296
+
240
297
  def getter(config, key):
241
298
  section, option = location(config, key)
242
299
  return config._config[section][option]
300
+
243
301
  def setter(config, key, keymap):
244
302
  section, option = location(config, key)
245
303
  config._set(section, option, str(keymap))
304
+
246
305
  def validate(config, key, value):
247
306
  try:
248
307
  return build_keymap(config, key, value)
249
308
  except (TypeError, ValueError) as e:
250
309
  raise InvalidConfigOption(value, default(config, key)) from e
251
- return ConfigOption('system_keymap', default, getter, setter, validate, full_key)
310
+
311
+ return ConfigOption("system_keymap", default, getter, setter, validate, full_key)
312
+
252
313
 
253
314
  def dictionaries_option():
254
315
  def full_key(config, key):
255
316
  if isinstance(key, tuple):
256
317
  assert len(key) == 2
257
318
  return key
258
- return (key, config['system_name'])
319
+ return (key, config["system_name"])
320
+
259
321
  def location(config, key):
260
322
  return (
261
323
  SYSTEM_CONFIG_SECTION % key[1],
262
- 'dictionaries',
324
+ "dictionaries",
263
325
  )
326
+
264
327
  def default(config, key):
265
- system = registry.get_plugin('system', key[1]).obj
328
+ system = registry.get_plugin("system", key[1]).obj
266
329
  return [DictionaryConfig(path) for path in system.DEFAULT_DICTIONARIES]
330
+
267
331
  def legacy_getter(config):
268
332
  options = config._config[LEGACY_DICTIONARY_CONFIG_SECTION].items()
269
333
  return [
270
- {'path': value}
334
+ {"path": value}
271
335
  for name, value in reversed(sorted(options))
272
- if re.match(r'dictionary_file\d*$', name) is not None
336
+ if re.match(r"dictionary_file\d*$", name) is not None
273
337
  ]
338
+
274
339
  def getter(config, key):
275
340
  section, option = location(config, key)
276
341
  value = config._config.get(section, option, fallback=None)
277
342
  if value is None:
278
343
  return legacy_getter(config)
279
344
  return json.loads(value)
345
+
280
346
  def setter(config, key, dictionaries):
281
347
  section, option = location(config, key)
282
- config._set(section, option, json.dumps([
283
- d.to_dict() for d in dictionaries
284
- ], sort_keys=True))
348
+ config._set(
349
+ section,
350
+ option,
351
+ json.dumps([d.to_dict() for d in dictionaries], sort_keys=True),
352
+ )
285
353
  config._config.remove_section(LEGACY_DICTIONARY_CONFIG_SECTION)
354
+
286
355
  def validate(config, key, value):
287
356
  dictionaries = []
288
357
  for d in value:
@@ -294,11 +363,11 @@ def dictionaries_option():
294
363
  d = DictionaryConfig.from_dict(d)
295
364
  dictionaries.append(d)
296
365
  return dictionaries
297
- return ConfigOption('dictionaries', default, getter, setter, validate, full_key)
298
366
 
367
+ return ConfigOption("dictionaries", default, getter, setter, validate, full_key)
299
368
 
300
- class Config:
301
369
 
370
+ class Config:
302
371
  def __init__(self, path=None):
303
372
  self._config = None
304
373
  self._cache = {}
@@ -308,7 +377,7 @@ class Config:
308
377
 
309
378
  def load(self):
310
379
  self.clear()
311
- with open(self.path, encoding='utf-8') as fp:
380
+ with open(self.path, encoding="utf-8") as fp:
312
381
  try:
313
382
  self._config.read_file(fp)
314
383
  except configparser.Error as e:
@@ -320,7 +389,7 @@ class Config:
320
389
 
321
390
  def save(self):
322
391
  with resource_update(self.path) as temp_path:
323
- with open(temp_path, mode='w', encoding='utf-8') as fp:
392
+ with open(temp_path, mode="w", encoding="utf-8") as fp:
324
393
  self._config.write(fp)
325
394
 
326
395
  def _set(self, section, option, value):
@@ -331,35 +400,69 @@ class Config:
331
400
  # Note: order matters, e.g. machine_type comes before
332
401
  # machine_specific_options and system_keymap because
333
402
  # the latter depend on the former.
334
- _OPTIONS = OrderedDict((opt.name, opt) for opt in [
335
- # Output.
336
- choice_option('space_placement', ('Before Output', 'After Output'), OUTPUT_CONFIG_SECTION),
337
- boolean_option('start_attached', False, OUTPUT_CONFIG_SECTION),
338
- boolean_option('start_capitalized', False, OUTPUT_CONFIG_SECTION),
339
- int_option('undo_levels', DEFAULT_UNDO_LEVELS, MINIMUM_UNDO_LEVELS, None, OUTPUT_CONFIG_SECTION),
340
- int_option('time_between_key_presses', DEFAULT_TIME_BETWEEN_KEY_PRESSES, MINIMUM_TIME_BETWEEN_KEY_PRESSES, None, OUTPUT_CONFIG_SECTION),
341
- choice_option("keyboard_layout", ("qwerty", "qwertz", "colemak", "colemak-dh"), OUTPUT_CONFIG_SECTION),
342
- # Logging.
343
- path_option('log_file_name', expand_path('strokes.log'), LOGGING_CONFIG_SECTION, 'log_file'),
344
- boolean_option('enable_stroke_logging', False, LOGGING_CONFIG_SECTION),
345
- boolean_option('enable_translation_logging', False, LOGGING_CONFIG_SECTION),
346
- # GUI.
347
- boolean_option('start_minimized', False, 'Startup', 'Start Minimized'),
348
- boolean_option('show_stroke_display', False, 'Stroke Display', 'show'),
349
- boolean_option('show_suggestions_display', False, 'Suggestions Display', 'show'),
350
- opacity_option('translation_frame_opacity', 'Translation Frame', 'opacity'),
351
- boolean_option('classic_dictionaries_display_order', False, 'GUI'),
352
- # Plugins.
353
- enabled_extensions_option(),
354
- # Machine.
355
- boolean_option('auto_start', False, MACHINE_CONFIG_SECTION),
356
- plugin_option('machine_type', 'machine', 'Keyboard', MACHINE_CONFIG_SECTION),
357
- machine_specific_options(),
358
- # System.
359
- plugin_option('system_name', 'system', DEFAULT_SYSTEM_NAME, 'System', 'name'),
360
- system_keymap_option(),
361
- dictionaries_option(),
362
- ])
403
+ _OPTIONS = OrderedDict(
404
+ (opt.name, opt)
405
+ for opt in [
406
+ # Output.
407
+ choice_option(
408
+ "space_placement",
409
+ ("Before Output", "After Output"),
410
+ OUTPUT_CONFIG_SECTION,
411
+ ),
412
+ boolean_option("start_attached", False, OUTPUT_CONFIG_SECTION),
413
+ boolean_option("start_capitalized", False, OUTPUT_CONFIG_SECTION),
414
+ int_option(
415
+ "undo_levels",
416
+ DEFAULT_UNDO_LEVELS,
417
+ MINIMUM_UNDO_LEVELS,
418
+ None,
419
+ OUTPUT_CONFIG_SECTION,
420
+ ),
421
+ int_option(
422
+ "time_between_key_presses",
423
+ DEFAULT_TIME_BETWEEN_KEY_PRESSES,
424
+ MINIMUM_TIME_BETWEEN_KEY_PRESSES,
425
+ None,
426
+ OUTPUT_CONFIG_SECTION,
427
+ ),
428
+ choice_option(
429
+ "keyboard_layout",
430
+ ("qwerty", "qwertz", "colemak", "colemak-dh", "dvorak"),
431
+ OUTPUT_CONFIG_SECTION,
432
+ ),
433
+ # Logging.
434
+ path_option(
435
+ "log_file_name",
436
+ expand_path("strokes.log"),
437
+ LOGGING_CONFIG_SECTION,
438
+ "log_file",
439
+ ),
440
+ boolean_option("enable_stroke_logging", False, LOGGING_CONFIG_SECTION),
441
+ boolean_option("enable_translation_logging", False, LOGGING_CONFIG_SECTION),
442
+ # GUI.
443
+ boolean_option("start_minimized", False, "Startup", "Start Minimized"),
444
+ boolean_option("show_stroke_display", False, "Stroke Display", "show"),
445
+ boolean_option(
446
+ "show_suggestions_display", False, "Suggestions Display", "show"
447
+ ),
448
+ opacity_option("translation_frame_opacity", "Translation Frame", "opacity"),
449
+ boolean_option("classic_dictionaries_display_order", False, "GUI"),
450
+ # Plugins.
451
+ enabled_extensions_option(),
452
+ # Machine.
453
+ boolean_option("auto_start", False, MACHINE_CONFIG_SECTION),
454
+ plugin_option(
455
+ "machine_type", "machine", "Keyboard", MACHINE_CONFIG_SECTION
456
+ ),
457
+ machine_specific_options(),
458
+ # System.
459
+ plugin_option(
460
+ "system_name", "system", DEFAULT_SYSTEM_NAME, "System", "name"
461
+ ),
462
+ system_keymap_option(),
463
+ dictionaries_option(),
464
+ ]
465
+ )
363
466
 
364
467
  def _lookup(self, key):
365
468
  name = key[0] if isinstance(key, tuple) else key
@@ -377,7 +480,7 @@ class Config:
377
480
  except (configparser.NoOptionError, KeyError):
378
481
  value = opt.default(self, key)
379
482
  except InvalidConfigOption as e:
380
- log.error('invalid value for %r option', opt.name, exc_info=True)
483
+ log.error("invalid value for %r option", opt.name, exc_info=True)
381
484
  value = e.fixed_value
382
485
  self._cache[key] = value
383
486
  return value
plover/dictionary/base.py CHANGED
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) 2013 Hesky Fisher
2
2
  # See LICENSE.txt for details.
3
3
 
4
- # TODO: maybe move this code into the StenoDictionary itself. The current saver
4
+ # TODO: maybe move this code into the StenoDictionary itself. The current saver
5
5
  # structure is odd and awkward.
6
6
  # TODO: write tests for this file
7
7
 
@@ -17,47 +17,59 @@ from plover.registry import registry
17
17
  def _get_dictionary_class(filename):
18
18
  extension = splitext(filename)[1].lower()[1:]
19
19
  try:
20
- dict_module = registry.get_plugin('dictionary', extension).obj
20
+ dict_module = registry.get_plugin("dictionary", extension).obj
21
21
  except KeyError:
22
22
  raise ValueError(
23
- 'Unsupported extension: %s. Supported extensions: %s' %
24
- (extension, ', '.join(plugin.name for plugin in
25
- registry.list_plugins('dictionary'))))
23
+ "Unsupported extension: %s. Supported extensions: %s"
24
+ % (
25
+ extension,
26
+ ", ".join(
27
+ plugin.name for plugin in registry.list_plugins("dictionary")
28
+ ),
29
+ )
30
+ )
26
31
  return dict_module
27
32
 
33
+
28
34
  def _locked(fn):
29
35
  lock = threading.Lock()
36
+
30
37
  @functools.wraps(fn)
31
38
  def wrapper(*args, **kwargs):
32
39
  with lock:
33
40
  fn(*args, **kwargs)
41
+
34
42
  return wrapper
35
43
 
44
+
36
45
  def _threaded(fn):
37
46
  @functools.wraps(fn)
38
47
  def wrapper(*args, **kwargs):
39
48
  t = threading.Thread(target=fn, args=args, kwargs=kwargs)
40
49
  t.start()
50
+
41
51
  return wrapper
42
52
 
53
+
43
54
  def create_dictionary(resource, threaded_save=True):
44
- '''Create a new dictionary.
55
+ """Create a new dictionary.
45
56
 
46
57
  The format is inferred from the extension.
47
58
 
48
59
  Note: the file is not created! The resulting dictionary save
49
60
  method must be called to finalize the creation on disk.
50
- '''
61
+ """
51
62
  d = _get_dictionary_class(resource).create(resource)
52
63
  if threaded_save:
53
64
  d.save = _threaded(_locked(d.save))
54
65
  return d
55
66
 
67
+
56
68
  def load_dictionary(resource, threaded_save=True):
57
- '''Load a dictionary from a file.
69
+ """Load a dictionary from a file.
58
70
 
59
71
  The format is inferred from the extension.
60
- '''
72
+ """
61
73
  d = _get_dictionary_class(resource).load(resource)
62
74
  if not d.readonly and threaded_save:
63
75
  d.save = _threaded(_locked(d.save))
@@ -4,7 +4,6 @@ from plover.steno import normalize_steno
4
4
 
5
5
 
6
6
  class StenoNormalizer:
7
-
8
7
  def __init__(self, dictionary_path):
9
8
  self._dictionary_path = dictionary_path
10
9
  self._errors_count = 0
@@ -14,12 +13,15 @@ class StenoNormalizer:
14
13
  return normalize_steno(steno)
15
14
  except ValueError:
16
15
  self._errors_count += 1
17
- return tuple(steno.split('/'))
16
+ return tuple(steno.split("/"))
18
17
 
19
18
  def __enter__(self):
20
19
  return self.normalize
21
20
 
22
21
  def __exit__(self, exc_type, exc_value, traceback):
23
22
  if exc_type is None and self._errors_count:
24
- log.warning(_('dictionary `%s` loaded with %u invalid steno errors'),
25
- shorten_path(self._dictionary_path), self._errors_count)
23
+ log.warning(
24
+ _("dictionary `%s` loaded with %u invalid steno errors"),
25
+ shorten_path(self._dictionary_path),
26
+ self._errors_count,
27
+ )