PrEditor 0.0.0.dev1__py2.py3-none-any.whl → 0.1.0__py2.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.

Potentially problematic release.


This version of PrEditor might be problematic. Click here for more details.

Files changed (363) hide show
  1. PrEditor-0.1.0.dist-info/LICENSE +165 -0
  2. PrEditor-0.1.0.dist-info/METADATA +212 -0
  3. PrEditor-0.1.0.dist-info/RECORD +149 -0
  4. {PrEditor-0.0.0.dev1.dist-info → PrEditor-0.1.0.dist-info}/WHEEL +1 -1
  5. PrEditor-0.1.0.dist-info/entry_points.txt +18 -0
  6. PrEditor-0.1.0.dist-info/top_level.txt +1 -0
  7. preditor/__init__.py +301 -0
  8. {blurdev → preditor}/__main__.py +13 -13
  9. preditor/about_module.py +166 -0
  10. preditor/cli.py +192 -0
  11. {blurdev → preditor}/contexts.py +119 -119
  12. preditor/cores/core.py +65 -0
  13. preditor/dccs/maya/PrEditor_maya.mod +2 -0
  14. preditor/dccs/maya/plug-ins/PrEditor_maya.py +108 -0
  15. preditor/debug.py +294 -0
  16. blurdev/scintilla/delayable_engine.py → preditor/delayable_engine/__init__.py +310 -299
  17. blurdev/scintilla/delayables/base.py → preditor/delayable_engine/delayables.py +85 -85
  18. {blurdev → preditor}/enum.py +728 -1003
  19. {blurdev → preditor}/gui/__init__.py +84 -125
  20. preditor/gui/app.py +159 -0
  21. {blurdev → preditor}/gui/codehighlighter.py +209 -219
  22. {blurdev → preditor}/gui/completer.py +226 -236
  23. {blurdev → preditor}/gui/console.py +801 -858
  24. {blurdev → preditor}/gui/dialog.py +200 -216
  25. preditor/gui/drag_tab_bar.py +190 -0
  26. preditor/gui/editor_chooser.py +57 -0
  27. {blurdev → preditor}/gui/errordialog.py +100 -97
  28. preditor/gui/fuzzy_search/fuzzy_search.py +93 -0
  29. preditor/gui/group_tab_widget/__init__.py +319 -0
  30. preditor/gui/group_tab_widget/grouped_tab_menu.py +35 -0
  31. preditor/gui/group_tab_widget/grouped_tab_models.py +108 -0
  32. preditor/gui/group_tab_widget/grouped_tab_widget.py +75 -0
  33. preditor/gui/group_tab_widget/one_tab_widget.py +54 -0
  34. preditor/gui/level_buttons.py +349 -0
  35. {blurdev → preditor}/gui/logger_window_handler.py +46 -45
  36. {blurdev → preditor}/gui/loggerwindow.py +1205 -1417
  37. {blurdev → preditor}/gui/newtabwidget.py +69 -68
  38. {blurdev → preditor}/gui/redmine_login_dialog.py +63 -61
  39. {blurdev → preditor}/gui/set_text_editor_path_dialog.py +59 -57
  40. preditor/gui/ui/editor_chooser.ui +93 -0
  41. {blurdev → preditor}/gui/ui/errordialog.ui +81 -81
  42. {blurdev → preditor}/gui/ui/loggerwindow.ui +1030 -864
  43. {blurdev → preditor}/gui/ui/redmine_login_dialog.ui +124 -124
  44. {blurdev → preditor}/gui/ui/set_text_editor_path_dialog.ui +149 -149
  45. {blurdev → preditor}/gui/window.py +183 -199
  46. preditor/gui/workbox_mixin.py +357 -0
  47. preditor/gui/workbox_text_edit.py +117 -0
  48. preditor/gui/workboxwidget.py +276 -0
  49. preditor/logging_config.py +52 -0
  50. preditor/osystem.py +401 -0
  51. preditor/plugins.py +65 -0
  52. preditor/prefs.py +74 -0
  53. {blurdev → preditor}/resource/environment_variables.html +26 -38
  54. {blurdev → preditor}/resource/error_mail.html +85 -85
  55. {blurdev → preditor}/resource/error_mail_inline.html +41 -41
  56. preditor/resource/img/README.md +7 -0
  57. preditor/resource/img/arrow_forward.png +0 -0
  58. preditor/resource/img/check-bold.png +0 -0
  59. preditor/resource/img/chevron-down.png +0 -0
  60. preditor/resource/img/chevron-up.png +0 -0
  61. preditor/resource/img/close-thick.png +0 -0
  62. preditor/resource/img/comment-edit.png +0 -0
  63. preditor/resource/img/content-copy.png +0 -0
  64. preditor/resource/img/content-cut.png +0 -0
  65. preditor/resource/img/content-duplicate.png +0 -0
  66. preditor/resource/img/content-paste.png +0 -0
  67. preditor/resource/img/content-save.png +0 -0
  68. preditor/resource/img/debug_disabled.png +0 -0
  69. preditor/resource/img/eye-check.png +0 -0
  70. preditor/resource/img/file-plus.png +0 -0
  71. preditor/resource/img/file-remove.png +0 -0
  72. preditor/resource/img/format-align-left.png +0 -0
  73. preditor/resource/img/format-letter-case-lower.png +0 -0
  74. preditor/resource/img/format-letter-case-upper.png +0 -0
  75. preditor/resource/img/information.png +0 -0
  76. preditor/resource/img/logging_critical.png +0 -0
  77. preditor/resource/img/logging_custom.png +0 -0
  78. preditor/resource/img/logging_debug.png +0 -0
  79. preditor/resource/img/logging_error.png +0 -0
  80. preditor/resource/img/logging_info.png +0 -0
  81. preditor/resource/img/logging_not_set.png +0 -0
  82. preditor/resource/img/logging_warning.png +0 -0
  83. preditor/resource/img/marker.png +0 -0
  84. preditor/resource/img/play.png +0 -0
  85. preditor/resource/img/playlist-play.png +0 -0
  86. preditor/resource/img/plus-minus-variant.png +0 -0
  87. preditor/resource/img/preditor.ico +0 -0
  88. preditor/resource/img/preditor.png +0 -0
  89. preditor/resource/img/preditor.psd +0 -0
  90. preditor/resource/img/preditor.svg +44 -0
  91. preditor/resource/img/restart.svg +1 -0
  92. preditor/resource/img/skip-forward-outline.png +0 -0
  93. preditor/resource/img/skip-next-outline.png +0 -0
  94. preditor/resource/img/skip-next.png +0 -0
  95. preditor/resource/img/skip-previous.png +0 -0
  96. preditor/resource/img/subdirectory-arrow-right.png +0 -0
  97. preditor/resource/img/text-search-variant.png +0 -0
  98. {blurdev → preditor}/resource/lang/python.json +30 -30
  99. preditor/resource/settings.ini +25 -0
  100. {blurdev/resource/stylesheet/logger → preditor/resource/stylesheet}/Bright.css +56 -61
  101. {blurdev → preditor}/resource/stylesheet/Dark.css +190 -132
  102. {blurdev → preditor}/scintilla/__init__.py +22 -28
  103. preditor/scintilla/delayables/__init__.py +11 -0
  104. {blurdev → preditor}/scintilla/delayables/smart_highlight.py +94 -93
  105. {blurdev → preditor}/scintilla/delayables/spell_check.py +173 -172
  106. {blurdev → preditor}/scintilla/documenteditor.py +2039 -2115
  107. {blurdev → preditor}/scintilla/finddialog.py +68 -81
  108. {blurdev → preditor}/scintilla/lang/__init__.py +80 -93
  109. {blurdev → preditor}/scintilla/lang/config/bash.ini +15 -15
  110. {blurdev → preditor}/scintilla/lang/config/batch.ini +14 -14
  111. {blurdev → preditor}/scintilla/lang/config/cpp.ini +19 -19
  112. {blurdev → preditor}/scintilla/lang/config/css.ini +19 -19
  113. {blurdev → preditor}/scintilla/lang/config/eyeonscript.ini +17 -17
  114. {blurdev → preditor}/scintilla/lang/config/html.ini +21 -21
  115. {blurdev → preditor}/scintilla/lang/config/javascript.ini +24 -24
  116. {blurdev → preditor}/scintilla/lang/config/lua.ini +16 -16
  117. {blurdev → preditor}/scintilla/lang/config/maxscript.ini +20 -20
  118. {blurdev → preditor}/scintilla/lang/config/mel.ini +18 -18
  119. {blurdev → preditor}/scintilla/lang/config/mu.ini +22 -22
  120. {blurdev → preditor}/scintilla/lang/config/nsi.ini +5 -5
  121. {blurdev → preditor}/scintilla/lang/config/perl.ini +19 -19
  122. {blurdev → preditor}/scintilla/lang/config/puppet.ini +19 -19
  123. {blurdev → preditor}/scintilla/lang/config/python.ini +28 -28
  124. {blurdev → preditor}/scintilla/lang/config/ruby.ini +19 -19
  125. {blurdev → preditor}/scintilla/lang/config/sql.ini +7 -7
  126. {blurdev → preditor}/scintilla/lang/config/xml.ini +21 -21
  127. {blurdev → preditor}/scintilla/lang/config/yaml.ini +18 -18
  128. {blurdev → preditor}/scintilla/lang/language.py +240 -250
  129. preditor/scintilla/lexers/__init__.py +0 -0
  130. {blurdev → preditor}/scintilla/lexers/cpplexer.py +21 -30
  131. {blurdev → preditor}/scintilla/lexers/javascriptlexer.py +25 -34
  132. {blurdev → preditor}/scintilla/lexers/maxscriptlexer.py +234 -253
  133. {blurdev → preditor}/scintilla/lexers/mellexer.py +368 -376
  134. {blurdev → preditor}/scintilla/lexers/mulexer.py +32 -41
  135. {blurdev → preditor}/scintilla/lexers/pythonlexer.py +41 -50
  136. {blurdev → preditor}/scintilla/ui/finddialog.ui +160 -160
  137. preditor/settings.py +71 -0
  138. preditor/stream/__init__.py +80 -0
  139. preditor/stream/director.py +56 -0
  140. preditor/stream/manager.py +74 -0
  141. preditor/streamhandler_helper.py +46 -0
  142. preditor/utils/__init__.py +0 -0
  143. preditor/utils/cute.py +30 -0
  144. preditor/utils/stylesheets.py +54 -0
  145. {blurdev → preditor}/version.py +5 -5
  146. preditor/weakref.py +363 -0
  147. PrEditor-0.0.0.dev1.dist-info/METADATA +0 -51
  148. PrEditor-0.0.0.dev1.dist-info/RECORD +0 -279
  149. PrEditor-0.0.0.dev1.dist-info/top_level.txt +0 -1
  150. blurdev/__init__.py +0 -356
  151. blurdev/cores/__init__.py +0 -98
  152. blurdev/cores/application.py +0 -26
  153. blurdev/cores/core.py +0 -634
  154. blurdev/debug.py +0 -593
  155. blurdev/external.py +0 -391
  156. blurdev/gui/level_buttons.py +0 -585
  157. blurdev/gui/workboxwidget.py +0 -205
  158. blurdev/logger.py +0 -238
  159. blurdev/osystem.py +0 -813
  160. blurdev/prefs.py +0 -33
  161. blurdev/protocols/__init__.py +0 -71
  162. blurdev/protocols/write_std_output_handler.py +0 -83
  163. blurdev/resource/designer_plugins.xml +0 -9
  164. blurdev/resource/error_email_old.html +0 -41
  165. blurdev/resource/img/add.png +0 -0
  166. blurdev/resource/img/ajax-loader.gif +0 -0
  167. blurdev/resource/img/application.png +0 -0
  168. blurdev/resource/img/applications.png +0 -0
  169. blurdev/resource/img/assburner.png +0 -0
  170. blurdev/resource/img/assfreezer.png +0 -0
  171. blurdev/resource/img/bar.gif +0 -0
  172. blurdev/resource/img/blank.png +0 -0
  173. blurdev/resource/img/blurdev.png +0 -0
  174. blurdev/resource/img/calendar_disabled.png +0 -0
  175. blurdev/resource/img/calendar_enabled.png +0 -0
  176. blurdev/resource/img/cancel.png +0 -0
  177. blurdev/resource/img/custom.png +0 -0
  178. blurdev/resource/img/debug_high.png +0 -0
  179. blurdev/resource/img/debug_low.png +0 -0
  180. blurdev/resource/img/debug_mid.png +0 -0
  181. blurdev/resource/img/debug_off.png +0 -0
  182. blurdev/resource/img/django.png +0 -0
  183. blurdev/resource/img/doc.png +0 -0
  184. blurdev/resource/img/edit.png +0 -0
  185. blurdev/resource/img/elemental.png +0 -0
  186. blurdev/resource/img/explore.png +0 -0
  187. blurdev/resource/img/favorite.png +0 -0
  188. blurdev/resource/img/file.png +0 -0
  189. blurdev/resource/img/folder.png +0 -0
  190. blurdev/resource/img/ide/add.png +0 -0
  191. blurdev/resource/img/ide/add_note.png +0 -0
  192. blurdev/resource/img/ide/arrow_down.png +0 -0
  193. blurdev/resource/img/ide/arrow_up.png +0 -0
  194. blurdev/resource/img/ide/check.png +0 -0
  195. blurdev/resource/img/ide/class.png +0 -0
  196. blurdev/resource/img/ide/clean.png +0 -0
  197. blurdev/resource/img/ide/clearlog.png +0 -0
  198. blurdev/resource/img/ide/close.png +0 -0
  199. blurdev/resource/img/ide/comment_add.png +0 -0
  200. blurdev/resource/img/ide/comment_remove.png +0 -0
  201. blurdev/resource/img/ide/comment_toggle.png +0 -0
  202. blurdev/resource/img/ide/console.png +0 -0
  203. blurdev/resource/img/ide/copy.png +0 -0
  204. blurdev/resource/img/ide/copylstrip.png +0 -0
  205. blurdev/resource/img/ide/cut.png +0 -0
  206. blurdev/resource/img/ide/edit.png +0 -0
  207. blurdev/resource/img/ide/find.png +0 -0
  208. blurdev/resource/img/ide/find_replace.png +0 -0
  209. blurdev/resource/img/ide/findnext.png +0 -0
  210. blurdev/resource/img/ide/findprev.png +0 -0
  211. blurdev/resource/img/ide/folder_find.png +0 -0
  212. blurdev/resource/img/ide/function.png +0 -0
  213. blurdev/resource/img/ide/git-bash.png +0 -0
  214. blurdev/resource/img/ide/git-gui.png +0 -0
  215. blurdev/resource/img/ide/gitk.png +0 -0
  216. blurdev/resource/img/ide/goto.png +0 -0
  217. blurdev/resource/img/ide/goto_def.png +0 -0
  218. blurdev/resource/img/ide/help.png +0 -0
  219. blurdev/resource/img/ide/highlighter.png +0 -0
  220. blurdev/resource/img/ide/lowercase.png +0 -0
  221. blurdev/resource/img/ide/newfile.png +0 -0
  222. blurdev/resource/img/ide/newfolder.png +0 -0
  223. blurdev/resource/img/ide/newproject.png +0 -0
  224. blurdev/resource/img/ide/newwizard.png +0 -0
  225. blurdev/resource/img/ide/open.png +0 -0
  226. blurdev/resource/img/ide/paste.png +0 -0
  227. blurdev/resource/img/ide/pdb_continue.png +0 -0
  228. blurdev/resource/img/ide/pdb_down.png +0 -0
  229. blurdev/resource/img/ide/pdb_next.png +0 -0
  230. blurdev/resource/img/ide/pdb_step.png +0 -0
  231. blurdev/resource/img/ide/pdb_up.png +0 -0
  232. blurdev/resource/img/ide/plus_minus.png +0 -0
  233. blurdev/resource/img/ide/preferences.png +0 -0
  234. blurdev/resource/img/ide/project_find.png +0 -0
  235. blurdev/resource/img/ide/python.png +0 -0
  236. blurdev/resource/img/ide/pyular.png +0 -0
  237. blurdev/resource/img/ide/qt.png +0 -0
  238. blurdev/resource/img/ide/quit.png +0 -0
  239. blurdev/resource/img/ide/redo.png +0 -0
  240. blurdev/resource/img/ide/refresh.png +0 -0
  241. blurdev/resource/img/ide/remove.png +0 -0
  242. blurdev/resource/img/ide/ruler.png +0 -0
  243. blurdev/resource/img/ide/run.png +0 -0
  244. blurdev/resource/img/ide/runall.png +0 -0
  245. blurdev/resource/img/ide/runallclear.png +0 -0
  246. blurdev/resource/img/ide/runselected.png +0 -0
  247. blurdev/resource/img/ide/runselectedclear.png +0 -0
  248. blurdev/resource/img/ide/save.png +0 -0
  249. blurdev/resource/img/ide/saveas.png +0 -0
  250. blurdev/resource/img/ide/sdk.png +0 -0
  251. blurdev/resource/img/ide/separator.png +0 -0
  252. blurdev/resource/img/ide/tabbed.png +0 -0
  253. blurdev/resource/img/ide/tile.png +0 -0
  254. blurdev/resource/img/ide/toolbar.png +0 -0
  255. blurdev/resource/img/ide/undo.png +0 -0
  256. blurdev/resource/img/ide/uppercase.png +0 -0
  257. blurdev/resource/img/ide/view_as.png +0 -0
  258. blurdev/resource/img/ide/windowed.png +0 -0
  259. blurdev/resource/img/ide.ico +0 -0
  260. blurdev/resource/img/ide.png +0 -0
  261. blurdev/resource/img/ide48.png +0 -0
  262. blurdev/resource/img/info.png +0 -0
  263. blurdev/resource/img/legacy tool.png +0 -0
  264. blurdev/resource/img/library.png +0 -0
  265. blurdev/resource/img/logger/about.png +0 -0
  266. blurdev/resource/img/logger/arrow_forward.png +0 -0
  267. blurdev/resource/img/logger/clear.png +0 -0
  268. blurdev/resource/img/logger/close.png +0 -0
  269. blurdev/resource/img/logger/debug_disabled.png +0 -0
  270. blurdev/resource/img/logger/debug_high.png +0 -0
  271. blurdev/resource/img/logger/debug_low.png +0 -0
  272. blurdev/resource/img/logger/debug_mid.png +0 -0
  273. blurdev/resource/img/logger/down.png +0 -0
  274. blurdev/resource/img/logger/find.png +0 -0
  275. blurdev/resource/img/logger/logging_critical.png +0 -0
  276. blurdev/resource/img/logger/logging_debug.png +0 -0
  277. blurdev/resource/img/logger/logging_error.png +0 -0
  278. blurdev/resource/img/logger/logging_info.png +0 -0
  279. blurdev/resource/img/logger/logging_not_set.png +0 -0
  280. blurdev/resource/img/logger/logging_warning.png +0 -0
  281. blurdev/resource/img/logger/next.png +0 -0
  282. blurdev/resource/img/logger/play.png +0 -0
  283. blurdev/resource/img/logger/playlist_play.png +0 -0
  284. blurdev/resource/img/logger/previous.png +0 -0
  285. blurdev/resource/img/logger/return.png +0 -0
  286. blurdev/resource/img/logger/save.png +0 -0
  287. blurdev/resource/img/logger/subdirectory_arrow_right.png +0 -0
  288. blurdev/resource/img/logger/up.png +0 -0
  289. blurdev/resource/img/lovebar.png +0 -0
  290. blurdev/resource/img/new.png +0 -0
  291. blurdev/resource/img/new_selected.png +0 -0
  292. blurdev/resource/img/node.png +0 -0
  293. blurdev/resource/img/ok.png +0 -0
  294. blurdev/resource/img/options.png +0 -0
  295. blurdev/resource/img/packages.png +0 -0
  296. blurdev/resource/img/preview/add.png +0 -0
  297. blurdev/resource/img/preview/brush.png +0 -0
  298. blurdev/resource/img/preview/delete.png +0 -0
  299. blurdev/resource/img/preview/delte.png +0 -0
  300. blurdev/resource/img/preview/fill.png +0 -0
  301. blurdev/resource/img/preview/layers.png +0 -0
  302. blurdev/resource/img/preview/media.png +0 -0
  303. blurdev/resource/img/preview/navigate.png +0 -0
  304. blurdev/resource/img/preview/pencil.png +0 -0
  305. blurdev/resource/img/preview/select.png +0 -0
  306. blurdev/resource/img/preview/type.png +0 -0
  307. blurdev/resource/img/preview/visible.png +0 -0
  308. blurdev/resource/img/project.png +0 -0
  309. blurdev/resource/img/python_logger.ico +0 -0
  310. blurdev/resource/img/python_logger.png +0 -0
  311. blurdev/resource/img/refresh.png +0 -0
  312. blurdev/resource/img/remove.png +0 -0
  313. blurdev/resource/img/reset.png +0 -0
  314. blurdev/resource/img/richtext/font_bold.png +0 -0
  315. blurdev/resource/img/richtext/font_italic.png +0 -0
  316. blurdev/resource/img/richtext/link_image.png +0 -0
  317. blurdev/resource/img/richtext/spell_check.png +0 -0
  318. blurdev/resource/img/richtext/unordered_list.png +0 -0
  319. blurdev/resource/img/save.png +0 -0
  320. blurdev/resource/img/savesettings.png +0 -0
  321. blurdev/resource/img/settings.png +0 -0
  322. blurdev/resource/img/tool.png +0 -0
  323. blurdev/resource/img/toolbarHandleHorizontal.png +0 -0
  324. blurdev/resource/img/toolbarHandleVertical.png +0 -0
  325. blurdev/resource/img/trash.png +0 -0
  326. blurdev/resource/img/trax.png +0 -0
  327. blurdev/resource/img/tree.png +0 -0
  328. blurdev/resource/img/treegrunt.ico +0 -0
  329. blurdev/resource/img/treegrunt.png +0 -0
  330. blurdev/resource/img/treegruntedit.png +0 -0
  331. blurdev/resource/img/user interface.png +0 -0
  332. blurdev/resource/img/warning.png +0 -0
  333. blurdev/resource/img/watermark.png +0 -0
  334. blurdev/resource/sdk/blurdev.sdk +0 -3
  335. blurdev/resource/settings.ini +0 -82
  336. blurdev/resource/softimage/BlurApplication.dll +0 -0
  337. blurdev/resource/softimage/BlurApplication64.dll +0 -0
  338. blurdev/resource/stylesheet/Carbon.css +0 -35
  339. blurdev/resource/stylesheet/logger/Dark.css +0 -62
  340. blurdev/resource/templ/py_comment.templ +0 -1
  341. blurdev/resource/templ/py_debug_raise_error.templ +0 -7
  342. blurdev/resource/templ/py_doc_string.templ +0 -10
  343. blurdev/resource/templ/py_header.templ +0 -9
  344. blurdev/resource/templ/py_line_comment.templ +0 -1
  345. blurdev/resource/templ/py_log_to_file.templ +0 -22
  346. blurdev/resource/templ/py_module_path.templ +0 -1
  347. blurdev/resource/templ/py_pyqt_core.templ +0 -1
  348. blurdev/resource/templ/py_pyqt_gui.templ +0 -1
  349. blurdev/resource/templ/py_splashscreen.templ +0 -6
  350. blurdev/resource/templ/py_testing_note.templ +0 -1
  351. blurdev/resource/templ/py_testing_note_end.templ +0 -1
  352. blurdev/resource/tools_environments.json +0 -72
  353. blurdev/resource/tools_environments.xml +0 -11
  354. blurdev/resource/tools_environments_linux.xml +0 -11
  355. blurdev/resource/tools_environments_offline.xml +0 -7
  356. blurdev/runtimes/__init__.py +0 -2
  357. blurdev/runtimes/logger.py +0 -44
  358. blurdev/scintilla/delayables/__init__.py +0 -9
  359. blurdev/settings.py +0 -312
  360. blurdev/utils/error.py +0 -389
  361. {blurdev/scintilla/lexers → preditor/cores}/__init__.py +0 -0
  362. {blurdev/utils → preditor/gui/fuzzy_search}/__init__.py +0 -0
  363. {blurdev → preditor}/resource/img/warning-big.png +0 -0
