hspylib-clitt 0.9.120__py3-none-any.whl → 0.9.121__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 hspylib-clitt might be problematic. Click here for more details.

Files changed (266) hide show
  1. clitt/.version +1 -1
  2. clitt/__init__.py +3 -3
  3. clitt/addons/__init__.py +3 -3
  4. clitt/addons/appman/__init__.py +3 -3
  5. clitt/addons/appman/templates/__init__.py +3 -3
  6. clitt/addons/widman/__init__.py +3 -3
  7. clitt/addons/widman/widgets/__init__.py +3 -3
  8. clitt/core/__init__.py +3 -3
  9. clitt/core/exception/__init__.py +3 -3
  10. clitt/core/icons/__init__.py +3 -3
  11. clitt/core/icons/emojis/__init__.py +3 -3
  12. clitt/core/icons/font_awesome/__init__.py +3 -3
  13. clitt/core/term/__init__.py +3 -3
  14. clitt/core/tui/__init__.py +3 -3
  15. clitt/core/tui/line_input/__init__.py +3 -3
  16. clitt/core/tui/line_input/keyboard_input.py +70 -63
  17. clitt/core/tui/mchoose/__init__.py +3 -3
  18. clitt/core/tui/mdashboard/__init__.py +3 -3
  19. clitt/core/tui/menu/__init__.py +3 -3
  20. clitt/core/tui/minput/__init__.py +3 -3
  21. clitt/core/tui/minput/menu_input.py +7 -15
  22. clitt/core/tui/mselect/__init__.py +3 -3
  23. clitt/core/tui/table/__init__.py +3 -3
  24. clitt/utils/__init__.py +3 -3
  25. {hspylib_clitt-0.9.120.dist-info → hspylib_clitt-0.9.121.dist-info}/METADATA +2 -2
  26. hspylib_clitt-0.9.121.dist-info/RECORD +97 -0
  27. {hspylib_clitt-0.9.120.dist-info → hspylib_clitt-0.9.121.dist-info}/top_level.txt +0 -1
  28. build/lib/build/lib/build/lib/clitt/__classpath__.py +0 -28
  29. build/lib/build/lib/build/lib/clitt/__init__.py +0 -13
  30. build/lib/build/lib/build/lib/clitt/__main__.py +0 -139
  31. build/lib/build/lib/build/lib/clitt/addons/__init__.py +0 -12
  32. build/lib/build/lib/build/lib/clitt/addons/appman/__init__.py +0 -13
  33. build/lib/build/lib/build/lib/clitt/addons/appman/appman.py +0 -305
  34. build/lib/build/lib/build/lib/clitt/addons/appman/appman_enums.py +0 -39
  35. build/lib/build/lib/build/lib/clitt/addons/appman/templates/__init__.py +0 -11
  36. build/lib/build/lib/build/lib/clitt/addons/widman/__init__.py +0 -14
  37. build/lib/build/lib/build/lib/clitt/addons/widman/widget.py +0 -70
  38. build/lib/build/lib/build/lib/clitt/addons/widman/widget_entry.py +0 -54
  39. build/lib/build/lib/build/lib/clitt/addons/widman/widgets/__init__.py +0 -14
  40. build/lib/build/lib/build/lib/clitt/addons/widman/widgets/widget_free.py +0 -110
  41. build/lib/build/lib/build/lib/clitt/addons/widman/widgets/widget_punch.py +0 -246
  42. build/lib/build/lib/build/lib/clitt/addons/widman/widgets/widget_send_msg.py +0 -272
  43. build/lib/build/lib/build/lib/clitt/addons/widman/widgets/widget_time_calc.py +0 -146
  44. build/lib/build/lib/build/lib/clitt/addons/widman/widman.py +0 -123
  45. build/lib/build/lib/build/lib/clitt/core/__init__.py +0 -15
  46. build/lib/build/lib/build/lib/clitt/core/exception/__init__.py +0 -11
  47. build/lib/build/lib/build/lib/clitt/core/exception/exceptions.py +0 -19
  48. build/lib/build/lib/build/lib/clitt/core/icons/__init__.py +0 -12
  49. build/lib/build/lib/build/lib/clitt/core/icons/emojis/__init__.py +0 -12
  50. build/lib/build/lib/build/lib/clitt/core/icons/emojis/emojis.py +0 -41
  51. build/lib/build/lib/build/lib/clitt/core/icons/emojis/face_smiling.py +0 -40
  52. build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/__init__.py +0 -18
  53. build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/app_icons.py +0 -55
  54. build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/awesome.py +0 -76
  55. build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/dashboard_icons.py +0 -93
  56. build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/form_icons.py +0 -69
  57. build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/game_icons.py +0 -59
  58. build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/nav_icons.py +0 -42
  59. build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/trickplay_icons.py +0 -39
  60. build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/widget_icons.py +0 -37
  61. build/lib/build/lib/build/lib/clitt/core/preferences.py +0 -87
  62. build/lib/build/lib/build/lib/clitt/core/term/__init__.py +0 -14
  63. build/lib/build/lib/build/lib/clitt/core/term/commons.py +0 -106
  64. build/lib/build/lib/build/lib/clitt/core/term/cursor.py +0 -174
  65. build/lib/build/lib/build/lib/clitt/core/term/screen.py +0 -106
  66. build/lib/build/lib/build/lib/clitt/core/term/terminal.py +0 -202
  67. build/lib/build/lib/build/lib/clitt/core/tui/__init__.py +0 -20
  68. build/lib/build/lib/build/lib/clitt/core/tui/line_input/__init__.py +0 -12
  69. build/lib/build/lib/build/lib/clitt/core/tui/line_input/keyboard_input.py +0 -229
  70. build/lib/build/lib/build/lib/clitt/core/tui/line_input/line_input.py +0 -31
  71. build/lib/build/lib/build/lib/clitt/core/tui/mchoose/__init__.py +0 -12
  72. build/lib/build/lib/build/lib/clitt/core/tui/mchoose/mchoose.py +0 -43
  73. build/lib/build/lib/build/lib/clitt/core/tui/mchoose/menu_choose.py +0 -192
  74. build/lib/build/lib/build/lib/clitt/core/tui/mdashboard/__init__.py +0 -14
  75. build/lib/build/lib/build/lib/clitt/core/tui/mdashboard/dashboard_builder.py +0 -54
  76. build/lib/build/lib/build/lib/clitt/core/tui/mdashboard/dashboard_item.py +0 -31
  77. build/lib/build/lib/build/lib/clitt/core/tui/mdashboard/mdashboard.py +0 -26
  78. build/lib/build/lib/build/lib/clitt/core/tui/mdashboard/menu_dashboard.py +0 -148
  79. build/lib/build/lib/build/lib/clitt/core/tui/menu/__init__.py +0 -16
  80. build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu.py +0 -111
  81. build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu_action.py +0 -47
  82. build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu_factory.py +0 -117
  83. build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu_item.py +0 -196
  84. build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu_ui.py +0 -98
  85. build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu_view.py +0 -57
  86. build/lib/build/lib/build/lib/clitt/core/tui/minput/__init__.py +0 -19
  87. build/lib/build/lib/build/lib/clitt/core/tui/minput/access_type.py +0 -26
  88. build/lib/build/lib/build/lib/clitt/core/tui/minput/field_builder.py +0 -117
  89. build/lib/build/lib/build/lib/clitt/core/tui/minput/form_builder.py +0 -72
  90. build/lib/build/lib/build/lib/clitt/core/tui/minput/form_field.py +0 -180
  91. build/lib/build/lib/build/lib/clitt/core/tui/minput/input_type.py +0 -30
  92. build/lib/build/lib/build/lib/clitt/core/tui/minput/input_validator.py +0 -98
  93. build/lib/build/lib/build/lib/clitt/core/tui/minput/menu_input.py +0 -292
  94. build/lib/build/lib/build/lib/clitt/core/tui/minput/minput.py +0 -44
  95. build/lib/build/lib/build/lib/clitt/core/tui/minput/minput_utils.py +0 -156
  96. build/lib/build/lib/build/lib/clitt/core/tui/mselect/__init__.py +0 -12
  97. build/lib/build/lib/build/lib/clitt/core/tui/mselect/menu_select.py +0 -170
  98. build/lib/build/lib/build/lib/clitt/core/tui/mselect/mselect.py +0 -36
  99. build/lib/build/lib/build/lib/clitt/core/tui/table/__init__.py +0 -12
  100. build/lib/build/lib/build/lib/clitt/core/tui/table/table_enums.py +0 -47
  101. build/lib/build/lib/build/lib/clitt/core/tui/table/table_renderer.py +0 -339
  102. build/lib/build/lib/build/lib/clitt/core/tui/tui_application.py +0 -52
  103. build/lib/build/lib/build/lib/clitt/core/tui/tui_component.py +0 -154
  104. build/lib/build/lib/build/lib/clitt/core/tui/tui_preferences.py +0 -103
  105. build/lib/build/lib/build/lib/clitt/utils/__init__.py +0 -11
  106. build/lib/build/lib/build/lib/clitt/utils/git_utils.py +0 -66
  107. build/lib/build/lib/clitt/__classpath__.py +0 -28
  108. build/lib/build/lib/clitt/__init__.py +0 -13
  109. build/lib/build/lib/clitt/__main__.py +0 -139
  110. build/lib/build/lib/clitt/addons/__init__.py +0 -12
  111. build/lib/build/lib/clitt/addons/appman/__init__.py +0 -13
  112. build/lib/build/lib/clitt/addons/appman/appman.py +0 -305
  113. build/lib/build/lib/clitt/addons/appman/appman_enums.py +0 -39
  114. build/lib/build/lib/clitt/addons/appman/templates/__init__.py +0 -11
  115. build/lib/build/lib/clitt/addons/widman/__init__.py +0 -14
  116. build/lib/build/lib/clitt/addons/widman/widget.py +0 -70
  117. build/lib/build/lib/clitt/addons/widman/widget_entry.py +0 -54
  118. build/lib/build/lib/clitt/addons/widman/widgets/__init__.py +0 -14
  119. build/lib/build/lib/clitt/addons/widman/widgets/widget_free.py +0 -110
  120. build/lib/build/lib/clitt/addons/widman/widgets/widget_punch.py +0 -246
  121. build/lib/build/lib/clitt/addons/widman/widgets/widget_send_msg.py +0 -272
  122. build/lib/build/lib/clitt/addons/widman/widgets/widget_time_calc.py +0 -146
  123. build/lib/build/lib/clitt/addons/widman/widman.py +0 -123
  124. build/lib/build/lib/clitt/core/__init__.py +0 -15
  125. build/lib/build/lib/clitt/core/exception/__init__.py +0 -11
  126. build/lib/build/lib/clitt/core/exception/exceptions.py +0 -19
  127. build/lib/build/lib/clitt/core/icons/__init__.py +0 -12
  128. build/lib/build/lib/clitt/core/icons/emojis/__init__.py +0 -12
  129. build/lib/build/lib/clitt/core/icons/emojis/emojis.py +0 -41
  130. build/lib/build/lib/clitt/core/icons/emojis/face_smiling.py +0 -40
  131. build/lib/build/lib/clitt/core/icons/font_awesome/__init__.py +0 -18
  132. build/lib/build/lib/clitt/core/icons/font_awesome/app_icons.py +0 -55
  133. build/lib/build/lib/clitt/core/icons/font_awesome/awesome.py +0 -76
  134. build/lib/build/lib/clitt/core/icons/font_awesome/dashboard_icons.py +0 -93
  135. build/lib/build/lib/clitt/core/icons/font_awesome/form_icons.py +0 -69
  136. build/lib/build/lib/clitt/core/icons/font_awesome/game_icons.py +0 -59
  137. build/lib/build/lib/clitt/core/icons/font_awesome/nav_icons.py +0 -42
  138. build/lib/build/lib/clitt/core/icons/font_awesome/trickplay_icons.py +0 -39
  139. build/lib/build/lib/clitt/core/icons/font_awesome/widget_icons.py +0 -37
  140. build/lib/build/lib/clitt/core/preferences.py +0 -87
  141. build/lib/build/lib/clitt/core/term/__init__.py +0 -14
  142. build/lib/build/lib/clitt/core/term/commons.py +0 -106
  143. build/lib/build/lib/clitt/core/term/cursor.py +0 -174
  144. build/lib/build/lib/clitt/core/term/screen.py +0 -106
  145. build/lib/build/lib/clitt/core/term/terminal.py +0 -202
  146. build/lib/build/lib/clitt/core/tui/__init__.py +0 -20
  147. build/lib/build/lib/clitt/core/tui/line_input/__init__.py +0 -12
  148. build/lib/build/lib/clitt/core/tui/line_input/keyboard_input.py +0 -229
  149. build/lib/build/lib/clitt/core/tui/line_input/line_input.py +0 -31
  150. build/lib/build/lib/clitt/core/tui/mchoose/__init__.py +0 -12
  151. build/lib/build/lib/clitt/core/tui/mchoose/mchoose.py +0 -43
  152. build/lib/build/lib/clitt/core/tui/mchoose/menu_choose.py +0 -192
  153. build/lib/build/lib/clitt/core/tui/mdashboard/__init__.py +0 -14
  154. build/lib/build/lib/clitt/core/tui/mdashboard/dashboard_builder.py +0 -54
  155. build/lib/build/lib/clitt/core/tui/mdashboard/dashboard_item.py +0 -31
  156. build/lib/build/lib/clitt/core/tui/mdashboard/mdashboard.py +0 -26
  157. build/lib/build/lib/clitt/core/tui/mdashboard/menu_dashboard.py +0 -148
  158. build/lib/build/lib/clitt/core/tui/menu/__init__.py +0 -16
  159. build/lib/build/lib/clitt/core/tui/menu/tui_menu.py +0 -111
  160. build/lib/build/lib/clitt/core/tui/menu/tui_menu_action.py +0 -47
  161. build/lib/build/lib/clitt/core/tui/menu/tui_menu_factory.py +0 -117
  162. build/lib/build/lib/clitt/core/tui/menu/tui_menu_item.py +0 -196
  163. build/lib/build/lib/clitt/core/tui/menu/tui_menu_ui.py +0 -98
  164. build/lib/build/lib/clitt/core/tui/menu/tui_menu_view.py +0 -57
  165. build/lib/build/lib/clitt/core/tui/minput/__init__.py +0 -19
  166. build/lib/build/lib/clitt/core/tui/minput/access_type.py +0 -26
  167. build/lib/build/lib/clitt/core/tui/minput/field_builder.py +0 -117
  168. build/lib/build/lib/clitt/core/tui/minput/form_builder.py +0 -72
  169. build/lib/build/lib/clitt/core/tui/minput/form_field.py +0 -180
  170. build/lib/build/lib/clitt/core/tui/minput/input_type.py +0 -30
  171. build/lib/build/lib/clitt/core/tui/minput/input_validator.py +0 -98
  172. build/lib/build/lib/clitt/core/tui/minput/menu_input.py +0 -292
  173. build/lib/build/lib/clitt/core/tui/minput/minput.py +0 -44
  174. build/lib/build/lib/clitt/core/tui/minput/minput_utils.py +0 -156
  175. build/lib/build/lib/clitt/core/tui/mselect/__init__.py +0 -12
  176. build/lib/build/lib/clitt/core/tui/mselect/menu_select.py +0 -170
  177. build/lib/build/lib/clitt/core/tui/mselect/mselect.py +0 -36
  178. build/lib/build/lib/clitt/core/tui/table/__init__.py +0 -12
  179. build/lib/build/lib/clitt/core/tui/table/table_enums.py +0 -47
  180. build/lib/build/lib/clitt/core/tui/table/table_renderer.py +0 -339
  181. build/lib/build/lib/clitt/core/tui/tui_application.py +0 -52
  182. build/lib/build/lib/clitt/core/tui/tui_component.py +0 -154
  183. build/lib/build/lib/clitt/core/tui/tui_preferences.py +0 -103
  184. build/lib/build/lib/clitt/utils/__init__.py +0 -11
  185. build/lib/build/lib/clitt/utils/git_utils.py +0 -66
  186. build/lib/clitt/__classpath__.py +0 -28
  187. build/lib/clitt/__init__.py +0 -13
  188. build/lib/clitt/__main__.py +0 -139
  189. build/lib/clitt/addons/__init__.py +0 -12
  190. build/lib/clitt/addons/appman/__init__.py +0 -13
  191. build/lib/clitt/addons/appman/appman.py +0 -305
  192. build/lib/clitt/addons/appman/appman_enums.py +0 -39
  193. build/lib/clitt/addons/appman/templates/__init__.py +0 -11
  194. build/lib/clitt/addons/widman/__init__.py +0 -14
  195. build/lib/clitt/addons/widman/widget.py +0 -70
  196. build/lib/clitt/addons/widman/widget_entry.py +0 -54
  197. build/lib/clitt/addons/widman/widgets/__init__.py +0 -14
  198. build/lib/clitt/addons/widman/widgets/widget_free.py +0 -110
  199. build/lib/clitt/addons/widman/widgets/widget_punch.py +0 -246
  200. build/lib/clitt/addons/widman/widgets/widget_send_msg.py +0 -272
  201. build/lib/clitt/addons/widman/widgets/widget_time_calc.py +0 -146
  202. build/lib/clitt/addons/widman/widman.py +0 -123
  203. build/lib/clitt/core/__init__.py +0 -15
  204. build/lib/clitt/core/exception/__init__.py +0 -11
  205. build/lib/clitt/core/exception/exceptions.py +0 -19
  206. build/lib/clitt/core/icons/__init__.py +0 -12
  207. build/lib/clitt/core/icons/emojis/__init__.py +0 -12
  208. build/lib/clitt/core/icons/emojis/emojis.py +0 -41
  209. build/lib/clitt/core/icons/emojis/face_smiling.py +0 -40
  210. build/lib/clitt/core/icons/font_awesome/__init__.py +0 -18
  211. build/lib/clitt/core/icons/font_awesome/app_icons.py +0 -55
  212. build/lib/clitt/core/icons/font_awesome/awesome.py +0 -76
  213. build/lib/clitt/core/icons/font_awesome/dashboard_icons.py +0 -93
  214. build/lib/clitt/core/icons/font_awesome/form_icons.py +0 -69
  215. build/lib/clitt/core/icons/font_awesome/game_icons.py +0 -59
  216. build/lib/clitt/core/icons/font_awesome/nav_icons.py +0 -42
  217. build/lib/clitt/core/icons/font_awesome/trickplay_icons.py +0 -39
  218. build/lib/clitt/core/icons/font_awesome/widget_icons.py +0 -37
  219. build/lib/clitt/core/preferences.py +0 -87
  220. build/lib/clitt/core/term/__init__.py +0 -14
  221. build/lib/clitt/core/term/commons.py +0 -106
  222. build/lib/clitt/core/term/cursor.py +0 -174
  223. build/lib/clitt/core/term/screen.py +0 -106
  224. build/lib/clitt/core/term/terminal.py +0 -202
  225. build/lib/clitt/core/tui/__init__.py +0 -20
  226. build/lib/clitt/core/tui/line_input/__init__.py +0 -12
  227. build/lib/clitt/core/tui/line_input/keyboard_input.py +0 -229
  228. build/lib/clitt/core/tui/line_input/line_input.py +0 -31
  229. build/lib/clitt/core/tui/mchoose/__init__.py +0 -12
  230. build/lib/clitt/core/tui/mchoose/mchoose.py +0 -43
  231. build/lib/clitt/core/tui/mchoose/menu_choose.py +0 -192
  232. build/lib/clitt/core/tui/mdashboard/__init__.py +0 -14
  233. build/lib/clitt/core/tui/mdashboard/dashboard_builder.py +0 -54
  234. build/lib/clitt/core/tui/mdashboard/dashboard_item.py +0 -31
  235. build/lib/clitt/core/tui/mdashboard/mdashboard.py +0 -26
  236. build/lib/clitt/core/tui/mdashboard/menu_dashboard.py +0 -148
  237. build/lib/clitt/core/tui/menu/__init__.py +0 -16
  238. build/lib/clitt/core/tui/menu/tui_menu.py +0 -111
  239. build/lib/clitt/core/tui/menu/tui_menu_action.py +0 -47
  240. build/lib/clitt/core/tui/menu/tui_menu_factory.py +0 -117
  241. build/lib/clitt/core/tui/menu/tui_menu_item.py +0 -196
  242. build/lib/clitt/core/tui/menu/tui_menu_ui.py +0 -98
  243. build/lib/clitt/core/tui/menu/tui_menu_view.py +0 -57
  244. build/lib/clitt/core/tui/minput/__init__.py +0 -19
  245. build/lib/clitt/core/tui/minput/access_type.py +0 -26
  246. build/lib/clitt/core/tui/minput/field_builder.py +0 -117
  247. build/lib/clitt/core/tui/minput/form_builder.py +0 -72
  248. build/lib/clitt/core/tui/minput/form_field.py +0 -180
  249. build/lib/clitt/core/tui/minput/input_type.py +0 -30
  250. build/lib/clitt/core/tui/minput/input_validator.py +0 -98
  251. build/lib/clitt/core/tui/minput/menu_input.py +0 -292
  252. build/lib/clitt/core/tui/minput/minput.py +0 -44
  253. build/lib/clitt/core/tui/minput/minput_utils.py +0 -156
  254. build/lib/clitt/core/tui/mselect/__init__.py +0 -12
  255. build/lib/clitt/core/tui/mselect/menu_select.py +0 -170
  256. build/lib/clitt/core/tui/mselect/mselect.py +0 -36
  257. build/lib/clitt/core/tui/table/__init__.py +0 -12
  258. build/lib/clitt/core/tui/table/table_enums.py +0 -47
  259. build/lib/clitt/core/tui/table/table_renderer.py +0 -339
  260. build/lib/clitt/core/tui/tui_application.py +0 -52
  261. build/lib/clitt/core/tui/tui_component.py +0 -154
  262. build/lib/clitt/core/tui/tui_preferences.py +0 -103
  263. build/lib/clitt/utils/__init__.py +0 -11
  264. build/lib/clitt/utils/git_utils.py +0 -66
  265. hspylib_clitt-0.9.120.dist-info/RECORD +0 -334
  266. {hspylib_clitt-0.9.120.dist-info → hspylib_clitt-0.9.121.dist-info}/WHEEL +0 -0
