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
blurdev/external.py DELETED
@@ -1,391 +0,0 @@
1
- from __future__ import print_function
2
- from __future__ import absolute_import
3
- import os
4
- import sys
5
- import time
6
- import multiprocessing
7
- from multiprocessing import Process, Pipe
8
- import blurdev
9
- from Qt.QtCore import QTimer
10
- from blurdev.protocols import BaseProtocolHandler, InvalidHandlerError
11
- import six
12
-
13
- try:
14
- # Optional: In case blur.Stone is not installed,
15
- # though this will mean it can't automatically close python.
16
- import blur.Stone as Stone
17
- except ImportError:
18
- Stone = None
19
-
20
-
21
- class External(object):
22
- """Singleton class used for multiProcess communication.
23
-
24
- This class provides a easy way to spawn a secondary instance of python and run
25
- Qt/blurdev. It also provides for two way communication between the two processes.
26
- Currently, the parent process does not check its pipe for data automatically, you
27
- will need to periodicly poll that data using checkPipe if you would like to receive
28
- that info.
29
-
30
- Note: This uses blur.Stone to monitor the parent process though it is optional, if
31
- blur.Stone is not installed, it may not properly close the subprocesses.
32
-
33
- Args:
34
- send: If provided, call multiProcess, and send the data. Defaults to None. See
35
- parsePipe for valid values.
36
-
37
- Attributes:
38
-
39
- checkIfOrphaned (bool): If true, exit blurdev if the parent process terminates
40
-
41
- childProcess (multiprocessing.Process): Pointer to the child process
42
-
43
- exitMonitorPid (int): Parent process id used to check if the parent process has
44
- terminated.
45
-
46
- exitMonitorProcessName (str): Parent process name used to check if the parent
47
- process has terminated. Because of how multiprocessing works this becomes
48
- invalid before the pid. In most cases the pid will not become invalid until
49
- the child python closes.
50
-
51
- isChildProcess (bool): If true, this is the child process, otherwise it is the
52
- parent process.
53
-
54
- timerCommand (QTimer): QTimer used to to check if there is data in the pipe, and
55
- check if the parent process has closed.
56
-
57
- parentCore (str): The name of the core that launched the child process. It is
58
- used to handleData any core specific configuration required like not
59
- parenting to the parent app.
60
-
61
- Example:
62
-
63
- In the parent process, this will spawn a child process if neccissary, and send
64
- ['treegrunt', 'Python_Logger'] to the child process. In this case it will launch
65
- the Python_Logger tool. In the child process, it would send the message back up
66
- the pipe to the parent process.
67
-
68
- >>> import blurdev.external
69
- >>> blurdev.external.External(['treegrunt', 'Python_Logger'])
70
- """
71
-
72
- _instance = None
73
-
74
- def __new__(cls, send=None):
75
- if not cls._instance:
76
- cls._instance = super(External, cls).__new__(cls, send=send)
77
- cls._parentPipe = None
78
- cls._childPipe = None
79
- cls.checkIfOrphaned = False
80
- cls.childProcess = None
81
- cls.exitMonitorPid = None
82
- cls.exitMonitorProcessName = ''
83
- cls.isChildProcess = False
84
- cls.timerCommand = None
85
- cls.parentCore = ""
86
- return cls._instance
87
-
88
- def __init__(self, send=None):
89
- super(External, self).__init__()
90
- if send:
91
- self.multiProcess()
92
- self.send(send)
93
-
94
- def checkPipe(self):
95
- """Poll the pipe to see if it contains data and return if it does and the data.
96
-
97
- If the pipe is broken because the parent process was closed, it will call
98
- shutdownIfParentClosed if checkIfOrphaned is enabled.
99
-
100
- Returns:
101
- bool: If the pipe had data
102
- var: The data stored in the pipe
103
- """
104
- pipe = self.pipe()
105
- try:
106
- if pipe and pipe.poll():
107
- data = pipe.recv()
108
- return True, data
109
- except IOError as e:
110
- if e.errno == 109:
111
- # The pipe has been ended, shutdown blurdev and exit python even if the
112
- # parent process is still running
113
- if self.checkIfOrphaned:
114
- self.shutdownIfParentClosed(force=True)
115
- return False, None
116
-
117
- def handleData(self, data):
118
- """Parses the data returned from the pipe and calls the proper handler.
119
-
120
- Processes data retreived from the pipe, and uses
121
- blurdev.protocols.BaseProtocolHandler to process the contents of data. Valid
122
- data should be in the form of ['handlerName', 'handlerCommand'] or
123
- ['handlerName', 'handlerCommand', {'keyword', 'args'}]. It will also accept a
124
- Exception as the only data. If a Exception is received it will be raised. If a
125
- invalid request is received, it will send a InvalidHandlerError exception back
126
- up the pipe.
127
-
128
- Args:
129
- data (list): ['handlerName', 'handlerCommand', {'keyword', 'args'}]
130
-
131
- Returns:
132
- bool: If a handler was found
133
- """
134
- name = None
135
- command = None
136
- params = {}
137
- if isinstance(data, Exception):
138
- raise data
139
- if isinstance(data, (list, tuple)) and len(data) > 1:
140
- # Lists/tuple's are only valid if they contain an id string and a dictionary
141
- name = data[0]
142
- command = data[1]
143
- # params are optional
144
- if len(data) > 2:
145
- params = data[2]
146
- handler = data
147
- if (
148
- not isinstance(name, six.string_types)
149
- or not isinstance(command, six.string_types)
150
- or not isinstance(params, dict)
151
- ):
152
- print("Invalid data", [name, command, params])
153
- msg = (
154
- "Please provide valid command handler arguments. Example: "
155
- "['handlerName', 'handlerCommand', {'keyword', 'args'}]"
156
- )
157
- self.send(InvalidHandlerError(msg))
158
- return
159
- handler = BaseProtocolHandler.findHandler(name, command, params)
160
- if handler:
161
- handler.run()
162
- return True
163
- return False
164
-
165
- def childIsAlive(self):
166
- if not self.isChildProcess:
167
- return self.childProcess.is_alive()
168
- return False
169
-
170
- @classmethod
171
- def launch(
172
- cls,
173
- hwnd,
174
- childPipe=None,
175
- exitMonitorPid=None,
176
- exitMonitorProcessName='',
177
- parentCore='',
178
- compid=None,
179
- ):
180
- """Used to initialize a new instance of python and start the Qt Event loop.
181
-
182
- This function configures blurdev and starts Qt. It calls QApplication.exec_()
183
- and will not exit until blurdev is shutdown.
184
-
185
- Args:
186
- hwnd(int): The win32 id used to parent Qt to the parent process
187
- childPipe(multiProcess.Pipe):
188
- The Pipe used for inter-process communication.
189
- Defaults to None.
190
- exitMonitorPid(int):
191
- Shutdown blurdev when this pid becomes invalid.
192
- Defaults to None.
193
- exitMonitorProcessName(str):
194
- Used with exitMonitorPid.
195
- Closing applications with a multiprocessing instance running often
196
- does not invalidate the pid, but changes the process name, checking
197
- both, allows us to detect that the process has closed
198
- even though the pid is still valid. Defaults to None.
199
- compid(string):
200
- A unique id used by Fusion to connect to the correct fusion if more than
201
- one fusion is open. Defaults to None.
202
- """
203
- instance = cls()
204
- instance.exitMonitorProcessName = exitMonitorProcessName
205
- instance.isChildProcess = True
206
- instance.parentCore = parentCore
207
- # Diffrent parent cores have diffrent requirements.
208
- # Studiomax and other software cores are not importable externally,
209
- # so we need to identify them by their object name.
210
- parentCore = parentCore.lower()
211
- if parentCore != "studiomax":
212
- blurdev.core.setHwnd(hwnd)
213
- blurdev.core._mfcApp = True
214
- if childPipe:
215
- # Monitor the pipe for communications from the parent application
216
- instance._childPipe = childPipe
217
- instance.startCheckingPipe(100)
218
- if exitMonitorPid and Stone:
219
- # Make parsePipe check if the parent process was closed, if so exit qt.
220
- instance.exitMonitorPid = exitMonitorPid
221
- instance.checkIfOrphaned = True
222
- elif exitMonitorPid and Stone is None:
223
- print(
224
- "blur.Stone is not installed, "
225
- "so this will not close automatically, or properly save prefs"
226
- )
227
- blurdev.core.setObjectName("multiprocessing")
228
- # Notes: studiomax: max crashes if app.quitOnLastWindowClosed is False.
229
- # fusion:if True, closing any window/dialog will cause qt to close and
230
- # python to exit external: pdb auto continue on close is not triggered if
231
- # app.quitOnLastWindowClosed is false
232
- if parentCore == "fusion" or (
233
- parentCore != "studiomax" and not instance.checkIfOrphaned
234
- ):
235
- # If this is not set, Qt will close when ever a QDialog or QMainWindow is
236
- # closed
237
- app = blurdev.application
238
- app.setQuitOnLastWindowClosed(False)
239
- # This is neccissary as long as our stylesheets depend on Plastique as a base.
240
- blurdev.application.setStyle(blurdev.core.defaultStyle())
241
- # Initialize the logger
242
- blurdev.core.logger()
243
- # Start Qt's event loop
244
- blurdev.startApplication()
245
-
246
- def multiProcess(self):
247
- """Spawns or returns instance of python and the Pipe to communicate with.
248
-
249
- It is safe to call this method multiple times in both the parent and child
250
- processes. It will only spawn a new instance of python in the parent process if
251
- the child process has been closed, or never launched. When called in the child
252
- process it does nothing
253
- """
254
- # Only create the subprocess if it hasn't already been created
255
- if self.isChildProcess or (self.childProcess and self.childProcess.is_alive()):
256
- return self.childProcess, self._parentPipe
257
- # NOTE: I am using a blur.Stone function to monitor if the parent app is closed.
258
- # If blur.Stone in not installed, you need a way to close it. For now I am
259
- # showing a python console. In the future I may extract the win32 code so it can
260
- # be checked, but it will probably be slower.
261
- exe = "python.exe"
262
- daemon = True
263
- if Stone:
264
- exe = "pythonw.exe"
265
- daemon = False
266
- exe = os.path.join(sys.exec_prefix, exe)
267
- # Nuke's sys.exec_prefix is the root directory on windows. Should I just use
268
- # pythonPath?
269
- if not os.path.exists(exe):
270
- exe = blurdev.osystem.pythonPath(pyw=bool(Stone))
271
- multiprocessing.set_executable(exe)
272
- if not hasattr(sys, "argv"):
273
- # multiprocessing requires sys.argv so manually create it if it doesn't
274
- # already exist
275
- sys.argv = ['']
276
- # Get all neccissary info to properly parent, communicate and detect closing
277
- hwnd = blurdev.core.hwnd() # used to parent Qt to parent app
278
- compid = (
279
- blurdev.core.uuid()
280
- ) # Id used by 3rd party api's to connect to parent app
281
- pid = os.getpid() # Detect if parent app was closed
282
-
283
- self._parentPipe, self._childPipe = Pipe()
284
- kwargs = {"compid": compid}
285
- kwargs["childPipe"] = self._childPipe
286
- kwargs["exitMonitorPid"] = pid
287
- kwargs["parentCore"] = blurdev.core.objectName()
288
- self.childProcess = Process(target=External.launch, args=(hwnd,), kwargs=kwargs)
289
- self.childProcess.daemon = daemon
290
- self.childProcess.start()
291
- return self.childProcess, self._parentPipe
292
-
293
- def parsePipe(self):
294
- """Callback used to monitor for incoming commands and execute them.
295
-
296
- If checkIfOrphaned is True, and exitMonitorPid is populated,
297
- it will check if the process is still running, if not,
298
- it will call blurdev.core.shutdown() and allow python to close without
299
- processing any queued pipe items.
300
- """
301
- if self.checkIfOrphaned and self.exitMonitorPid:
302
- if self.shutdownIfParentClosed():
303
- return
304
- hasData, data = self.checkPipe()
305
- # Clear out all pending data in the pipe
306
- while hasData:
307
- self.handleData(data)
308
- hasData, data = self.checkPipe()
309
-
310
- def pipe(self):
311
- """Returns the pipe used to communicate with the other end of the application.
312
-
313
- Returns:
314
- multiprocessing.Pipe: used to communicate with the other process
315
- """
316
- if self.isChildProcess:
317
- return self._childPipe
318
- return self._parentPipe
319
-
320
- def send(self, data):
321
- """Sends a command to be handled in the other process
322
-
323
- Commands must be a list. The first item is the name of the handler.
324
- The second item is the
325
- command to send to the handler.
326
- You can optionally pass a dictionary of kwargs as the third argument.
327
-
328
- See Also: blurdev.protocols
329
-
330
- Args:
331
- data(list): Command to send.
332
-
333
- Returns:
334
- bool: If data was sent
335
- """
336
- pipe = self.pipe()
337
- if pipe:
338
- pipe.send(data)
339
- return True
340
- return False
341
-
342
- def shutdownIfParentClosed(self, force=False):
343
- """Shutdown blurdev if parent process is closed.
344
-
345
- Uses blur.Stone to check if the parent process is still running, if not,
346
- it calls blurdev.core.shutdown() to close qt and allow python to exit.
347
-
348
- Args:
349
- force(bool): Ignore blur.Stone check and force blurdev to shutdown.
350
- """
351
- if force or not Stone.isRunning(
352
- self.exitMonitorPid, self.exitMonitorProcessName
353
- ):
354
- args = {"app": self.parentCore.capitalize()}
355
- msg = "{app} is no longer running, shutting down blurdev and saving prefs"
356
- print(msg.format(**args))
357
- if "python.exe" in sys.executable.lower():
358
- time.sleep(1)
359
- blurdev.core.shutdown()
360
- return True
361
- return False
362
-
363
- def startCheckingPipe(self, interval):
364
- """Starts a QTimer that calls parsePipe at the provided interval.
365
-
366
- This will process all pre-existing messages in the pipe
367
-
368
- Args:
369
- interval (int): The number of milliseconds between calling parsePipe
370
- """
371
- if not self.timerCommand:
372
- self.timerCommand = QTimer(blurdev.core)
373
- self.timerCommand.timeout.connect(self.parsePipe)
374
- self.timerCommand.start(interval)
375
-
376
- def stopCheckingPipe(self):
377
- """Stops the timerCommand QTimer."""
378
- if self.timerCommand:
379
- self.timerCommand.stop()
380
-
381
- def writeToPipe(self, msg, error=False):
382
- command = "stderr" if error else "stdout"
383
- # use wrapper to ensure that the pickle process
384
- # doesn't end up creating a int or something.
385
- self.send(
386
- [
387
- "stdoutput",
388
- command,
389
- {"msg": "!!!{}!!!".format(msg), "pdb": True, "wrapper": "!!!"},
390
- ]
391
- )