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,1003 +1,728 @@
1
- from __future__ import absolute_import
2
- from future.utils import iteritems, with_metaclass
3
- import abc
4
- import re
5
- from numbers import Number
6
- from builtins import str as text
7
- from past.builtins import long
8
-
9
- # =============================================================================
10
- # CLASSES
11
- # =============================================================================
12
-
13
-
14
- class _MetaEnumGroup(type):
15
- """An EnumGroup metaclass."""
16
-
17
- def __new__(cls, className, bases, classDict):
18
- newCls = type.__new__(cls, className, bases, classDict)
19
- newCls.__init_enums__()
20
- newCls._cls = cls
21
- newCls._clsName = className
22
- newCls._clsBases = bases
23
- newCls._clsDict = classDict
24
- return newCls
25
-
26
- def __call__(cls, number):
27
- number = int(number)
28
- e = cls.Nothing
29
- for enum in cls._ENUMERATORS:
30
- if enum & number:
31
- if e:
32
- e = e | enum
33
- else:
34
- e = enum
35
- return e
36
-
37
- def __getitem__(cls, key):
38
- if isinstance(key, Number):
39
- return list(cls)[int(key)]
40
- elif isinstance(key, slice):
41
- # If a Enum is passed convert it to its labelIndex
42
- start = key.start
43
- stop = key.stop
44
- if isinstance(start, Enum):
45
- start = start.labelIndex
46
- if isinstance(stop, Enum):
47
- stop = stop.labelIndex
48
- return list(cls)[slice(start, stop, key.step)]
49
- else:
50
- return getattr(cls, str(key))
51
-
52
- def __instancecheck__(cls, inst):
53
- if type(inst) == cls:
54
- return True
55
- if isinstance(inst, cls._cls):
56
- return True
57
- return False
58
-
59
- def __iter__(cls):
60
- for e in cls._ENUMERATORS:
61
- yield e
62
-
63
- def __len__(cls):
64
- return len(cls._ENUMERATORS)
65
-
66
- def __repr__(cls):
67
- return '<{mdl}.{cls}({enums})>'.format(
68
- mdl=cls._clsDict.get('__module__', 'unknown'),
69
- cls=cls._clsName,
70
- enums=cls.join(),
71
- )
72
-
73
- def __str__(cls):
74
- return '{0}({1})'.format(cls._clsName, cls.join())
75
-
76
- def __getattr__(cls, name):
77
- """This is entirely for backwards compatibility.
78
-
79
- This should/will be removed once a full transition is made.
80
- This is primarily required because there will be a period
81
- of time when trax.api is going out using the new EnumGroup
82
- setup, but there will be a time when not everyone has the
83
- update installed.
84
- """
85
- # Construct an old enum from our EnumGroup. If we have
86
- # descriptions for our new-style Enums, which is not
87
- # guaranteed, then we will set them. Otherwise we will
88
- # give it an empty string.
89
- kwargs = dict()
90
- descriptions = dict()
91
- for e in cls._ENUMERATORS:
92
- kwargs[e.name] = e.number
93
- try:
94
- descriptions[e.name] = e.description
95
- except AttributeError:
96
- descriptions[e.number] = ''
97
- oldEnum = enum(**kwargs)
98
- for number, desc in iteritems(descriptions):
99
- oldEnum.setDescription(number, desc)
100
- # Try and return the attribute from the old-style enum.
101
- try:
102
- return getattr(oldEnum, name)
103
- except AttributeError:
104
- raise AttributeError(
105
- "'EnumGroup' object has no attribute '{}'".format(name)
106
- )
107
-
108
-
109
- # =============================================================================
110
-
111
-
112
- class Enum(with_metaclass(abc.ABCMeta, object)):
113
- """A basic enumerator class.
114
-
115
- Enumerators are named values that act as identifiers. Typically, a
116
- list of enumerators are component pieces of an `EnumGroup`.
117
-
118
- Example::
119
-
120
- class Suit(Enum):
121
- pass
122
-
123
- class Suits(EnumGroup):
124
- Hearts = Suit()
125
- Spades = Suit()
126
- Clubs = Suit()
127
- Diamonds = Suit()
128
-
129
- Enum objects can be combined and compared using binary "and" and "or"
130
- operations.
131
-
132
- Example::
133
-
134
- mySuits = Suits.Hearts | Suits.Spades
135
-
136
- if Suits.Hearts & mySuits:
137
- print("This is true!")
138
-
139
- if Suits.Clubs & mySuits:
140
- print("This is false!")
141
-
142
- Attributes:
143
- name: The name of the enumerator.
144
- number: The integer value representation of the enumerator.
145
- label: The enumerator's label.
146
- labelIndex: The enumerator's index within its parent EnumGroup.
147
- """
148
-
149
- _CREATIONORDER = 0
150
-
151
- def __init__(self, number=None, label=None, **kwargs):
152
- """Initializes a new Enum object.
153
-
154
- In addition to the named arguments listed below, keyword arguments
155
- may be given that will be set as attributes on the Enum.
156
-
157
- Args:
158
- number(int): The integer representation of the Enum. The default
159
- is to have this number determined dynamically based on its
160
- place with the parent EnumGroup.
161
- label(str): The Enum's label. The default is to inherit the
162
- attribute name the Enum is associated with in its parent
163
- EnumGroup.
164
- """
165
- self._creationOrder = Enum._CREATIONORDER
166
- Enum._CREATIONORDER += 1
167
- self._name = None
168
- self._number = number
169
- self._label = label
170
- self._labelIndex = None
171
- self._cmpLabel = None
172
- self._cmpName = None
173
- self._enumGroup = None
174
- if kwargs:
175
- self.__dict__.update(kwargs)
176
-
177
- @property
178
- def name(self):
179
- """The name of the Enum."""
180
- return self._name
181
-
182
- @property
183
- def number(self):
184
- """The number representation of the Enum."""
185
- return self._number
186
-
187
- @property
188
- def label(self):
189
- """The Enum's label."""
190
- return self._label
191
-
192
- @property
193
- def labelIndex(self):
194
- """The Enum's index within its parent EnumGroup."""
195
- return self._labelIndex
196
-
197
- def _setName(self, name):
198
- if name is None:
199
- self._name = None
200
- self._cmpName = None
201
- else:
202
- self._name = name
203
- self._cmpName = name.strip('_ ')
204
-
205
- def _setLabel(self, label):
206
- if label is None:
207
- self._label = None
208
- self._cmpLabel = None
209
- else:
210
- self._label = label
211
- self._cmpLabel = label.replace(' ', '').replace('_', '')
212
-
213
- def __add__(self, other):
214
- return self.__or__(other)
215
-
216
- def __and__(self, other):
217
- if isinstance(other, Enum):
218
- other = int(other)
219
- return int(self) & other
220
-
221
- def __call__(self):
222
- return int(self)
223
-
224
- def __cmp__(self, value):
225
- if not isinstance(value, Enum):
226
- return -1
227
- return self.number - value.number
228
-
229
- def __lt__(self, value):
230
- return self.__cmp__(value) < 0
231
-
232
- def __eq__(self, value):
233
- if value is None:
234
- return False
235
- if isinstance(value, Enum):
236
- return self.number == value.number
237
- if isinstance(value, (int, long)):
238
- return self.number == value
239
- if isinstance(value, str) or isinstance(value, text):
240
- if self._compareStr(value):
241
- return True
242
- return False
243
-
244
- def __hash__(self):
245
- return self.number
246
-
247
- def __index__(self):
248
- return self.number
249
-
250
- def __int__(self):
251
- return self.number or 0
252
-
253
- def __invert__(self):
254
- return ~int(self)
255
-
256
- def __ne__(self, value):
257
- return not self.__eq__(value)
258
-
259
- def __nonzero__(self):
260
- return bool(int(self))
261
-
262
- def __or__(self, other):
263
- o = other
264
- if isinstance(other, Enum):
265
- o = int(other)
266
- # No need to return a CompositeEnum if one of these is Nothing
267
- if o == 0:
268
- return self
269
- v = int(self)
270
- if v == 0:
271
- return other
272
- value = v | o
273
- label = '{0} {1}'.format(str(self), str(other))
274
- name = '{0}_{1}'.format(str(self), str(other))
275
-
276
- class CompositeEnum(Enum):
277
- def __init__(ss, number, lbl, name): # noqa: N805,B902
278
- super(CompositeEnum, ss).__init__(number, lbl)
279
- ss._name = name
280
-
281
- # Register our composite enum class as a virtual
282
- # subclass of this enum's class, plus the same for
283
- # the other enum if it's an Enum object. This
284
- # will make the composite enum isinstance check true
285
- # against both.
286
- type(self).register(CompositeEnum)
287
- if isinstance(other, Enum):
288
- type(other).register(CompositeEnum)
289
- return CompositeEnum(value, label, name)
290
-
291
- def __rand__(self, other):
292
- if isinstance(other, Enum):
293
- other = int(other)
294
- return other & int(self)
295
-
296
- def __repr__(self):
297
- return '<{mdl}.{cls}.{name}>'.format(
298
- mdl=self.__class__.__module__,
299
- cls=self.__class__.__name__,
300
- name=str(self.name),
301
- )
302
-
303
- def __ror__(self, other):
304
- return self | other
305
-
306
- def __rxor__(self, other):
307
- return self ^ other
308
-
309
- def __str__(self):
310
- if self.name:
311
- return self.name
312
- return self.label or ''
313
-
314
- def __xor__(self, other):
315
- if isinstance(other, Enum):
316
- other = int(other)
317
- return int(self) ^ other
318
-
319
- def _compareStr(self, inStr):
320
- return inStr.replace(' ', '').replace('_', '') in (
321
- self._cmpLabel,
322
- self._cmpName,
323
- )
324
-
325
-
326
- # =============================================================================
327
-
328
-
329
- class EnumGroup(with_metaclass(_MetaEnumGroup, object)):
330
- """A container class for collecting, organizing, and accessing Enums.
331
-
332
- An EnumGroup class is a container for Enum objects. It provides
333
- organizational convenience, and in most cases handles the generation
334
- and assignment of Enum numbers, names, and labels.
335
-
336
- Example::
337
-
338
- class Suit(Enum):
339
- pass
340
-
341
- class Suits(EnumGroup):
342
- Hearts = Suit()
343
- Spades = Suit()
344
- Clubs = Suit()
345
- Diamonds = Suit()
346
-
347
- The above example outlines defining an enumerator, and grouping
348
- four of them inside of a group. This provides a number of things,
349
- including references by attribute, name, and index. Also provided
350
- is an "All" attribute, if one is not explicitly assigned, it will be
351
- a CompositeEnum of all the defined enums, and compare true against
352
- any members of the group via the binary "and" operator. Also provided
353
- is an "Nothing" attribute, if one is not explicitly assigned, it
354
- compares false against any members of the group and when converted to
355
- a int its value will be zero.
356
-
357
- Example::
358
-
359
- # By attribute.
360
- Suits.Hearts
361
-
362
- # By name.
363
- Suits['Hearts']
364
-
365
- suitList = list(Suits)
366
-
367
- if Suits.Hearts & Suits.All:
368
- print("This is true!")
369
-
370
- You can also pass a int value as a index lookup. If you pass a int value it
371
- will return the object by its index. This means you can not lookup composite
372
- Enum objects as 3 returns the third index which in the above example is Diamonds.
373
- The index value for Enum is stored on its labelIndex property.
374
-
375
- Example::
376
-
377
- print(Suits.Diamonds.labelIndex)
378
-
379
- if Suits.Diamonds == Suits[3]:
380
- print("This is true!")
381
-
382
- An EnumGroup can be sliced by passing an Enum object or its labelIndex value for
383
- start and stop, returning a list of matching Enums.
384
-
385
- Example::
386
-
387
- # All Enums between Spades and Diamonds
388
- Suits[Suits.Spades:Suits.Diamonds]
389
-
390
- # All Enums between Spades and Clubs including Clubs
391
- Suits[Suits.Spades:Suits.Clubs.labelIndex+1]
392
-
393
- An EnumGroup can also act as a factory for composite Enum objects.
394
- If a known composite value is available, like 3, which is the
395
- combination of enum values 1 and 2, a composite Enum object can
396
- be constructed.
397
-
398
- Example::
399
-
400
- comp = Suits(3)
401
-
402
- if Suits.Hearts & comp:
403
- print("This is true!")
404
-
405
- if Suits.Clubs & comp:
406
- print("This is false!")
407
-
408
- If one of the Enum's has the default keyword argument set to True, then that Enum
409
- is also exposed as the "Default" attribute. Additionally all other Enum's will have
410
- a default property added and set to False.
411
-
412
- Example::
413
-
414
- class Suits(EnumGroup):
415
- Hearts = Suit()
416
- Spades = Suit(default=True)
417
-
418
- assert Suits.Hearts.default == False
419
- assert Suits.Spades.default == True
420
- assert Suits.Default == Suits.Spades
421
-
422
- Attributes:
423
- All: The sum of all members.
424
- Nothing: None of the members.
425
- """
426
-
427
- _ENUMERATORS = None
428
- _copyCount = 1
429
- All = 0
430
- Nothing = 0
431
-
432
- def __init__(self):
433
- raise InstantiationError('Unable to instantiate static class EnumGroup.')
434
-
435
- @classmethod
436
- def append(cls, *args, **kwargs):
437
- """Appends additional enumerators to the EnumGroup.
438
-
439
- New members can be provided as ordered arguments where the
440
- each Enum's label is used to determine the attribute name, or
441
- by keyword arguments where the key is the attribute name and
442
- the Enum is the value. When using an Enum's label to determine
443
- its name, any spaces in the label will be converted to underscores.
444
-
445
- Example:
446
- Suits.append(Suit(None, 'Funky'), Foo=Suit())
447
-
448
- # The "Funky" and "Foo" suits are now available.
449
- Suits.Funky
450
- Suits.Foo
451
-
452
- Raises:
453
- ValueError
454
- """
455
- if [e for e in (list(args) + list(kwargs.values())) if not isinstance(e, Enum)]:
456
- raise ValueError('Given items must be of class Enum.')
457
- if [e for e in args if not e.label]:
458
- raise ValueError('Enums given as ordered arguments must have a label.')
459
- for e in args:
460
- setattr(cls, cls._labelToVarName(e.label), e)
461
- for n, e in iteritems(kwargs):
462
- setattr(cls, n, e)
463
- # reset All and Nothing -- this is necessary so that All is regenerated
464
- # and so that Nothing is not included when finding the member Enums.
465
- cls.All = 0
466
- cls.Nothing = 0
467
- cls.__init_enums__()
468
-
469
- @classmethod
470
- def copy(cls, name=None):
471
- """Returns a new class type from this class without any Enums assigned.
472
-
473
- If name is not provided it will automatically generate a new class name.
474
- For example if the EnumGroup class named DefaultEnums has been copied
475
- twice the new class name will be "DefaultEnums_3".
476
- If you provide name it will not check for duplicates.
477
-
478
- Args:
479
- name (str|None): The name to give the new class. Defaults to None
480
-
481
- Returns:
482
- EnumGroup: A new Class type.
483
- """
484
- if not name:
485
- # Generate a unique name for the class if one was not provided
486
- name = '{name}_{count}'.format(name=cls.__name__, count=cls._copyCount)
487
- cls._copyCount += 1
488
- return type(name, cls.__bases__, dict(cls.__dict__))
489
-
490
- @classmethod
491
- def fromLabel(cls, label, default=None):
492
- """Gets an enumerator based on the given label.
493
-
494
- If a default is provided and is not None, that value will be returned
495
- in the event that the given label does not exist in the EnumGroup. If
496
- no default is provided, a ValueError is raised.
497
-
498
- Args:
499
- label(str): The label to look up.
500
- default(*): The default value to return if the label is not found.
501
-
502
- Raises:
503
- ValueError: Raised if default is None and the given label does not
504
- exist in the EnumGroup.
505
-
506
- Returns:
507
- Enum
508
- """
509
- label = str(label)
510
- for e in cls._ENUMERATORS:
511
- if e.label == label:
512
- return e
513
- if default is not None:
514
- return default
515
- raise ValueError('No enumerators exist with the given label.')
516
-
517
- @classmethod
518
- def fromValue(cls, value, default=None, allowComposite=False):
519
- """Gets an enumerator based on the given value.
520
-
521
- If a default is provided and is not None, that value will be returned
522
- in the event that the given label does not exist in the EnumGroup. If
523
- no default is provided, a ValueError is raised.
524
-
525
- Args:
526
- value (int): The value to look up.
527
- default (*): The default value to return if the label is not found.
528
- allowComposite (bool, optional): If True a composite enums will be
529
- created when provided a value that is the sum of multiple enum
530
- values. Otherwise, a ValueError will be raised. Defaults to
531
- False.
532
-
533
- Returns:
534
- Enum
535
-
536
- Raises:
537
- ValueError: Raised if default is None and the given label does not
538
- exist in the EnumGroup.
539
- """
540
- value = int(value)
541
- composite = None
542
- for e in cls._ENUMERATORS:
543
- eVal = int(e)
544
- if eVal == value:
545
- return e
546
- if allowComposite and eVal & value:
547
- composite = e if composite is None else (composite | e)
548
- if composite is not None and int(composite) == value:
549
- return composite
550
- if default is not None:
551
- return default
552
- raise ValueError('No enumerators exist with the given value.')
553
-
554
- @classmethod
555
- def join(cls, include=None, separator=','):
556
- """Joins all child Enums together into a single string.
557
-
558
- The string representation of each Enum is joined using the
559
- given separator.
560
-
561
- Args:
562
- include(int|Enum): Only enumerators that compare via bitwise "and" against
563
- the given int or Enum will be returned. Default is EnumGroup.All.
564
- separator(str): The separator to use. Default is ",".
565
-
566
- Returns:
567
- str: The joined enumerators.
568
- """
569
- include = include is None and cls.All or include
570
- return str(separator).join(
571
- [str(e) for e in cls._ENUMERATORS if e & int(include)]
572
- )
573
-
574
- @classmethod
575
- def labels(cls):
576
- """A generator containing all Enum labels in the EnumGroup."""
577
- return (e.label for e in cls._ENUMERATORS)
578
-
579
- @classmethod
580
- def names(cls):
581
- """A generator containing all Enum names in the EnumGroup."""
582
- return (e.name for e in cls._ENUMERATORS)
583
-
584
- @classmethod
585
- def split(cls, string, separator=','):
586
- """Splits the given string and returns the corresponding Enums.
587
-
588
- The string is split using the provided separator, and all names
589
- contained within must be attributes of the EnumGroup class that
590
- is performing the split.
591
-
592
- Args:
593
- string(str): The string containing the desired Enum names.
594
- separator(str): The separator to split on. Default is ','.
595
-
596
- Raises:
597
- AttributeError
598
-
599
- Returns:
600
- list(Enum, ...): The list of resulting Enum objects.
601
- """
602
- names = str(string).split(str(separator))
603
- return [getattr(cls, n) for n in names]
604
-
605
- @classmethod
606
- def values(cls):
607
- """A generator containing all Enum values in the EnumGroup."""
608
- return (int(e) for e in cls._ENUMERATORS)
609
-
610
- @classmethod
611
- def __init_enums__(cls):
612
- enums = []
613
- default_enum = None
614
-
615
- orderedEnums = sorted(
616
- [
617
- (k, v)
618
- for k, v in iteritems(cls.__dict__)
619
- if isinstance(v, Enum) and k not in ('All', 'Nothing')
620
- ],
621
- key=lambda i: i[1]._creationOrder,
622
- )
623
- for name, value in orderedEnums:
624
- enums.append(value)
625
- value._enumGroup = cls
626
- value._setName(name)
627
- if value.label is None:
628
- value._setLabel(cls._varNameToLabel(name))
629
- # Check for a default property and raise a error if more than one is found
630
- if hasattr(value, 'default') and value.default:
631
- if default_enum is not None:
632
- raise ValueError(
633
- (
634
- '"{}" already defines default and "{}" is trying to '
635
- 'claim the default'
636
- ).format(default_enum, value)
637
- )
638
- default_enum = value
639
-
640
- enumNumbers = [enum.number for enum in enums if enum.number]
641
- num = 1
642
- for enum in enums:
643
- if enum._number is None:
644
- while num in enumNumbers:
645
- num *= 2
646
- enum._number = num
647
- enumNumbers.append(num)
648
- enums.sort()
649
- labelIndex = 0
650
- for enum in enums:
651
- if enum._label is not None:
652
- enum._labelIndex = labelIndex
653
- labelIndex += 1
654
- # Add a default property to all enums for consistency
655
- if default_enum and not hasattr(enum, 'default'):
656
- enum.default = False
657
- cls._ENUMERATORS = enums
658
- # Build the All object if its not defined
659
- if isinstance(cls.All, int):
660
- for e in enums:
661
- if isinstance(cls.All, int):
662
- cls.All = e
663
- else:
664
- cls.All |= e
665
- # Build the Nothing object if its not defined
666
- if isinstance(cls.Nothing, int) and enums:
667
- processed = set()
668
- for i, enum in enumerate(enums):
669
- enumClass = enum.__class__
670
- if i == 0:
671
- # Create the Nothing instance from the first class type
672
- cls.Nothing = enumClass(0, 'Nothing')
673
- elif enumClass not in processed:
674
- # Register our Nothing enum's class as a virtual
675
- # subclass of any additional enum classes. This
676
- # will make the Nothing enum isinstance check true
677
- # against all Enums in this EnumGroup.
678
- enumClass.register(cls.Nothing.__class__)
679
- processed.add(enumClass)
680
- # If a default was specified, store it on the Default argument
681
- if default_enum and not hasattr(cls, 'Default'):
682
- cls.Default = default_enum
683
- # Ensure the All and Nothing Enum's have a default as well
684
- cls.All.default = False
685
- if enums:
686
- cls.Nothing.default = False
687
-
688
- @classmethod
689
- def _varNameToLabel(cls, varName):
690
- label = str(varName)
691
- label = ' '.join(re.findall('[A-Z]+[^A-Z]*', label))
692
- label = re.sub(r'[_\s]+', ' ', label)
693
- return label
694
-
695
- @classmethod
696
- def _labelToVarName(cls, label):
697
- name = str(label)
698
- name = re.sub(r'\s+', '_', name)
699
- return name
700
-
701
-
702
- # =============================================================================
703
- class Incrementer(object):
704
- """A class that behaves similarly to c i++ or ++i.
705
-
706
- Once you init this class, every time you call it it will update count and return the
707
- previous value like c's i++. If you pass True to pre, it will increment then return
708
- the new value like c's ++i.
709
-
710
- Args:
711
- start (int): Start the counter at this value. Defaults to Zero.
712
-
713
- increment (int): increment by this value. In most cases it should be 1 or -1.
714
- Defaults to one.
715
-
716
- pre (bool): If true calling the object will return the incremented value. If
717
- False it will return the current value and increment for the next call.
718
- Defaults to False.
719
-
720
- Attributes:
721
- count: The current value.
722
- increment: The incremnt added to count
723
- pre: Should it preform a ++i or i++ operation when called.
724
- """
725
-
726
- def __init__(self, start=0, increment=1, pre=False):
727
- super(Incrementer, self).__init__()
728
- self.count = start
729
- self.increment = increment
730
- self.pre = pre
731
-
732
- def __call__(self):
733
- if self.pre:
734
- self.count += self.increment
735
- return self.count
736
- ret = self.count
737
- self.count += self.increment
738
- return ret
739
-
740
- def __repr__(self):
741
- return '{}.{}(start={}, increment={}, pre={!r})'.format(
742
- self.__module__, type(self).__name__, self.count, self.increment, self.pre
743
- )
744
-
745
- def __str__(self):
746
- return str(self.count)
747
-
748
-
749
- # =============================================================================
750
-
751
-
752
- class enum(object): # noqa: N801
753
- """DEPRECATED: Python based enumerator class.
754
-
755
- This class is deprecated and should be replaced by blurdev.enum.Enum and
756
- blurdev.enum.EnumGroup.
757
-
758
- A short example::
759
-
760
- >>> Colors = enum("Red", "Yellow", "Blue")
761
- >>> Color.Red
762
- 1
763
- >>> Color.Yellow
764
- 2
765
- >>> Color.Blue
766
- 4
767
- >>> Color.labelByValue(Color.Blue)
768
- 'Blue'
769
- """
770
-
771
- def __call__(self, key):
772
- return self.value(key)
773
-
774
- def __getattr__(self, key):
775
- if key == '__name__':
776
- return 'enum'
777
- else:
778
- raise AttributeError(key)
779
-
780
- def __init__(self, *args, **kwds):
781
- """Takes the provided arguments adds them as properties of this object. For
782
- each argument you pass in it will assign binary values starting with the first
783
- argument, 1, 2, 4, 8, 16, .... If you pass in any keyword arguments it will
784
- store the value.
785
-
786
- Note: Labels automatically add spaces for every capital letter after the first,
787
- so do not use spaces for args, or the keys of kwargs or you will not be able to
788
- access those parameters.
789
-
790
- :param *args: Properties with binary values are created
791
- :param **kwds: Properties with passed in values are created
792
-
793
- Example::
794
- >>> e = blurdev.enum.enum('Red', 'Green', 'Blue', White=7)
795
- >>> e.Blue
796
- 4
797
- >>> e.White
798
- 7
799
- >>> e.Red | e.Green | e.Blue
800
- 7
801
- """
802
- super(enum, self).__init__()
803
- self._keys = list(args) + list(kwds.keys())
804
- self._compound = list(kwds.keys())
805
- self._descr = {}
806
- key = 1
807
- for i in range(len(args)):
808
- self.__dict__[args[i]] = key
809
- key *= 2
810
-
811
- for kwd, value in kwds.items():
812
- self.__dict__[kwd] = value
813
-
814
- if not ('All' in args or 'All' in kwds):
815
- out = 0
816
- for k in self._keys:
817
- if isinstance(self.__dict__[k], int):
818
- out |= self.__dict__[k]
819
- self.__dict__['All'] = out
820
-
821
- def count(self):
822
- return len(self._keys)
823
-
824
- def description(self, value):
825
- """Returns the description string for the provided value
826
- :param value: The binary value of the description you want
827
- """
828
- return self._descr.get(value, '')
829
-
830
- def matches(self, a, b): # noqa: N804
831
- """Does a binary and on a and b
832
- :param a: First item
833
- :param b: Second item
834
- :returns: boolean
835
- """
836
- return a & b != 0
837
-
838
- def hasKey(self, key):
839
- return key in self._keys
840
-
841
- def labels(self, byVal=False):
842
- """Returns a list of all provided parameters.
843
- :param byVal: Sorts the labels by their values. Defaults to False
844
- :returns: A list of labels as strings
845
- """
846
- if byVal:
847
- return [
848
- ' '.join(re.findall('[A-Z]+[^A-Z]*', key))
849
- for key in sorted(list(self.keys()), key=lambda i: getattr(self, i))
850
- ]
851
- return [' '.join(re.findall('[A-Z]+[^A-Z]*', key)) for key in self.keys()]
852
-
853
- def labelByValue(self, value):
854
- """Returns the label for a specific value. Labels automatically add spaces
855
- for every capital letter after the first.
856
- :param value: The value you want the label for
857
- """
858
- return ' '.join(re.findall('[A-Z]+[^A-Z]*', self.keyByValue(value)))
859
-
860
- def isValid(self, value):
861
- """Returns True if this value is stored in the parameters.
862
- :param value: The value to check
863
- :return: boolean. Is the value stored in a parameter.
864
- """
865
- return self.keyByValue(value) != ''
866
-
867
- def keyByIndex(self, index):
868
- """Finds the key based on a index. This index contains the *args in the order
869
- they were passed in then any **kwargs's keys in the order **kwargs.keys()
870
- returned. This index is created when the class is initialized.
871
-
872
- :param index: The index to lookup
873
- :returns: The key for the provided index or a empty string if it was not found.
874
- """
875
- if index in range(self.count()):
876
- return self._keys[index]
877
- return ''
878
-
879
- def keyByValue(self, value):
880
- """Return the parameter name for a specific value. If not found returns a empty string.
881
- :param value: The value to find the parameter name of.
882
- :returns: String. The parameter name or empty string.
883
- """
884
- for key in self._keys:
885
- if self.__dict__[key] == value:
886
- return key
887
- return ''
888
-
889
- def keys(self):
890
- """Returns a list of parameter names"""
891
- return self._keys
892
-
893
- def value(self, key, caseSensitive=True):
894
- """Return the value for a parameter name
895
- :param key: The key to get the value for
896
- :param caseSensitive: Defaults to True
897
- :returns: The value for the key, or zero if it was not found
898
- """
899
- if caseSensitive:
900
- return self.__dict__.get(str(key), 0)
901
- else:
902
- key = str(key).lower()
903
- for k in self.__dict__.keys():
904
- if k.lower() == key:
905
- return self.__dict__[k]
906
- return 0
907
-
908
- def values(self):
909
- """Returns a list of all values for stored parameters"""
910
- return [self.__dict__[key] for key in self.keys()]
911
-
912
- def valueByLabel(self, label, caseSensitive=True):
913
- """
914
- Return the binary value fromt the given label.
915
- :param label: The label you want the binary value of
916
- :param caseSensitive: Defaults to True
917
- :returns: the bindary value of the label as a int
918
- """
919
- return self.value(''.join(str(label).split(' ')), caseSensitive=caseSensitive)
920
-
921
- def valueByIndex(self, index):
922
- """Returns the stored value for the index of a parameter.
923
- .. seealso:: :meth:`keyByValue`
924
- .. seealso:: :meth:`value`
925
- """
926
- return self.value(self.keyByIndex(index))
927
-
928
- def index(self, key):
929
- """Return the index for a key.
930
- :param key: The key to find the index for
931
- :returns: Int, The index for the key or -1
932
- .. seealso:: :meth:`keyByValue`
933
- """
934
- if key in self._keys:
935
- return self._keys.index(key)
936
- return -1
937
-
938
- def indexByValue(self, value):
939
- """Return the index for a value.
940
- :param value: The value to find the index for
941
- :returns: Int, the index of the value or -1
942
- .. seealso:: :meth:`keyByValue`
943
- """
944
- for index in range(len(self._keys)):
945
- if self.__dict__[self._keys[index]] == value:
946
- return index
947
- return -1
948
-
949
- def toString(self, value, default='None', sep=' '):
950
- """For the provided value return the parameter name(s) seperated by sep. If you
951
- provide a int that represents two or more binary values, it will return all
952
- parameter names that binary value represents seperated by sep. If no meaningful
953
- value is found it will return the provided default.
954
-
955
- :param value: The value to return parameter names of
956
- :param default: If no parameter were found this is returned. Defaults to 'None'
957
- :param sep: The parameters are joined by this value. Defaults to a space.
958
- :return: Returns a string of values or the provided default
959
- .. seealso:: :meth:`fromString`
960
- """
961
- parts = []
962
- for key in self._keys:
963
- if key not in self._compound and value & self.value(key):
964
- parts.append(key)
965
- if parts:
966
- return sep.join(parts)
967
- return default
968
-
969
- def fromString(self, labels, sep=' '):
970
- """Returns the value for a given string. This function binary or's the
971
- parameters, so it may not work well when using **kwargs
972
- :param labels: A string of parameter names.
973
- :param sep: The seperator used to seperate the provided parameters.
974
- :returns: The found value
975
- .. seealso:: :meth:`value`
976
- .. seealso:: :meth:`toString`
977
- """
978
- parts = str(labels).split(sep)
979
- value = 0
980
- for part in parts:
981
- value |= self.value(part)
982
- return value
983
-
984
- def setDescription(self, value, descr):
985
- """Used to set a description string for a value.
986
- :param value: The parameter value to set the description on
987
- :param descr: The description string to set on a parameter
988
- """
989
- self._descr[value] = descr
990
-
991
- matches = classmethod(matches)
992
-
993
-
994
- # =============================================================================
995
- # EXCEPTIONS
996
- # =============================================================================
997
-
998
-
999
- class InstantiationError(Exception):
1000
- pass
1001
-
1002
-
1003
- # =============================================================================
1
+ from __future__ import absolute_import
2
+
3
+ import abc
4
+ import re
5
+ from builtins import str as text
6
+ from numbers import Number
7
+
8
+ from future.utils import iteritems, with_metaclass
9
+ from past.builtins import long
10
+
11
+ # =============================================================================
12
+ # CLASSES
13
+ # =============================================================================
14
+
15
+
16
+ class _MetaEnumGroup(type):
17
+ """An EnumGroup metaclass."""
18
+
19
+ def __new__(cls, className, bases, classDict): # noqa: B902
20
+ newCls = type.__new__(cls, className, bases, classDict)
21
+ newCls.__init_enums__()
22
+ newCls._cls = cls
23
+ newCls._clsName = className
24
+ newCls._clsBases = bases
25
+ newCls._clsDict = classDict
26
+ return newCls
27
+
28
+ def __call__(cls, number):
29
+ number = int(number)
30
+ e = cls.Nothing
31
+ for enum in cls._ENUMERATORS:
32
+ if enum & number:
33
+ if e:
34
+ e = e | enum
35
+ else:
36
+ e = enum
37
+ return e
38
+
39
+ def __getitem__(cls, key):
40
+ if isinstance(key, Number):
41
+ return list(cls)[int(key)]
42
+ elif isinstance(key, slice):
43
+ # If a Enum is passed convert it to its labelIndex
44
+ start = key.start
45
+ stop = key.stop
46
+ if isinstance(start, Enum):
47
+ start = start.labelIndex
48
+ if isinstance(stop, Enum):
49
+ stop = stop.labelIndex
50
+ return list(cls)[slice(start, stop, key.step)]
51
+ else:
52
+ return getattr(cls, str(key))
53
+
54
+ def __instancecheck__(cls, inst):
55
+ if type(inst) == cls:
56
+ return True
57
+ if isinstance(inst, cls._cls):
58
+ return True
59
+ return False
60
+
61
+ def __iter__(cls):
62
+ for e in cls._ENUMERATORS:
63
+ yield e
64
+
65
+ def __len__(cls):
66
+ return len(cls._ENUMERATORS)
67
+
68
+ def __repr__(cls):
69
+ return '<{mdl}.{cls}({enums})>'.format(
70
+ mdl=cls._clsDict.get('__module__', 'unknown'),
71
+ cls=cls._clsName,
72
+ enums=cls.join(),
73
+ )
74
+
75
+ def __str__(cls):
76
+ return '{0}({1})'.format(cls._clsName, cls.join())
77
+
78
+
79
+ # =============================================================================
80
+
81
+
82
+ class Enum(with_metaclass(abc.ABCMeta, object)):
83
+ """A basic enumerator class.
84
+
85
+ Enumerators are named values that act as identifiers. Typically, a
86
+ list of enumerators are component pieces of an `EnumGroup`.
87
+
88
+ Example::
89
+
90
+ class Suit(Enum):
91
+ pass
92
+
93
+ class Suits(EnumGroup):
94
+ Hearts = Suit()
95
+ Spades = Suit()
96
+ Clubs = Suit()
97
+ Diamonds = Suit()
98
+
99
+ Enum objects can be combined and compared using binary "and" and "or"
100
+ operations.
101
+
102
+ Example::
103
+
104
+ mySuits = Suits.Hearts | Suits.Spades
105
+
106
+ if Suits.Hearts & mySuits:
107
+ print("This is true!")
108
+
109
+ if Suits.Clubs & mySuits:
110
+ print("This is false!")
111
+
112
+ Attributes:
113
+ name: The name of the enumerator.
114
+ number: The integer value representation of the enumerator.
115
+ label: The enumerator's label.
116
+ labelIndex: The enumerator's index within its parent EnumGroup.
117
+ """
118
+
119
+ _CREATIONORDER = 0
120
+
121
+ def __init__(self, number=None, label=None, **kwargs):
122
+ """Initializes a new Enum object.
123
+
124
+ In addition to the named arguments listed below, keyword arguments
125
+ may be given that will be set as attributes on the Enum.
126
+
127
+ Args:
128
+ number(int): The integer representation of the Enum. The default
129
+ is to have this number determined dynamically based on its
130
+ place with the parent EnumGroup.
131
+ label(str): The Enum's label. The default is to inherit the
132
+ attribute name the Enum is associated with in its parent
133
+ EnumGroup.
134
+ """
135
+ self._creationOrder = Enum._CREATIONORDER
136
+ Enum._CREATIONORDER += 1
137
+ self._name = None
138
+ self._number = number
139
+ self._label = label
140
+ self._labelIndex = None
141
+ self._cmpLabel = None
142
+ self._cmpName = None
143
+ self._enumGroup = None
144
+ if kwargs:
145
+ self.__dict__.update(kwargs)
146
+
147
+ @property
148
+ def name(self):
149
+ """The name of the Enum."""
150
+ return self._name
151
+
152
+ @property
153
+ def number(self):
154
+ """The number representation of the Enum."""
155
+ return self._number
156
+
157
+ @property
158
+ def label(self):
159
+ """The Enum's label."""
160
+ return self._label
161
+
162
+ @property
163
+ def labelIndex(self):
164
+ """The Enum's index within its parent EnumGroup."""
165
+ return self._labelIndex
166
+
167
+ def _setName(self, name):
168
+ if name is None:
169
+ self._name = None
170
+ self._cmpName = None
171
+ else:
172
+ self._name = name
173
+ self._cmpName = name.strip('_ ')
174
+
175
+ def _setLabel(self, label):
176
+ if label is None:
177
+ self._label = None
178
+ self._cmpLabel = None
179
+ else:
180
+ self._label = label
181
+ self._cmpLabel = label.replace(' ', '').replace('_', '')
182
+
183
+ def __add__(self, other):
184
+ return self.__or__(other)
185
+
186
+ def __and__(self, other):
187
+ if isinstance(other, Enum):
188
+ other = int(other)
189
+ return int(self) & other
190
+
191
+ def __call__(self):
192
+ return int(self)
193
+
194
+ def __cmp__(self, value):
195
+ if not isinstance(value, Enum):
196
+ return -1
197
+ return self.number - value.number
198
+
199
+ def __lt__(self, value):
200
+ return self.__cmp__(value) < 0
201
+
202
+ def __eq__(self, value):
203
+ if value is None:
204
+ return False
205
+ if isinstance(value, Enum):
206
+ return self.number == value.number
207
+ if isinstance(value, (int, long)):
208
+ return self.number == value
209
+ if isinstance(value, str) or isinstance(value, text):
210
+ if self._compareStr(value):
211
+ return True
212
+ return False
213
+
214
+ def __hash__(self):
215
+ return self.number
216
+
217
+ def __index__(self):
218
+ return self.number
219
+
220
+ def __int__(self):
221
+ return self.number or 0
222
+
223
+ def __invert__(self):
224
+ return ~int(self)
225
+
226
+ def __ne__(self, value):
227
+ return not self.__eq__(value)
228
+
229
+ def __nonzero__(self):
230
+ return bool(int(self))
231
+
232
+ def __or__(self, other):
233
+ o = other
234
+ if isinstance(other, Enum):
235
+ o = int(other)
236
+ # No need to return a CompositeEnum if one of these is Nothing
237
+ if o == 0:
238
+ return self
239
+ v = int(self)
240
+ if v == 0:
241
+ return other
242
+ value = v | o
243
+ label = '{0} {1}'.format(str(self), str(other))
244
+ name = '{0}_{1}'.format(str(self), str(other))
245
+
246
+ class CompositeEnum(Enum):
247
+ def __init__(ss, number, lbl, name): # noqa: N805,B902
248
+ super(CompositeEnum, ss).__init__(number, lbl)
249
+ ss._name = name
250
+
251
+ # Register our composite enum class as a virtual
252
+ # subclass of this enum's class, plus the same for
253
+ # the other enum if it's an Enum object. This
254
+ # will make the composite enum isinstance check true
255
+ # against both.
256
+ type(self).register(CompositeEnum)
257
+ if isinstance(other, Enum):
258
+ type(other).register(CompositeEnum)
259
+ return CompositeEnum(value, label, name)
260
+
261
+ def __rand__(self, other):
262
+ if isinstance(other, Enum):
263
+ other = int(other)
264
+ return other & int(self)
265
+
266
+ def __repr__(self):
267
+ return '<{mdl}.{cls}.{name}>'.format(
268
+ mdl=self.__class__.__module__,
269
+ cls=self.__class__.__name__,
270
+ name=str(self.name),
271
+ )
272
+
273
+ def __ror__(self, other):
274
+ return self | other
275
+
276
+ def __rxor__(self, other):
277
+ return self ^ other
278
+
279
+ def __str__(self):
280
+ if self.name:
281
+ return self.name
282
+ return self.label or ''
283
+
284
+ def __xor__(self, other):
285
+ if isinstance(other, Enum):
286
+ other = int(other)
287
+ return int(self) ^ other
288
+
289
+ def _compareStr(self, inStr):
290
+ return inStr.replace(' ', '').replace('_', '') in (
291
+ self._cmpLabel,
292
+ self._cmpName,
293
+ )
294
+
295
+
296
+ # =============================================================================
297
+
298
+
299
+ class EnumGroup(with_metaclass(_MetaEnumGroup, object)):
300
+ """A container class for collecting, organizing, and accessing Enums.
301
+
302
+ An EnumGroup class is a container for Enum objects. It provides
303
+ organizational convenience, and in most cases handles the generation
304
+ and assignment of Enum numbers, names, and labels.
305
+
306
+ Example::
307
+
308
+ class Suit(Enum):
309
+ pass
310
+
311
+ class Suits(EnumGroup):
312
+ Hearts = Suit()
313
+ Spades = Suit()
314
+ Clubs = Suit()
315
+ Diamonds = Suit()
316
+
317
+ The above example outlines defining an enumerator, and grouping
318
+ four of them inside of a group. This provides a number of things,
319
+ including references by attribute, name, and index. Also provided
320
+ is an "All" attribute, if one is not explicitly assigned, it will be
321
+ a CompositeEnum of all the defined enums, and compare true against
322
+ any members of the group via the binary "and" operator. Also provided
323
+ is an "Nothing" attribute, if one is not explicitly assigned, it
324
+ compares false against any members of the group and when converted to
325
+ a int its value will be zero.
326
+
327
+ Example::
328
+
329
+ # By attribute.
330
+ Suits.Hearts
331
+
332
+ # By name.
333
+ Suits['Hearts']
334
+
335
+ suitList = list(Suits)
336
+
337
+ if Suits.Hearts & Suits.All:
338
+ print("This is true!")
339
+
340
+ You can also pass a int value as a index lookup. If you pass a int value it
341
+ will return the object by its index. This means you can not lookup composite
342
+ Enum objects as 3 returns the third index which in the above example is Diamonds.
343
+ The index value for Enum is stored on its labelIndex property.
344
+
345
+ Example::
346
+
347
+ print(Suits.Diamonds.labelIndex)
348
+
349
+ if Suits.Diamonds == Suits[3]:
350
+ print("This is true!")
351
+
352
+ An EnumGroup can be sliced by passing an Enum object or its labelIndex value for
353
+ start and stop, returning a list of matching Enums.
354
+
355
+ Example::
356
+
357
+ # All Enums between Spades and Diamonds
358
+ Suits[Suits.Spades:Suits.Diamonds]
359
+
360
+ # All Enums between Spades and Clubs including Clubs
361
+ Suits[Suits.Spades:Suits.Clubs.labelIndex+1]
362
+
363
+ An EnumGroup can also act as a factory for composite Enum objects.
364
+ If a known composite value is available, like 3, which is the
365
+ combination of enum values 1 and 2, a composite Enum object can
366
+ be constructed.
367
+
368
+ Example::
369
+
370
+ comp = Suits(3)
371
+
372
+ if Suits.Hearts & comp:
373
+ print("This is true!")
374
+
375
+ if Suits.Clubs & comp:
376
+ print("This is false!")
377
+
378
+ If one of the Enum's has the default keyword argument set to True, then that Enum
379
+ is also exposed as the "Default" attribute. Additionally all other Enum's will have
380
+ a default property added and set to False.
381
+
382
+ Example::
383
+
384
+ class Suits(EnumGroup):
385
+ Hearts = Suit()
386
+ Spades = Suit(default=True)
387
+
388
+ assert Suits.Hearts.default == False
389
+ assert Suits.Spades.default == True
390
+ assert Suits.Default == Suits.Spades
391
+
392
+ Attributes:
393
+ All: The sum of all members.
394
+ Nothing: None of the members.
395
+ """
396
+
397
+ _ENUMERATORS = None
398
+ _copyCount = 1
399
+ All = 0
400
+ Nothing = 0
401
+
402
+ def __init__(self):
403
+ raise InstantiationError('Unable to instantiate static class EnumGroup.')
404
+
405
+ @classmethod
406
+ def append(cls, *args, **kwargs):
407
+ """Appends additional enumerators to the EnumGroup.
408
+
409
+ New members can be provided as ordered arguments where the
410
+ each Enum's label is used to determine the attribute name, or
411
+ by keyword arguments where the key is the attribute name and
412
+ the Enum is the value. When using an Enum's label to determine
413
+ its name, any spaces in the label will be converted to underscores.
414
+
415
+ Example:
416
+ Suits.append(Suit(None, 'Funky'), Foo=Suit())
417
+
418
+ # The "Funky" and "Foo" suits are now available.
419
+ Suits.Funky
420
+ Suits.Foo
421
+
422
+ Raises:
423
+ ValueError
424
+ """
425
+ if [e for e in (list(args) + list(kwargs.values())) if not isinstance(e, Enum)]:
426
+ raise ValueError('Given items must be of class Enum.')
427
+ if [e for e in args if not e.label]:
428
+ raise ValueError('Enums given as ordered arguments must have a label.')
429
+ for e in args:
430
+ setattr(cls, cls._labelToVarName(e.label), e)
431
+ for n, e in iteritems(kwargs):
432
+ setattr(cls, n, e)
433
+ # reset All and Nothing -- this is necessary so that All is regenerated
434
+ # and so that Nothing is not included when finding the member Enums.
435
+ cls.All = 0
436
+ cls.Nothing = 0
437
+ cls.__init_enums__()
438
+
439
+ @classmethod
440
+ def copy(cls, name=None):
441
+ """Returns a new class type from this class without any Enums assigned.
442
+
443
+ If name is not provided it will automatically generate a new class name.
444
+ For example if the EnumGroup class named DefaultEnums has been copied
445
+ twice the new class name will be "DefaultEnums_3".
446
+ If you provide name it will not check for duplicates.
447
+
448
+ Args:
449
+ name (str|None): The name to give the new class. Defaults to None
450
+
451
+ Returns:
452
+ EnumGroup: A new Class type.
453
+ """
454
+ if not name:
455
+ # Generate a unique name for the class if one was not provided
456
+ name = '{name}_{count}'.format(name=cls.__name__, count=cls._copyCount)
457
+ cls._copyCount += 1
458
+ return type(name, cls.__bases__, dict(cls.__dict__))
459
+
460
+ @classmethod
461
+ def fromLabel(cls, label, default=None):
462
+ """Gets an enumerator based on the given label.
463
+
464
+ If a default is provided and is not None, that value will be returned
465
+ in the event that the given label does not exist in the EnumGroup. If
466
+ no default is provided, a ValueError is raised.
467
+
468
+ Args:
469
+ label(str): The label to look up.
470
+ default(*): The default value to return if the label is not found.
471
+
472
+ Raises:
473
+ ValueError: Raised if default is None and the given label does not
474
+ exist in the EnumGroup.
475
+
476
+ Returns:
477
+ Enum
478
+ """
479
+ label = str(label)
480
+ for e in cls._ENUMERATORS:
481
+ if e.label == label:
482
+ return e
483
+ if default is not None:
484
+ return default
485
+ raise ValueError('No enumerators exist with the given label.')
486
+
487
+ @classmethod
488
+ def fromValue(cls, value, default=None, allowComposite=False):
489
+ """Gets an enumerator based on the given value.
490
+
491
+ If a default is provided and is not None, that value will be returned
492
+ in the event that the given label does not exist in the EnumGroup. If
493
+ no default is provided, a ValueError is raised.
494
+
495
+ Args:
496
+ value (int): The value to look up.
497
+ default (*): The default value to return if the label is not found.
498
+ allowComposite (bool, optional): If True a composite enums will be
499
+ created when provided a value that is the sum of multiple enum
500
+ values. Otherwise, a ValueError will be raised. Defaults to
501
+ False.
502
+
503
+ Returns:
504
+ Enum
505
+
506
+ Raises:
507
+ ValueError: Raised if default is None and the given label does not
508
+ exist in the EnumGroup.
509
+ """
510
+ value = int(value)
511
+ composite = None
512
+ for e in cls._ENUMERATORS:
513
+ eVal = int(e)
514
+ if eVal == value:
515
+ return e
516
+ if allowComposite and eVal & value:
517
+ composite = e if composite is None else (composite | e)
518
+ if composite is not None and int(composite) == value:
519
+ return composite
520
+ if default is not None:
521
+ return default
522
+ raise ValueError('No enumerators exist with the given value.')
523
+
524
+ @classmethod
525
+ def join(cls, include=None, separator=','):
526
+ """Joins all child Enums together into a single string.
527
+
528
+ The string representation of each Enum is joined using the
529
+ given separator.
530
+
531
+ Args:
532
+ include(int|Enum): Only enumerators that compare via bitwise "and" against
533
+ the given int or Enum will be returned. Default is EnumGroup.All.
534
+ separator(str): The separator to use. Default is ",".
535
+
536
+ Returns:
537
+ str: The joined enumerators.
538
+ """
539
+ include = include is None and cls.All or include
540
+ return str(separator).join(
541
+ [str(e) for e in cls._ENUMERATORS if e & int(include)]
542
+ )
543
+
544
+ @classmethod
545
+ def labels(cls):
546
+ """A generator containing all Enum labels in the EnumGroup."""
547
+ return (e.label for e in cls._ENUMERATORS)
548
+
549
+ @classmethod
550
+ def names(cls):
551
+ """A generator containing all Enum names in the EnumGroup."""
552
+ return (e.name for e in cls._ENUMERATORS)
553
+
554
+ @classmethod
555
+ def split(cls, string, separator=','):
556
+ """Splits the given string and returns the corresponding Enums.
557
+
558
+ The string is split using the provided separator, and all names
559
+ contained within must be attributes of the EnumGroup class that
560
+ is performing the split.
561
+
562
+ Args:
563
+ string(str): The string containing the desired Enum names.
564
+ separator(str): The separator to split on. Default is ','.
565
+
566
+ Raises:
567
+ AttributeError
568
+
569
+ Returns:
570
+ list(Enum, ...): The list of resulting Enum objects.
571
+ """
572
+ names = str(string).split(str(separator))
573
+ return [getattr(cls, n) for n in names]
574
+
575
+ @classmethod
576
+ def values(cls):
577
+ """A generator containing all Enum values in the EnumGroup."""
578
+ return (int(e) for e in cls._ENUMERATORS)
579
+
580
+ @classmethod
581
+ def __init_enums__(cls):
582
+ enums = []
583
+ default_enum = None
584
+
585
+ orderedEnums = sorted(
586
+ [
587
+ (k, v)
588
+ for k, v in iteritems(cls.__dict__)
589
+ if isinstance(v, Enum) and k not in ('All', 'Nothing')
590
+ ],
591
+ key=lambda i: i[1]._creationOrder,
592
+ )
593
+ for name, value in orderedEnums:
594
+ enums.append(value)
595
+ value._enumGroup = cls
596
+ value._setName(name)
597
+ if value.label is None:
598
+ value._setLabel(cls._varNameToLabel(name))
599
+ # Check for a default property and raise a error if more than one is found
600
+ if hasattr(value, 'default') and value.default:
601
+ if default_enum is not None:
602
+ raise ValueError(
603
+ (
604
+ '"{}" already defines default and "{}" is trying to '
605
+ 'claim the default'
606
+ ).format(default_enum, value)
607
+ )
608
+ default_enum = value
609
+
610
+ enumNumbers = [enum.number for enum in enums if enum.number]
611
+ num = 1
612
+ for enum in enums:
613
+ if enum._number is None:
614
+ while num in enumNumbers:
615
+ num *= 2
616
+ enum._number = num
617
+ enumNumbers.append(num)
618
+ enums.sort()
619
+ labelIndex = 0
620
+ for enum in enums:
621
+ if enum._label is not None:
622
+ enum._labelIndex = labelIndex
623
+ labelIndex += 1
624
+ # Add a default property to all enums for consistency
625
+ if default_enum and not hasattr(enum, 'default'):
626
+ enum.default = False
627
+ cls._ENUMERATORS = enums
628
+ # Build the All object if its not defined
629
+ if isinstance(cls.All, int):
630
+ for e in enums:
631
+ if isinstance(cls.All, int):
632
+ cls.All = e
633
+ else:
634
+ cls.All |= e
635
+ # Build the Nothing object if its not defined
636
+ if isinstance(cls.Nothing, int) and enums:
637
+ processed = set()
638
+ for i, enum in enumerate(enums):
639
+ enumClass = enum.__class__
640
+ if i == 0:
641
+ # Create the Nothing instance from the first class type
642
+ cls.Nothing = enumClass(0, 'Nothing')
643
+ elif enumClass not in processed:
644
+ # Register our Nothing enum's class as a virtual
645
+ # subclass of any additional enum classes. This
646
+ # will make the Nothing enum isinstance check true
647
+ # against all Enums in this EnumGroup.
648
+ enumClass.register(cls.Nothing.__class__)
649
+ processed.add(enumClass)
650
+ # If a default was specified, store it on the Default argument
651
+ if default_enum and not hasattr(cls, 'Default'):
652
+ cls.Default = default_enum
653
+ # Ensure the All and Nothing Enum's have a default as well
654
+ cls.All.default = False
655
+ if enums:
656
+ cls.Nothing.default = False
657
+
658
+ @classmethod
659
+ def _varNameToLabel(cls, varName):
660
+ label = str(varName)
661
+ label = ' '.join(re.findall('[A-Z]+[^A-Z]*', label))
662
+ label = re.sub(r'[_\s]+', ' ', label)
663
+ return label
664
+
665
+ @classmethod
666
+ def _labelToVarName(cls, label):
667
+ name = str(label)
668
+ name = re.sub(r'\s+', '_', name)
669
+ return name
670
+
671
+
672
+ # =============================================================================
673
+ class Incrementer(object):
674
+ """A class that behaves similarly to c i++ or ++i.
675
+
676
+ Once you init this class, every time you call it it will update count and return the
677
+ previous value like c's i++. If you pass True to pre, it will increment then return
678
+ the new value like c's ++i.
679
+
680
+ Args:
681
+ start (int): Start the counter at this value. Defaults to Zero.
682
+
683
+ increment (int): increment by this value. In most cases it should be 1 or -1.
684
+ Defaults to one.
685
+
686
+ pre (bool): If true calling the object will return the incremented value. If
687
+ False it will return the current value and increment for the next call.
688
+ Defaults to False.
689
+
690
+ Attributes:
691
+ count: The current value.
692
+ increment: The incremnt added to count
693
+ pre: Should it preform a ++i or i++ operation when called.
694
+ """
695
+
696
+ def __init__(self, start=0, increment=1, pre=False):
697
+ super(Incrementer, self).__init__()
698
+ self.count = start
699
+ self.increment = increment
700
+ self.pre = pre
701
+
702
+ def __call__(self):
703
+ if self.pre:
704
+ self.count += self.increment
705
+ return self.count
706
+ ret = self.count
707
+ self.count += self.increment
708
+ return ret
709
+
710
+ def __repr__(self):
711
+ return '{}.{}(start={}, increment={}, pre={!r})'.format(
712
+ self.__module__, type(self).__name__, self.count, self.increment, self.pre
713
+ )
714
+
715
+ def __str__(self):
716
+ return str(self.count)
717
+
718
+
719
+ # =============================================================================
720
+ # EXCEPTIONS
721
+ # =============================================================================
722
+
723
+
724
+ class InstantiationError(Exception):
725
+ pass
726
+
727
+
728
+ # =============================================================================