@@ -1,272 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
-
4
- """
5
- @project: HsPyLib-Clitt
6
- @package: clitt.addons.widman.widgets
7
- @file: widget_send_msg.py
8
- @created: Thu, 26 Aug 2017
9
- @author: <B>H</B>ugo <B>S</B>aporetti <B>J</B>unior"
10
- @site: https://github.com/yorevs/hspylib
11
- @license: MIT - Please refer to <https://opensource.org/licenses/MIT>
12
-
13
- Copyright·(c)·2024,·HSPyLib
14
- """
15
- from clitt.addons.widman.widget import Widget
16
- from clitt.core.icons.font_awesome.widget_icons import WidgetIcons
17
- from clitt.core.tui.minput.input_validator import InputValidator
18
- from clitt.core.tui.minput.minput import MenuInput, minput
19
- from hspylib.core.exception.exceptions import WidgetExecutionError
20
- from hspylib.core.tools.commons import hook_exit_signals, sysout
21
- from hspylib.modules.application.argparse.argument_parser import HSArgumentParser
22
- from hspylib.modules.application.exit_status import ExitStatus
23
- from hspylib.modules.application.version import Version
24
- from hspylib.modules.cli.keyboard import Keyboard
25
- from textwrap import dedent
26
- from time import sleep
27
-
28
- import os
29
- import socket
30
- import threading
31
-
32
-
33
- class WidgetSendMsg(Widget):
34
- """HsPyLib Widget to send TCP/UDP messages (multi-threaded)"""
35
-
36
- # fmt: off
37
- MAX_THREADS = 1000
38
- NET_TYPE_UDP = "UDP"
39
- NET_TYPE_TCP = "TCP"
40
-
41
- WIDGET_ICON = WidgetIcons.NETWORK
42
- WIDGET_NAME = "SendMsg"
43
- VERSION = Version(0, 3, 0)
44
- TOOLTIP = "Multi-Threaded IP Message Sender. Sends TCP/UDP messages"
45
- USAGE = dedent(f"""Usage: SendMsg [options]
46
-
47
- Options:
48
- +n, ++net_type <network_type> : The network type to be used. Either udp or tcp ( default is tcp ).
49
- +p, ++port <port_num> : The port number [1-65535] ( default is 12345).
50
- +a, ++address <host_address> : The address of the datagram receiver ( default is 127.0.0.1 ).
51
- +k, ++packets <num_packets> : The number of max datagrams to be send. If zero is specified, then the app
52
- is going to send indefinitely ( default is 100 ).
53
- +i, ++interval <interval_MS> : The interval in seconds between each datagram ( default is 1 Second ).
54
- +t, ++threads <threads_num> : Number of threads [1-{MAX_THREADS}] to be opened to send simultaneously
55
- ( default is 1 ).
56
- +m, ++message <message/filename> : The message to be sent. If the message matches a filename, then the file
57
- contents sent instead.
58
-
59
- E.g:. send-msg.py +n tcp +m "Hello" +p 12345 +a 0.0.0.0 +k 100 +i 500 +t 2
60
- """)
61
- # fmt: on
62
-
63
- def __init__(self) -> None:
64
- super().__init__(self.WIDGET_ICON, self.WIDGET_NAME, self.TOOLTIP, self.USAGE, self.VERSION)
65
- self.is_alive = True
66
- self.net_type = None
67
- self.host = None
68
- self.packets = None
69
- self.interval = None
70
- self.threads = None
71
- self.message = None
72
- self._args = None
73
- self.socket = None
74
- self.counter = 1
75
-
76
- def execute(self, *args) -> ExitStatus:
77
- hook_exit_signals(self.cleanup)
78
- if args and args[0] in ["-h", "--help"]:
79
- sysout(self.usage())
80
- return ExitStatus.SUCCESS
81
- if args and args[0] in ["-v", "--version"]:
82
- sysout(self.version())
83
- return ExitStatus.SUCCESS
84
- if args and not self._parse_args(*args):
85
- return ExitStatus.ERROR
86
- if not args and not self._prompt():
87
- return ExitStatus.ERROR
88
- if not args and not self._args:
89
- return ExitStatus.ERROR
90
-
91
- self.net_type = self._args.net_type or self.NET_TYPE_TCP
92
- self.host = (self._args.address or "127.0.0.1", self._args.port or 12345)
93
- self.packets = self._args.packets or 100
94
- self.interval = self._args.interval or 1
95
- self.threads = self._args.threads or 1
96
-
97
- if self._args.message and os.path.isfile(self._args.message):
98
- file_size = os.stat(self._args.message).st_size
99
- sysout(f"Reading contents from file: {self._args.message} ({file_size}) [Bs] instead")
100
- with open(self._args.message, "r", encoding="utf-8") as f_msg:
101
- self.message = f_msg.read()
102
- else:
103
- self.message = self._args.message or f"This is a {self._args.net_type} test %(count)"
104
-
105
- self._start_send()
106
-
107
- Keyboard.wait_keystroke()
108
-
109
- return ExitStatus.SUCCESS
110
-
111
- def cleanup(self) -> None:
112
- """Stops workers and close socket connection."""
113
- sysout("Terminating threads%NC%")
114
- self.is_alive = False
115
- if self.net_type == self.NET_TYPE_TCP:
116
- sysout("Closing TCP connection")
117
- self.socket.close()
118
-
119
- def _prompt(self) -> bool:
120
- """When no input is provided (e.g:. when executed from dashboard). Prompt the user for the info."""
121
- # fmt: off
122
- form_fields = MenuInput.builder() \
123
- .field() \
124
- .label('Net Type') \
125
- .itype('select') \
126
- .value(f"{self.NET_TYPE_TCP}|{self.NET_TYPE_UDP}") \
127
- .build() \
128
- .field() \
129
- .label('Address') \
130
- .validator(InputValidator.custom(r"^([0-9]{0,3}){0,1}(\.[0-9]{0,3}){0,3}$")) \
131
- .value('127.0.0.1') \
132
- .build() \
133
- .field() \
134
- .label('Port') \
135
- .validator(InputValidator.numbers()) \
136
- .min_max_length(2, 5) \
137
- .value(12345) \
138
- .build() \
139
- .field() \
140
- .label('Packets') \
141
- .validator(InputValidator.numbers()) \
142
- .min_max_length(1, 4) \
143
- .value(100) \
144
- .build() \
145
- .field() \
146
- .label('Interval') \
147
- .validator(InputValidator.numbers()) \
148
- .min_max_length(1, 4) \
149
- .value(1) \
150
- .build() \
151
- .field() \
152
- .label('Threads') \
153
- .validator(InputValidator.numbers()) \
154
- .min_max_length(1, 4) \
155
- .value(1) \
156
- .build() \
157
- .field() \
158
- .label('Message') \
159
- .validator(InputValidator.anything()) \
160
- .min_max_length(1, 40) \
161
- .value('This is a test') \
162
- .build() \
163
- .build()
164
- # fmt: on
165
- self._args = minput(form_fields)
166
- sysout("%HOM%%ED2%%MOD(0)%", end="")
167
-
168
- return len(self._args) > 1 if self._args else False
169
-
170
- def _parse_args(self, *args):
171
- """When arguments are passed from the command line, parse them.
172
- :param args the widget arguments
173
- """
174
- parser = HSArgumentParser(
175
- prog="sendmsg", prefix_chars="+", description="Sends TCP/UDP messages (multi-threaded)"
176
- )
177
- # fmt: off
178
- parser.add_argument(
179
- "+n", "++net-type", action="store", choices=["udp", "tcp"],
180
- type=str, default="tcp", required=False,
181
- help="The network type to be used. Either udp or tcp ( default is tcp )",
182
- )
183
- parser.add_argument(
184
- "+a", "++address", action="store",
185
- type=str, default="127.0.0.1", required=False,
186
- help="The address of the datagram receiver ( default is 127.0.0.1 )",
187
- )
188
- parser.add_argument(
189
- "+p", "++port", action="store",
190
- type=int, default=12345, required=False,
191
- help="The port number [1-65535] ( default is 12345)",
192
- )
193
- parser.add_argument(
194
- "+k", "++packets", action="store",
195
- type=int, default=100, required=False,
196
- help="The number of max datagrams to be send. If zero is specified, then the app "
197
- "is going to send indefinitely ( default is 100 ).",
198
- )
199
- parser.add_argument(
200
- "+i", "++interval", action="store",
201
- type=float, default=1, required=False,
202
- help="The interval in seconds between each datagram ( default is 1 Second )",
203
- )
204
- parser.add_argument(
205
- "+t", "++threads", action="store",
206
- type=int, default=1, required=False,
207
- help=f"Number of threads [1-{self.MAX_THREADS}] to be opened to send simultaneously ( default is 1 )",
208
- )
209
- parser.add_argument(
210
- "+m", "++message", action="store",
211
- type=str, required=False,
212
- help="The message to be sent. If the message matches a filename, then the file contents sent instead",
213
- )
214
- # fmt: on
215
- self._args = parser.parse_args(*args)
216
-
217
- return bool(self._args)
218
-
219
- def _init_sockets(self) -> None:
220
- """Initialize sockets."""
221
- if self.net_type == self.NET_TYPE_UDP:
222
- self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
223
- else:
224
- self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
225
- try:
226
- self.socket.connect(self.host)
227
- sysout(f"Successfully connected to {self.host}")
228
- except socket.error as err:
229
- raise WidgetExecutionError("Unable to initialize sockets") from err
230
-
231
- def _start_send(self) -> None:
232
- """Start sending packets."""
233
- thread_relief = 0.05
234
- self._init_sockets()
235
- sysout(
236
- f"\n%ORANGE%Start sending {self.packets} "
237
- f"{self.net_type.upper()} packet(s) "
238
- f"every {self.interval} second(s) to {self.host} using {self.threads} thread(s)"
239
- )
240
- threads_num = threading.active_count()
241
-
242
- for thread_num in range(1, int(self.threads) + 1):
243
- tr = threading.Thread(target=self._send_packet, args=(thread_num,))
244
- tr.daemon = True
245
- tr.start()
246
- sleep(thread_relief)
247
-
248
- while self.is_alive and threading.active_count() > threads_num:
249
- sleep(2 * thread_relief)
250
-
251
- def _send_packet(self, thread_num: int) -> None:
252
- """Send a packet."""
253
- lock = threading.Lock()
254
-
255
- while self.is_alive and self.packets <= 0 or self.counter <= self.packets:
256
- message = self.message.replace("%(count)", str(self.counter))
257
- length = len(message)
258
- sysout(
259
- f"%BLUE%[Thread-{thread_num:d}] "
260
- f'%GREEN%Sending "{message:s}" ({length:d}) bytes, '
261
- f"Pkt = {self.counter:>d}/{self.packets:>d} %NC%..."
262
- )
263
- if self.net_type == self.NET_TYPE_UDP:
264
- self.socket.sendto(message.encode(), self.host)
265
- else:
266
- try:
267
- self.socket.sendall((message + "\n").encode())
268
- with lock:
269
- self.counter += 1
270
- except socket.error as err:
271
- raise WidgetExecutionError("Unable to send packet") from err
272
- sleep(self.interval)
@@ -1,146 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
-
4
- """
5
- @project: HsPyLib-Clitt
6
- @package: clitt.addons.widman.widgets
7
- @file: widget_time_calc.py
8
- @created: Thu, 20 May 2021
9
- @author: <B>H</B>ugo <B>S</B>aporetti <B>J</B>unior"
10
- @site: https://github.com/yorevs/hspylib
11
- @license: MIT - Please refer to <https://opensource.org/licenses/MIT>
12
-
13
- Copyright·(c)·2024,·HSPyLib
14
- """
15
-
16
- from clitt.addons.widman.widget import Widget
17
- from clitt.core.icons.font_awesome.widget_icons import WidgetIcons
18
- from clitt.core.tui.minput.minput import MenuInput, minput
19
- from hspylib.core.exception.exceptions import WidgetExecutionError
20
- from hspylib.core.tools.commons import sysout
21
- from hspylib.modules.application.exit_status import ExitStatus
22
- from hspylib.modules.application.version import Version
23
- from typing import Optional, Tuple
24
-
25
- import math
26
- import re
27
-
28
-
29
- class WidgetTimeCalc(Widget):
30
- """HsPyLib Widget to calculate time based operations."""
31
-
32
- # fmt: off
33
- WIDGET_ICON = WidgetIcons.CLOCK
34
- WIDGET_NAME = "TimeCalc"
35
- VERSION = Version(0, 1, 0)
36
- TOOLTIP = "Calculate time based operations."
37
- USAGE = "Usage: TimeCalc [+d|++decimal] <HH1:MM1[:SS1]> <+|-> <HH2:MM2[:SS2]>"
38
- # fmt: on
39
-
40
- @staticmethod
41
- def to_decimal(time_raw: int = 0) -> int:
42
- """Convert a raw time into decimal.
43
- :param time_raw the raw time to be converted.
44
- """
45
- return int(round(((time_raw / 60.00) * 100.00)))
46
-
47
- @staticmethod
48
- def calc_time(*args) -> Tuple[int, int, int]:
49
- """Calculate the time resulted from the specified operations.
50
- :param args the widget arguments
51
- """
52
- op, total_seconds = "+", 0
53
- for tm in args:
54
- if not tm:
55
- continue
56
- if re.match(r"[+-]", tm):
57
- op = tm
58
- elif re.match(r"^([0-9]{1,2}:?)+", tm):
59
- try:
60
- parts = [int(math.floor(float(s))) for s in tm.split(":")]
61
- except ValueError as err:
62
- raise WidgetExecutionError(f"Unable to extract time parts from '{tm}'") from err
63
- f_hours = parts[0] if len(parts) > 0 else 0
64
- f_minutes = parts[1] if len(parts) > 1 else 0
65
- f_secs = parts[2] if len(parts) > 2 else 0
66
- tm_amount = (f_hours * 60 + f_minutes) * 60 + f_secs
67
- if op == "+":
68
- total_seconds += tm_amount
69
- elif op == "-":
70
- total_seconds -= tm_amount
71
- else:
72
- raise WidgetExecutionError(f"Invalid time input: '{tm}'")
73
- total_seconds, seconds = divmod(total_seconds, 60)
74
- hours, minutes = divmod(abs(total_seconds), 60)
75
-
76
- return hours if total_seconds > 0 else -1 * hours, minutes, seconds
77
-
78
- def __init__(self) -> None:
79
- super().__init__(self.WIDGET_ICON, self.WIDGET_NAME, self.TOOLTIP, self.USAGE, self.VERSION)
80
-
81
- self._decimal = False
82
- self._args = None
83
-
84
- def _parse_args(self, *args) -> Optional[ExitStatus]:
85
- """Parse command line arguments.
86
- :param args the widget arguments
87
- """
88
-
89
- if not args and not self._read_args():
90
- return ExitStatus.ABORTED
91
- if args and any(a in args for a in ["+h", "++help"]):
92
- sysout(self.usage())
93
- return ExitStatus.SUCCESS
94
- if args and any(a in args for a in ["+v", "++version"]):
95
- sysout(self.version())
96
- return ExitStatus.SUCCESS
97
- if args and any(a in args for a in ["+d", "++decimal"]):
98
- self._decimal = True
99
- args = args[1:]
100
- if not self._args:
101
- self._args = args
102
-
103
- return None
104
-
105
- def execute(self, *args) -> ExitStatus:
106
- ret_val = self._parse_args(*args)
107
-
108
- if ret_val is not None:
109
- return ret_val
110
-
111
- hours, minutes, seconds = self.calc_time(*self._args)
112
-
113
- if self._decimal:
114
- print(f"{hours:02d}.{self.to_decimal(minutes):02d}.{self.to_decimal(seconds):02d}")
115
- else:
116
- print(f"{hours:02d}:{minutes:02d}:{seconds:02d}")
117
-
118
- return ExitStatus.SUCCESS
119
-
120
- def _read_args(self) -> bool:
121
- """When no input is provided (e.g:. when executed from dashboard). Prompt the user for the info."""
122
- # fmt: off
123
- form_fields = MenuInput.builder() \
124
- .field() \
125
- .label('Time 1') \
126
- .itype('masked') \
127
- .value('|##:##:##') \
128
- .build() \
129
- .field() \
130
- .label('Operation') \
131
- .itype('select') \
132
- .value('+|-') \
133
- .build() \
134
- .field() \
135
- .label('Time 2') \
136
- .itype('masked') \
137
- .value('|##:##:##') \
138
- .build() \
139
- .build()
140
- # fmt: on
141
-
142
- result = minput(form_fields)
143
- self._args = result.values if result else None
144
- sysout("%HOM%%ED2%%MOD(0)%", end="")
145
-
146
- return bool(result)
@@ -1,123 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
-
4
- """
5
- @project: HsPyLib-Clitt
6
- @package: clitt.addons.widman
7
- @file: widman.py
8
- @created: Thu, 20 May 2021
9
- @author: <B>H</B>ugo <B>S</B>aporetti <B>J</B>unior"
10
- @site: https://github.com/yorevs/hspylib
11
- @license: MIT - Please refer to <https://opensource.org/licenses/MIT>
12
-
13
- Copyright·(c)·2024,·HSPyLib
14
- """
15
- from clitt.addons.widman.widget import Widget
16
- from clitt.addons.widman.widget_entry import WidgetEntry
17
- from clitt.core.tui.mdashboard.dashboard_item import DashboardItem
18
- from clitt.core.tui.mdashboard.mdashboard import mdashboard
19
- from hspylib.core.exception.exceptions import WidgetExecutionError, WidgetNotFoundError
20
- from hspylib.core.metaclass.singleton import Singleton
21
- from hspylib.core.preconditions import check_state
22
- from hspylib.core.tools.commons import get_path
23
- from hspylib.core.tools.text_tools import camelcase
24
- from hspylib.modules.application.application import Application
25
- from hspylib.modules.application.exit_status import ExitStatus
26
-
27
- import atexit
28
- import os
29
- import sys
30
-
31
- HERE = get_path(__file__)
32
-
33
-
34
- class WidgetManager(metaclass=Singleton):
35
- """HsPyLib widget manager that handles HsPyLib widgets."""
36
-
37
- WIDGETS_PATH = HERE / "widgets"
38
-
39
- @staticmethod
40
- def _name_matches(expected_name: str, provided_name: str) -> bool:
41
- """Check if two names matches using defined naming rules.
42
- :param expected_name the expected widget name.
43
- :param provided_name the provided widget name (read from file).
44
- """
45
-
46
- return (
47
- expected_name.lower() == provided_name.lower()
48
- or expected_name == provided_name.capitalize()
49
- or expected_name == camelcase(provided_name, capitalized=True)
50
- or expected_name.lower() == provided_name.lower().replace("_", "")
51
- )
52
-
53
- def __init__(self, parent_app: Application):
54
- self._parent_app = parent_app
55
- self._widgets = []
56
- self._lookup_paths = os.environ.get("HHS_WIDGETS_PATH", "").split(":")
57
- self._lookup_paths.insert(0, str(WidgetManager.WIDGETS_PATH))
58
- list(map(sys.path.append, self._lookup_paths))
59
- check_state(self._search_widgets() > 0, "Unable to find any widgets from: {}", self._lookup_paths)
60
-
61
- def execute(self, widget_name: str, *widget_args) -> None:
62
- """Execute the specified widget.
63
- :param widget_name the widget name.
64
- :param widget_args the arguments to be provided to the widget.
65
- """
66
-
67
- widget = self._import_widget(camelcase(widget_name, capitalized=True))
68
- try:
69
- atexit.register(widget.cleanup)
70
- exit_code = widget.execute(*widget_args)
71
- if exit_code in [ExitStatus.ERROR, ExitStatus.FAILED]:
72
- raise WidgetExecutionError(f"Widget '{widget_name}' failed to execute. exit_code={exit_code}")
73
- except Exception as err:
74
- raise WidgetExecutionError(f"Unable to execute widget '{widget_name}' -> {err}") from err
75
-
76
- def dashboard(self) -> None:
77
- """Display all available widgets from the widget lookup paths on a dashboard."""
78
-
79
- items = []
80
- try:
81
- for widget_entry in self._widgets:
82
- widget = self._import_widget(widget_entry.name)
83
- item = DashboardItem(
84
- widget.icon(), f"{widget.name()} v{widget.version()}: {widget.tooltip()}", widget.execute
85
- )
86
- items.append(item)
87
- check_state(len(items) > 0, "No widgets found from: {}", str(self._lookup_paths))
88
- mdashboard(items, "Please select a widget to execute")
89
- except Exception as err:
90
- raise WidgetExecutionError(f"Failed to execute widget :: {str(err)}") from err
91
-
92
- # pylint: disable=cell-var-from-loop
93
- def _search_widgets(self) -> int:
94
- """Search and load all widgets from the widget lookup paths."""
95
-
96
- for path in self._lookup_paths:
97
- for root, _, files in os.walk(path):
98
- filtered = list(filter(lambda p: p.startswith(WidgetEntry.MODULE_PREFIX) and p.endswith("py"), files))
99
- widgets = list(map(lambda w: WidgetEntry(w, f"{root}/{w}"), filtered))
100
- self._widgets.extend(widgets)
101
-
102
- return len(self._widgets)
103
-
104
- def _import_widget(self, widget_name: str) -> Widget:
105
- """Find, import and return a widget specified by the widget name.
106
- :param widget_name the widget name.
107
- """
108
- widget_entry = next((w for w in self._widgets if self._name_matches(widget_name, w.name)), None)
109
- if not widget_entry:
110
- raise WidgetNotFoundError(
111
- f"Widget '{widget_name}' was not found on widget lookup paths: {str(self._lookup_paths)}"
112
- )
113
- try:
114
- widget_module = __import__(widget_entry.module)
115
- except ModuleNotFoundError as err:
116
- raise WidgetNotFoundError(
117
- f"Widget '{widget_name}' was not found on widget lookup paths: {str(self._lookup_paths)}"
118
- ) from err
119
- widget_clazz = getattr(widget_module, widget_entry.clazz)
120
- widget = widget_clazz()
121
- check_state(isinstance(widget, Widget), 'All widgets must inherit from "clitt.addons.widman.Widget"')
122
-
123
- return widget
@@ -1,15 +0,0 @@
1
- # _*_ coding: utf-8 _*_
2
- #
3
- # hspylib-clitt v0.9.120
4
- #
5
- # Package: main.build.lib.build.lib.build.lib.clitt.core
6
- """Package initialization."""
7
-
8
- __all__ = [
9
- 'exception',
10
- 'icons',
11
- 'preferences',
12
- 'term',
13
- 'tui'
14
- ]
15
- __version__ = '0.9.120'
@@ -1,11 +0,0 @@
1
- # _*_ coding: utf-8 _*_
2
- #
3
- # hspylib-clitt v0.9.120
4
- #
5
- # Package: main.build.lib.build.lib.build.lib.clitt.core.exception
6
- """Package initialization."""
7
-
8
- __all__ = [
9
- 'exceptions'
10
- ]
11
- __version__ = '0.9.120'
@@ -1,19 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
-
4
- """
5
- @project: HsPyLib
6
- @package: clitt.core.exceptions
7
- @file: exceptions.py
8
- @created: Fri, 7 Jul 2023
9
- @author: <B>H</B>ugo <B>S</B>aporetti <B>J</B>unior"
10
- @site: https://github.com/yorevs/hspylib
11
- @license: MIT - Please refer to <https://opensource.org/licenses/MIT>
12
-
13
- Copyright·(c)·2024,·HSPyLib
14
- """
15
-
16
-
17
- class NotATerminalError(NotImplementedError):
18
- """Raised when a TTY terminal is required"""
19
-
@@ -1,12 +0,0 @@
1
- # _*_ coding: utf-8 _*_
2
- #
3
- # hspylib-clitt v0.9.120
4
- #
5
- # Package: main.build.lib.build.lib.build.lib.clitt.core.icons
6
- """Package initialization."""
7
-
8
- __all__ = [
9
- 'emojis',
10
- 'font_awesome'
11
- ]
12
- __version__ = '0.9.120'
@@ -1,12 +0,0 @@
1
- # _*_ coding: utf-8 _*_
2
- #
3
- # hspylib-clitt v0.9.120
4
- #
5
- # Package: main.build.lib.build.lib.build.lib.clitt.core.icons.emojis
6
- """Package initialization."""
7
-
8
- __all__ = [
9
- 'emojis',
10
- 'face_smiling'
11
- ]
12
- __version__ = '0.9.120'
@@ -1,41 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
-
4
- """
5
- @project: HsPyLib-Clitt
6
- @package: clitt.core.icons.emojis
7
- @file: emojis.py
8
- @created: Tue, 4 May 2021
9
- @author: <B>H</B>ugo <B>S</B>aporetti <B>J</B>unior"
10
- @site: https://github.com/yorevs/hspylib
11
- @license: MIT - Please refer to <https://opensource.org/licenses/MIT>
12
-
13
- Copyright·(c)·2024,·HSPyLib
14
- """
15
-
16
- from emoji.core import emojize
17
- from hspylib.core.enums.enumeration import Enumeration
18
- from hspylib.core.tools.commons import sysout
19
-
20
-
21
- class Emoji(Enumeration):
22
- """
23
- Emoji codes
24
- Full list of emojis can be found here:
25
- - https://unicode.org/emoji/charts/emoji-list.html
26
- """
27
-
28
- @staticmethod
29
- def emj_print(emoji_str: str, end: str = "") -> None:
30
- """Print an emoji
31
- :param emoji_str the emoji to be printed.
32
- :param end string appended after the last value, default a newline.
33
- """
34
- sysout(f"{emojize(emoji_str)} ", end=end)
35
-
36
- def __str__(self) -> str:
37
- return str(self.value)
38
-
39
- @property
40
- def placeholder(self) -> str:
41
- return f":{self.name}:"