@@ -1,299 +1,310 @@
1
- from __future__ import print_function
2
- from __future__ import absolute_import
3
- from collections import MutableSet, OrderedDict
4
- import weakref
5
- import time
6
- import warnings
7
- from Qt.QtCore import QObject, QTimer, Signal
8
- from Qt import QtCompat
9
- from .delayables import Delayable
10
- import six
11
-
12
-
13
- # https://stackoverflow.com/a/7829569
14
- class OrderedSet(MutableSet):
15
- def __init__(self, values=()):
16
- self._od = OrderedDict().fromkeys(values)
17
-
18
- def __len__(self):
19
- return len(self._od)
20
-
21
- def __iter__(self):
22
- return iter(self._od)
23
-
24
- def __contains__(self, value):
25
- return value in self._od
26
-
27
- def add(self, value):
28
- self._od[value] = None
29
-
30
- def discard(self, value):
31
- self._od.pop(value, None)
32
-
33
-
34
- class OrderedWeakrefSet(weakref.WeakSet):
35
- def __init__(self, values=()):
36
- super(OrderedWeakrefSet, self).__init__()
37
- self.data = OrderedSet()
38
- for elem in values:
39
- self.add(elem)
40
-
41
-
42
- class DelayableEngine(QObject):
43
- """Provides a way for multiple DocumentEditors to run code over
44
- multiple Qt event loops in chunks preventing locking up the ui.
45
-
46
- Signals:
47
- processing_finished (int, float): Emitted when the engine finishes
48
- processing successfully.
49
- """
50
-
51
- _instance = {}
52
- processing_finished = Signal()
53
-
54
- def __init__(self, name, parent=None, interval=0):
55
- super(DelayableEngine, self).__init__()
56
- self.name = name
57
- self.documents = OrderedWeakrefSet()
58
- self.delayables = {}
59
- self.maxLoopTime = 0.01
60
- self.start_time = time.time()
61
- # It's likely we wont' finish processing all documents and all delayables
62
- # before we run out of time. These variables keep track of where we stopped.
63
- self.document_index = 0
64
- self.delayable_index = 0
65
-
66
- self.timer = QTimer(self)
67
- self.timer.setInterval(interval)
68
- self.timer.timeout.connect(self.loop)
69
-
70
- # These values are reset when enqueue needs to start self.timer
71
- # Each of these lists have a item added when self.loop exits
72
- # (this can be it finished or ran out of time)
73
- # Number of documents that had a delayable.loop called on them this loop
74
- self.processed = []
75
- # Time spent processing delayables for this self.loop
76
- self.processing_time = []
77
- # Number of nonVisible items that were skipped for this self.loop
78
- self.skipped = []
79
-
80
- def __repr__(self):
81
- return '{}.{}("{}")'.format(
82
- self.__module__,
83
- self.__class__.__name__,
84
- self.name,
85
- )
86
-
87
- def __str__(self):
88
- return '{}("{}")'.format(self.__class__.__name__, self.name)
89
-
90
- def add_delayable(self, delayable):
91
- """Add a Delayable subclass instance for processing in this engine.
92
-
93
- Args:
94
- delayable (Delayable or str): A Delayable instance or the key identifier.
95
- If a Delayable instance is passed, it will replace any previous
96
- instances. If a string is passed it will not replace previous instance.
97
-
98
- Raises:
99
- KeyError: A invalid key identifier string was passed.
100
- """
101
- if isinstance(delayable, six.string_types):
102
- if delayable in self.delayables:
103
- # Don't replace the instance if a string is passed
104
- return
105
- for cls in Delayable._all_subclasses():
106
- if cls.key == delayable:
107
- delayable = cls(self)
108
- break
109
- else:
110
- raise KeyError('No Delayable found with key: "{}"'.format(delayable))
111
- elif delayable.key in self.delayables:
112
- # Remove the old delayable if it exists so we can replace it.
113
- self.remove_delayable(self.delayables[delayable.key])
114
-
115
- self.delayables[delayable.key] = delayable
116
- for document in self.documents:
117
- delayable.add_document(document)
118
-
119
- def add_document(self, document):
120
- self.documents.add(document)
121
- document.delayable_engine = self
122
- for delayable in self.delayables:
123
- self.delayables[delayable].add_document(document)
124
-
125
- def add_supported_delayables(self, name):
126
- """Add all valid Delayable subclasses that have name in their supports."""
127
- for delayable in Delayable._all_subclasses():
128
- if delayable.key not in self.delayables:
129
- if name in delayable.supports and delayable.key != 'invalid':
130
- self.add_delayable(delayable(self))
131
-
132
- def delayable_enabled(self, delayable):
133
- """Returns True if delayable is currently added.
134
-
135
- Args:
136
- delayable (Delayable or str): A Delayable instance or the key identifier.
137
-
138
- Returns:
139
- bool: Is the given delayable installed for this engine.
140
- """
141
- if isinstance(delayable, Delayable):
142
- delayable = delayable.key
143
- return delayable in self.delayables
144
-
145
- def enqueue(self, document, key, *args):
146
- # Only add a item to be processed if we have a delayable that can
147
- # process the requested key.
148
- if key in self.delayables:
149
- # There is only ever one instance of a delayable class processed
150
- # If we already have a class enqueued, merge the arguments so we
151
- # don't end up loosing some processing.
152
- if key in document.delayable_info:
153
- args = self.delayables[key].merge_args(
154
- document.delayable_info[key], args
155
- )
156
- document.delayable_info[key] = args
157
- if not self.timer.isActive():
158
- self.timer.start()
159
- self.processed = []
160
- self.processing_time = []
161
- self.skipped = []
162
- return True
163
- return False
164
-
165
- def expired(self):
166
- return time.time() - self.start_time > self.maxLoopTime
167
-
168
- @classmethod
169
- def instance(cls, name, parent=None, interval=0):
170
- """Returns a shared instance of DelayableEngine, creating the instance if needed.
171
-
172
- Args:
173
- name (str): The name of the delayable engine to get the instance of.
174
- parent (QWidget, optional): If a new instance is created, use this as its
175
- parent. Ignored otherwise.
176
- interval (int, optional): If a new instance is created, use this as its
177
- interval value. Defaults to zero.
178
- """
179
- if name not in cls._instance:
180
- cls._instance[name] = cls(name, parent=parent, interval=interval)
181
- return cls._instance[name]
182
-
183
- def loop(self): # noqa C901
184
- self.start_time = time.time()
185
- documents = list(self.documents)
186
- # offset documents by the document_index so we can pickup where we left off
187
- documents = documents[self.document_index :] + documents[: self.document_index]
188
-
189
- count = 0
190
- skipped = 0
191
- finished = True
192
- first_loop = True
193
- while not self.expired():
194
- for document in documents:
195
- self.document_index += 1
196
- if self.document_index >= len(documents):
197
- self.document_index = 0
198
-
199
- if not QtCompat.isValid(document):
200
- if document in self.documents:
201
- self.documents.remove(document)
202
- print('Removing deleted document')
203
- continue
204
-
205
- if not document.delayable_info:
206
- continue
207
-
208
- if not document.isVisible() and first_loop:
209
- skipped += 1
210
- continue
211
-
212
- keys = list(document.delayable_info.keys())
213
- keys = keys[self.delayable_index :] + keys[: self.delayable_index]
214
- for key in keys:
215
- self.delayable_index += 1
216
- if self.delayable_index > len(keys):
217
- self.delayable_index = 0
218
-
219
- # delayable_info should only have keys for delayables we can access.
220
- delayable = self.delayables[key]
221
-
222
- args = document.delayable_info[key]
223
- try:
224
- args = delayable.loop(document, *args)
225
- except Exception:
226
- warnings.warn('Error processing {}, canceling it'.format(key))
227
- del document.delayable_info[key]
228
- raise
229
- if args:
230
- document.delayable_info[key] = args
231
- # We need to process more items
232
- finished = False
233
- else:
234
- del document.delayable_info[key]
235
- count += 1
236
- if self.expired():
237
- self.processed.append(count)
238
- self.processing_time.append(time.time() - self.start_time)
239
- self.skipped.append(skipped)
240
- return
241
-
242
- first_loop = False
243
-
244
- self.processed.append(count)
245
- self.processing_time.append(time.time() - self.start_time)
246
- self.skipped.append(skipped)
247
- if finished:
248
- # Nothing else to do for now, just exit
249
- self.timer.stop()
250
- self.processing_finished.emit()
251
-
252
- def remove_document(self, document):
253
- """Removes a document from being processed"""
254
- if document in self.documents:
255
- for delayable in self.delayables:
256
- self.delayables[delayable].remove_document(document)
257
-
258
- self.documents.remove(document)
259
- document.delayable_engine = type(self).instance('default')
260
-
261
- def remove_delayable(self, delayable):
262
- """Removes a Delayable subclass instance for processing in this engine.
263
-
264
- Args:
265
- delayable (Delayable or str): A Delayable instance or the key identifier.
266
- Remove this delayable from the current documents if it was added.
267
- """
268
- if isinstance(delayable, six.string_types):
269
- if delayable not in self.delayables:
270
- return
271
- delayable = self.delayables[delayable]
272
- if delayable:
273
- for document in self.documents:
274
- delayable.remove_document(document)
275
- # Stop processing this delayable if it's currently processing.
276
- try:
277
- del document.delayable_info[delayable.key]
278
- except KeyError:
279
- pass
280
- self.delayables.pop(delayable.key)
281
-
282
- def set_delayable_enabled(self, delayable, enabled):
283
- """Add or remove the delayable provided.
284
-
285
- Args:
286
- delayable (Delayable or str): A Delayable instance or the key identifier.
287
- enabled (bool): If True installs delayable, if False removes delayable.
288
-
289
- See Also:
290
- :py:meth:`DelayableEngine.add_delayable` and
291
- :py:meth:`DelayableEngine.remove_delayable`
292
-
293
- Raises:
294
- KeyError: A invalid key identifier string was passed.
295
- """
296
- if enabled:
297
- self.add_delayable(delayable)
298
- else:
299
- self.remove_delayable(delayable)
1
+ from __future__ import absolute_import, print_function
2
+
3
+ import time
4
+ import warnings
5
+ import weakref
6
+ from collections import OrderedDict
7
+
8
+ import six
9
+ from Qt import QtCompat
10
+ from Qt.QtCore import QObject, QTimer, Signal
11
+
12
+ from .delayables import Delayable
13
+
14
+ try:
15
+ from collections.abc import MutableSet
16
+ except ImportError:
17
+ # Due to the older versions of six installed by default with DCC's like
18
+ # Maya 2020, we can't rely on six.moves.collections_abc, so handle
19
+ # the py 2.7 import
20
+ from collections import MutableSet
21
+
22
+
23
+ # https://stackoverflow.com/a/7829569
24
+ class OrderedSet(MutableSet):
25
+ def __init__(self, values=()):
26
+ self._od = OrderedDict().fromkeys(values)
27
+
28
+ def __len__(self):
29
+ return len(self._od)
30
+
31
+ def __iter__(self):
32
+ return iter(self._od)
33
+
34
+ def __contains__(self, value):
35
+ return value in self._od
36
+
37
+ def add(self, value):
38
+ self._od[value] = None
39
+
40
+ def discard(self, value):
41
+ self._od.pop(value, None)
42
+
43
+
44
+ class OrderedWeakrefSet(weakref.WeakSet):
45
+ def __init__(self, values=()):
46
+ super(OrderedWeakrefSet, self).__init__()
47
+ self.data = OrderedSet()
48
+ for elem in values:
49
+ self.add(elem)
50
+
51
+
52
+ class DelayableEngine(QObject):
53
+ """Provides a way for multiple DocumentEditors to run code over
54
+ multiple Qt event loops in chunks preventing locking up the ui.
55
+
56
+ Signals:
57
+ processing_finished (int, float): Emitted when the engine finishes
58
+ processing successfully.
59
+ """
60
+
61
+ _instance = {}
62
+ processing_finished = Signal()
63
+
64
+ def __init__(self, name, parent=None, interval=0):
65
+ super(DelayableEngine, self).__init__()
66
+ self.name = name
67
+ self.documents = OrderedWeakrefSet()
68
+ self.delayables = {}
69
+ self.maxLoopTime = 0.01
70
+ self.start_time = time.time()
71
+ # It's likely we wont' finish processing all documents and all delayables
72
+ # before we run out of time. These variables keep track of where we stopped.
73
+ self.document_index = 0
74
+ self.delayable_index = 0
75
+
76
+ self.timer = QTimer(self)
77
+ self.timer.setInterval(interval)
78
+ self.timer.timeout.connect(self.loop)
79
+
80
+ # These values are reset when enqueue needs to start self.timer
81
+ # Each of these lists have a item added when self.loop exits
82
+ # (this can be it finished or ran out of time)
83
+ # Number of documents that had a delayable.loop called on them this loop
84
+ self.processed = []
85
+ # Time spent processing delayables for this self.loop
86
+ self.processing_time = []
87
+ # Number of nonVisible items that were skipped for this self.loop
88
+ self.skipped = []
89
+
90
+ def __repr__(self):
91
+ return '{}.{}("{}")'.format(
92
+ self.__module__,
93
+ self.__class__.__name__,
94
+ self.name,
95
+ )
96
+
97
+ def __str__(self):
98
+ return '{}("{}")'.format(self.__class__.__name__, self.name)
99
+
100
+ def add_delayable(self, delayable):
101
+ """Add a Delayable subclass instance for processing in this engine.
102
+
103
+ Args:
104
+ delayable (Delayable or str): A Delayable instance or the key identifier.
105
+ If a Delayable instance is passed, it will replace any previous
106
+ instances. If a string is passed it will not replace previous instance.
107
+
108
+ Raises:
109
+ KeyError: A invalid key identifier string was passed.
110
+ """
111
+ if isinstance(delayable, six.string_types):
112
+ if delayable in self.delayables:
113
+ # Don't replace the instance if a string is passed
114
+ return
115
+ for cls in Delayable._all_subclasses():
116
+ if cls.key == delayable:
117
+ delayable = cls(self)
118
+ break
119
+ else:
120
+ raise KeyError('No Delayable found with key: "{}"'.format(delayable))
121
+ elif delayable.key in self.delayables:
122
+ # Remove the old delayable if it exists so we can replace it.
123
+ self.remove_delayable(self.delayables[delayable.key])
124
+
125
+ self.delayables[delayable.key] = delayable
126
+ for document in self.documents:
127
+ delayable.add_document(document)
128
+
129
+ def add_document(self, document):
130
+ self.documents.add(document)
131
+ document.delayable_engine = self
132
+ for delayable in self.delayables:
133
+ self.delayables[delayable].add_document(document)
134
+
135
+ def add_supported_delayables(self, name):
136
+ """Add all valid Delayable subclasses that have name in their supports."""
137
+ for delayable in Delayable._all_subclasses():
138
+ if delayable.key not in self.delayables:
139
+ if name in delayable.supports and delayable.key != 'invalid':
140
+ self.add_delayable(delayable(self))
141
+
142
+ def delayable_enabled(self, delayable):
143
+ """Returns True if delayable is currently added.
144
+
145
+ Args:
146
+ delayable (Delayable or str): A Delayable instance or the key identifier.
147
+
148
+ Returns:
149
+ bool: Is the given delayable installed for this engine.
150
+ """
151
+ if isinstance(delayable, Delayable):
152
+ delayable = delayable.key
153
+ return delayable in self.delayables
154
+
155
+ def enqueue(self, document, key, *args):
156
+ # Only add a item to be processed if we have a delayable that can
157
+ # process the requested key.
158
+ if key in self.delayables:
159
+ # There is only ever one instance of a delayable class processed
160
+ # If we already have a class enqueued, merge the arguments so we
161
+ # don't end up loosing some processing.
162
+ if key in document.delayable_info:
163
+ args = self.delayables[key].merge_args(
164
+ document.delayable_info[key], args
165
+ )
166
+ document.delayable_info[key] = args
167
+ if not self.timer.isActive():
168
+ self.timer.start()
169
+ self.processed = []
170
+ self.processing_time = []
171
+ self.skipped = []
172
+ return True
173
+ return False
174
+
175
+ def expired(self):
176
+ return time.time() - self.start_time > self.maxLoopTime
177
+
178
+ @classmethod
179
+ def instance(cls, name, parent=None, interval=0):
180
+ """Returns a shared instance of DelayableEngine, creating the instance
181
+ if needed.
182
+
183
+ Args:
184
+ name (str): The name of the delayable engine to get the instance of.
185
+ parent (QWidget, optional): If a new instance is created, use this
186
+ as its parent. Ignored otherwise.
187
+ interval (int, optional): If a new instance is created, use this as
188
+ its interval value. Defaults to zero.
189
+ """
190
+ if name not in cls._instance:
191
+ cls._instance[name] = cls(name, parent=parent, interval=interval)
192
+ return cls._instance[name]
193
+
194
+ def loop(self): # noqa C901
195
+ self.start_time = time.time()
196
+ documents = list(self.documents)
197
+ # offset documents by the document_index so we can pickup where we left off
198
+ documents = documents[self.document_index :] + documents[: self.document_index]
199
+
200
+ count = 0
201
+ skipped = 0
202
+ finished = True
203
+ first_loop = True
204
+ while not self.expired():
205
+ for document in documents:
206
+ self.document_index += 1
207
+ if self.document_index >= len(documents):
208
+ self.document_index = 0
209
+
210
+ if not QtCompat.isValid(document):
211
+ if document in self.documents:
212
+ self.documents.remove(document)
213
+ print('Removing deleted document')
214
+ continue
215
+
216
+ if not document.delayable_info:
217
+ continue
218
+
219
+ if not document.isVisible() and first_loop:
220
+ skipped += 1
221
+ continue
222
+
223
+ keys = list(document.delayable_info.keys())
224
+ keys = keys[self.delayable_index :] + keys[: self.delayable_index]
225
+ for key in keys:
226
+ self.delayable_index += 1
227
+ if self.delayable_index > len(keys):
228
+ self.delayable_index = 0
229
+
230
+ # delayable_info should only have keys for delayables we can access.
231
+ delayable = self.delayables[key]
232
+
233
+ args = document.delayable_info[key]
234
+ try:
235
+ args = delayable.loop(document, *args)
236
+ except Exception:
237
+ warnings.warn('Error processing {}, canceling it'.format(key))
238
+ del document.delayable_info[key]
239
+ raise
240
+ if args:
241
+ document.delayable_info[key] = args
242
+ # We need to process more items
243
+ finished = False
244
+ else:
245
+ del document.delayable_info[key]
246
+ count += 1
247
+ if self.expired():
248
+ self.processed.append(count)
249
+ self.processing_time.append(time.time() - self.start_time)
250
+ self.skipped.append(skipped)
251
+ return
252
+
253
+ first_loop = False
254
+
255
+ self.processed.append(count)
256
+ self.processing_time.append(time.time() - self.start_time)
257
+ self.skipped.append(skipped)
258
+ if finished:
259
+ # Nothing else to do for now, just exit
260
+ self.timer.stop()
261
+ self.processing_finished.emit()
262
+
263
+ def remove_document(self, document):
264
+ """Removes a document from being processed"""
265
+ if document in self.documents:
266
+ for delayable in self.delayables:
267
+ self.delayables[delayable].remove_document(document)
268
+
269
+ self.documents.remove(document)
270
+ document.delayable_engine = type(self).instance('default')
271
+
272
+ def remove_delayable(self, delayable):
273
+ """Removes a Delayable subclass instance for processing in this engine.
274
+
275
+ Args:
276
+ delayable (Delayable or str): A Delayable instance or the key identifier.
277
+ Remove this delayable from the current documents if it was added.
278
+ """
279
+ if isinstance(delayable, six.string_types):
280
+ if delayable not in self.delayables:
281
+ return
282
+ delayable = self.delayables[delayable]
283
+ if delayable:
284
+ for document in self.documents:
285
+ delayable.remove_document(document)
286
+ # Stop processing this delayable if it's currently processing.
287
+ try:
288
+ del document.delayable_info[delayable.key]
289
+ except KeyError:
290
+ pass
291
+ self.delayables.pop(delayable.key)
292
+
293
+ def set_delayable_enabled(self, delayable, enabled):
294
+ """Add or remove the delayable provided.
295
+
296
+ Args:
297
+ delayable (Delayable or str): A Delayable instance or the key identifier.
298
+ enabled (bool): If True installs delayable, if False removes delayable.
299
+
300
+ See Also:
301
+ :py:meth:`DelayableEngine.add_delayable` and
302
+ :py:meth:`DelayableEngine.remove_delayable`
303
+
304
+ Raises:
305
+ KeyError: A invalid key identifier string was passed.
306
+ """
307
+ if enabled:
308
+ self.add_delayable(delayable)
309
+ else:
310
+ self.remove_delayable(delayable)