meerk40t 0.9.3001__py2.py3-none-any.whl → 0.9.7020__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.
Files changed (446) hide show
  1. meerk40t/__init__.py +1 -1
  2. meerk40t/balormk/balor_params.py +167 -167
  3. meerk40t/balormk/clone_loader.py +457 -457
  4. meerk40t/balormk/controller.py +1566 -1512
  5. meerk40t/balormk/cylindermod.py +64 -0
  6. meerk40t/balormk/device.py +966 -1959
  7. meerk40t/balormk/driver.py +778 -591
  8. meerk40t/balormk/galvo_commands.py +1194 -0
  9. meerk40t/balormk/gui/balorconfig.py +237 -111
  10. meerk40t/balormk/gui/balorcontroller.py +191 -184
  11. meerk40t/balormk/gui/baloroperationproperties.py +116 -115
  12. meerk40t/balormk/gui/corscene.py +845 -0
  13. meerk40t/balormk/gui/gui.py +179 -147
  14. meerk40t/balormk/livelightjob.py +466 -382
  15. meerk40t/balormk/mock_connection.py +131 -109
  16. meerk40t/balormk/plugin.py +133 -135
  17. meerk40t/balormk/usb_connection.py +306 -301
  18. meerk40t/camera/__init__.py +1 -1
  19. meerk40t/camera/camera.py +514 -397
  20. meerk40t/camera/gui/camerapanel.py +1241 -1095
  21. meerk40t/camera/gui/gui.py +58 -58
  22. meerk40t/camera/plugin.py +441 -399
  23. meerk40t/ch341/__init__.py +27 -27
  24. meerk40t/ch341/ch341device.py +628 -628
  25. meerk40t/ch341/libusb.py +595 -589
  26. meerk40t/ch341/mock.py +171 -171
  27. meerk40t/ch341/windriver.py +157 -157
  28. meerk40t/constants.py +13 -0
  29. meerk40t/core/__init__.py +1 -1
  30. meerk40t/core/bindalias.py +550 -539
  31. meerk40t/core/core.py +47 -47
  32. meerk40t/core/cutcode/cubiccut.py +73 -73
  33. meerk40t/core/cutcode/cutcode.py +315 -312
  34. meerk40t/core/cutcode/cutgroup.py +141 -137
  35. meerk40t/core/cutcode/cutobject.py +192 -185
  36. meerk40t/core/cutcode/dwellcut.py +37 -37
  37. meerk40t/core/cutcode/gotocut.py +29 -29
  38. meerk40t/core/cutcode/homecut.py +29 -29
  39. meerk40t/core/cutcode/inputcut.py +34 -34
  40. meerk40t/core/cutcode/linecut.py +33 -33
  41. meerk40t/core/cutcode/outputcut.py +34 -34
  42. meerk40t/core/cutcode/plotcut.py +335 -335
  43. meerk40t/core/cutcode/quadcut.py +61 -61
  44. meerk40t/core/cutcode/rastercut.py +168 -148
  45. meerk40t/core/cutcode/waitcut.py +34 -34
  46. meerk40t/core/cutplan.py +1843 -1316
  47. meerk40t/core/drivers.py +330 -329
  48. meerk40t/core/elements/align.py +801 -669
  49. meerk40t/core/elements/branches.py +1858 -1507
  50. meerk40t/core/elements/clipboard.py +229 -219
  51. meerk40t/core/elements/element_treeops.py +4595 -2837
  52. meerk40t/core/elements/element_types.py +125 -105
  53. meerk40t/core/elements/elements.py +4315 -3617
  54. meerk40t/core/elements/files.py +117 -64
  55. meerk40t/core/elements/geometry.py +473 -224
  56. meerk40t/core/elements/grid.py +467 -316
  57. meerk40t/core/elements/materials.py +158 -94
  58. meerk40t/core/elements/notes.py +50 -38
  59. meerk40t/core/elements/offset_clpr.py +934 -912
  60. meerk40t/core/elements/offset_mk.py +963 -955
  61. meerk40t/core/elements/penbox.py +339 -267
  62. meerk40t/core/elements/placements.py +300 -83
  63. meerk40t/core/elements/render.py +785 -687
  64. meerk40t/core/elements/shapes.py +2618 -2092
  65. meerk40t/core/elements/testcases.py +105 -0
  66. meerk40t/core/elements/trace.py +651 -563
  67. meerk40t/core/elements/tree_commands.py +415 -409
  68. meerk40t/core/elements/undo_redo.py +116 -58
  69. meerk40t/core/elements/wordlist.py +319 -200
  70. meerk40t/core/exceptions.py +9 -9
  71. meerk40t/core/laserjob.py +220 -220
  72. meerk40t/core/logging.py +63 -63
  73. meerk40t/core/node/blobnode.py +83 -86
  74. meerk40t/core/node/bootstrap.py +105 -103
  75. meerk40t/core/node/branch_elems.py +40 -31
  76. meerk40t/core/node/branch_ops.py +45 -38
  77. meerk40t/core/node/branch_regmark.py +48 -41
  78. meerk40t/core/node/cutnode.py +29 -32
  79. meerk40t/core/node/effect_hatch.py +375 -257
  80. meerk40t/core/node/effect_warp.py +398 -0
  81. meerk40t/core/node/effect_wobble.py +441 -309
  82. meerk40t/core/node/elem_ellipse.py +404 -309
  83. meerk40t/core/node/elem_image.py +1082 -801
  84. meerk40t/core/node/elem_line.py +358 -292
  85. meerk40t/core/node/elem_path.py +259 -201
  86. meerk40t/core/node/elem_point.py +129 -102
  87. meerk40t/core/node/elem_polyline.py +310 -246
  88. meerk40t/core/node/elem_rect.py +376 -286
  89. meerk40t/core/node/elem_text.py +445 -418
  90. meerk40t/core/node/filenode.py +59 -40
  91. meerk40t/core/node/groupnode.py +138 -74
  92. meerk40t/core/node/image_processed.py +777 -766
  93. meerk40t/core/node/image_raster.py +156 -113
  94. meerk40t/core/node/layernode.py +31 -31
  95. meerk40t/core/node/mixins.py +135 -107
  96. meerk40t/core/node/node.py +1427 -1304
  97. meerk40t/core/node/nutils.py +117 -114
  98. meerk40t/core/node/op_cut.py +463 -335
  99. meerk40t/core/node/op_dots.py +296 -251
  100. meerk40t/core/node/op_engrave.py +414 -311
  101. meerk40t/core/node/op_image.py +755 -369
  102. meerk40t/core/node/op_raster.py +787 -522
  103. meerk40t/core/node/place_current.py +37 -40
  104. meerk40t/core/node/place_point.py +329 -126
  105. meerk40t/core/node/refnode.py +58 -47
  106. meerk40t/core/node/rootnode.py +225 -219
  107. meerk40t/core/node/util_console.py +48 -48
  108. meerk40t/core/node/util_goto.py +84 -65
  109. meerk40t/core/node/util_home.py +61 -61
  110. meerk40t/core/node/util_input.py +102 -102
  111. meerk40t/core/node/util_output.py +102 -102
  112. meerk40t/core/node/util_wait.py +65 -65
  113. meerk40t/core/parameters.py +709 -707
  114. meerk40t/core/planner.py +875 -785
  115. meerk40t/core/plotplanner.py +656 -652
  116. meerk40t/core/space.py +120 -113
  117. meerk40t/core/spoolers.py +706 -705
  118. meerk40t/core/svg_io.py +1836 -1549
  119. meerk40t/core/treeop.py +534 -445
  120. meerk40t/core/undos.py +278 -124
  121. meerk40t/core/units.py +784 -680
  122. meerk40t/core/view.py +393 -322
  123. meerk40t/core/webhelp.py +62 -62
  124. meerk40t/core/wordlist.py +513 -504
  125. meerk40t/cylinder/cylinder.py +247 -0
  126. meerk40t/cylinder/gui/cylindersettings.py +41 -0
  127. meerk40t/cylinder/gui/gui.py +24 -0
  128. meerk40t/device/__init__.py +1 -1
  129. meerk40t/device/basedevice.py +322 -123
  130. meerk40t/device/devicechoices.py +50 -0
  131. meerk40t/device/dummydevice.py +163 -128
  132. meerk40t/device/gui/defaultactions.py +618 -602
  133. meerk40t/device/gui/effectspanel.py +114 -0
  134. meerk40t/device/gui/formatterpanel.py +253 -290
  135. meerk40t/device/gui/warningpanel.py +337 -260
  136. meerk40t/device/mixins.py +13 -13
  137. meerk40t/dxf/__init__.py +1 -1
  138. meerk40t/dxf/dxf_io.py +766 -554
  139. meerk40t/dxf/plugin.py +47 -35
  140. meerk40t/external_plugins.py +79 -79
  141. meerk40t/external_plugins_build.py +28 -28
  142. meerk40t/extra/cag.py +112 -116
  143. meerk40t/extra/coolant.py +403 -0
  144. meerk40t/extra/encode_detect.py +204 -0
  145. meerk40t/extra/ezd.py +1165 -1165
  146. meerk40t/extra/hershey.py +834 -340
  147. meerk40t/extra/imageactions.py +322 -316
  148. meerk40t/extra/inkscape.py +628 -622
  149. meerk40t/extra/lbrn.py +424 -424
  150. meerk40t/extra/outerworld.py +283 -0
  151. meerk40t/extra/param_functions.py +1542 -1556
  152. meerk40t/extra/potrace.py +257 -253
  153. meerk40t/extra/serial_exchange.py +118 -0
  154. meerk40t/extra/updater.py +602 -453
  155. meerk40t/extra/vectrace.py +147 -146
  156. meerk40t/extra/winsleep.py +83 -83
  157. meerk40t/extra/xcs_reader.py +597 -0
  158. meerk40t/fill/fills.py +781 -335
  159. meerk40t/fill/patternfill.py +1061 -1061
  160. meerk40t/fill/patterns.py +614 -567
  161. meerk40t/grbl/control.py +87 -87
  162. meerk40t/grbl/controller.py +990 -903
  163. meerk40t/grbl/device.py +1084 -768
  164. meerk40t/grbl/driver.py +989 -771
  165. meerk40t/grbl/emulator.py +532 -497
  166. meerk40t/grbl/gcodejob.py +783 -767
  167. meerk40t/grbl/gui/grblconfiguration.py +373 -298
  168. meerk40t/grbl/gui/grblcontroller.py +485 -271
  169. meerk40t/grbl/gui/grblhardwareconfig.py +269 -153
  170. meerk40t/grbl/gui/grbloperationconfig.py +105 -0
  171. meerk40t/grbl/gui/gui.py +147 -116
  172. meerk40t/grbl/interpreter.py +44 -44
  173. meerk40t/grbl/loader.py +22 -22
  174. meerk40t/grbl/mock_connection.py +56 -56
  175. meerk40t/grbl/plugin.py +294 -264
  176. meerk40t/grbl/serial_connection.py +93 -88
  177. meerk40t/grbl/tcp_connection.py +81 -79
  178. meerk40t/grbl/ws_connection.py +112 -0
  179. meerk40t/gui/__init__.py +1 -1
  180. meerk40t/gui/about.py +2042 -296
  181. meerk40t/gui/alignment.py +1644 -1608
  182. meerk40t/gui/autoexec.py +199 -0
  183. meerk40t/gui/basicops.py +791 -670
  184. meerk40t/gui/bufferview.py +77 -71
  185. meerk40t/gui/busy.py +232 -133
  186. meerk40t/gui/choicepropertypanel.py +1662 -1469
  187. meerk40t/gui/consolepanel.py +706 -542
  188. meerk40t/gui/devicepanel.py +687 -581
  189. meerk40t/gui/dialogoptions.py +110 -107
  190. meerk40t/gui/executejob.py +316 -306
  191. meerk40t/gui/fonts.py +90 -90
  192. meerk40t/gui/functionwrapper.py +252 -0
  193. meerk40t/gui/gui_mixins.py +729 -0
  194. meerk40t/gui/guicolors.py +205 -182
  195. meerk40t/gui/help_assets/help_assets.py +218 -201
  196. meerk40t/gui/helper.py +154 -0
  197. meerk40t/gui/hersheymanager.py +1440 -846
  198. meerk40t/gui/icons.py +3422 -2747
  199. meerk40t/gui/imagesplitter.py +555 -508
  200. meerk40t/gui/keymap.py +354 -344
  201. meerk40t/gui/laserpanel.py +897 -806
  202. meerk40t/gui/laserrender.py +1470 -1232
  203. meerk40t/gui/lasertoolpanel.py +805 -793
  204. meerk40t/gui/magnetoptions.py +436 -0
  205. meerk40t/gui/materialmanager.py +2944 -0
  206. meerk40t/gui/materialtest.py +1722 -1694
  207. meerk40t/gui/mkdebug.py +646 -359
  208. meerk40t/gui/mwindow.py +163 -140
  209. meerk40t/gui/navigationpanels.py +2605 -2467
  210. meerk40t/gui/notes.py +143 -142
  211. meerk40t/gui/opassignment.py +414 -410
  212. meerk40t/gui/operation_info.py +310 -299
  213. meerk40t/gui/plugin.py +500 -328
  214. meerk40t/gui/position.py +714 -669
  215. meerk40t/gui/preferences.py +901 -650
  216. meerk40t/gui/propertypanels/attributes.py +1461 -1131
  217. meerk40t/gui/propertypanels/blobproperty.py +117 -114
  218. meerk40t/gui/propertypanels/consoleproperty.py +83 -80
  219. meerk40t/gui/propertypanels/gotoproperty.py +77 -0
  220. meerk40t/gui/propertypanels/groupproperties.py +223 -217
  221. meerk40t/gui/propertypanels/hatchproperty.py +489 -469
  222. meerk40t/gui/propertypanels/imageproperty.py +2244 -1384
  223. meerk40t/gui/propertypanels/inputproperty.py +59 -58
  224. meerk40t/gui/propertypanels/opbranchproperties.py +82 -80
  225. meerk40t/gui/propertypanels/operationpropertymain.py +1890 -1638
  226. meerk40t/gui/propertypanels/outputproperty.py +59 -58
  227. meerk40t/gui/propertypanels/pathproperty.py +389 -380
  228. meerk40t/gui/propertypanels/placementproperty.py +1214 -383
  229. meerk40t/gui/propertypanels/pointproperty.py +140 -136
  230. meerk40t/gui/propertypanels/propertywindow.py +313 -181
  231. meerk40t/gui/propertypanels/rasterwizardpanels.py +996 -912
  232. meerk40t/gui/propertypanels/regbranchproperties.py +76 -0
  233. meerk40t/gui/propertypanels/textproperty.py +770 -755
  234. meerk40t/gui/propertypanels/waitproperty.py +56 -55
  235. meerk40t/gui/propertypanels/warpproperty.py +121 -0
  236. meerk40t/gui/propertypanels/wobbleproperty.py +255 -204
  237. meerk40t/gui/ribbon.py +2471 -2210
  238. meerk40t/gui/scene/scene.py +1100 -1051
  239. meerk40t/gui/scene/sceneconst.py +22 -22
  240. meerk40t/gui/scene/scenepanel.py +439 -349
  241. meerk40t/gui/scene/scenespacewidget.py +365 -365
  242. meerk40t/gui/scene/widget.py +518 -505
  243. meerk40t/gui/scenewidgets/affinemover.py +215 -215
  244. meerk40t/gui/scenewidgets/attractionwidget.py +315 -309
  245. meerk40t/gui/scenewidgets/bedwidget.py +120 -97
  246. meerk40t/gui/scenewidgets/elementswidget.py +137 -107
  247. meerk40t/gui/scenewidgets/gridwidget.py +785 -745
  248. meerk40t/gui/scenewidgets/guidewidget.py +765 -765
  249. meerk40t/gui/scenewidgets/laserpathwidget.py +66 -66
  250. meerk40t/gui/scenewidgets/machineoriginwidget.py +86 -86
  251. meerk40t/gui/scenewidgets/nodeselector.py +28 -28
  252. meerk40t/gui/scenewidgets/rectselectwidget.py +592 -346
  253. meerk40t/gui/scenewidgets/relocatewidget.py +33 -33
  254. meerk40t/gui/scenewidgets/reticlewidget.py +83 -83
  255. meerk40t/gui/scenewidgets/selectionwidget.py +2958 -2756
  256. meerk40t/gui/simpleui.py +362 -333
  257. meerk40t/gui/simulation.py +2451 -2094
  258. meerk40t/gui/snapoptions.py +208 -203
  259. meerk40t/gui/spoolerpanel.py +1227 -1180
  260. meerk40t/gui/statusbarwidgets/defaultoperations.py +480 -353
  261. meerk40t/gui/statusbarwidgets/infowidget.py +520 -483
  262. meerk40t/gui/statusbarwidgets/opassignwidget.py +356 -355
  263. meerk40t/gui/statusbarwidgets/selectionwidget.py +172 -171
  264. meerk40t/gui/statusbarwidgets/shapepropwidget.py +754 -236
  265. meerk40t/gui/statusbarwidgets/statusbar.py +272 -260
  266. meerk40t/gui/statusbarwidgets/statusbarwidget.py +268 -270
  267. meerk40t/gui/statusbarwidgets/strokewidget.py +267 -251
  268. meerk40t/gui/themes.py +200 -78
  269. meerk40t/gui/tips.py +590 -0
  270. meerk40t/gui/toolwidgets/circlebrush.py +35 -35
  271. meerk40t/gui/toolwidgets/toolcircle.py +248 -242
  272. meerk40t/gui/toolwidgets/toolcontainer.py +82 -77
  273. meerk40t/gui/toolwidgets/tooldraw.py +97 -90
  274. meerk40t/gui/toolwidgets/toolellipse.py +219 -212
  275. meerk40t/gui/toolwidgets/toolimagecut.py +25 -132
  276. meerk40t/gui/toolwidgets/toolline.py +39 -144
  277. meerk40t/gui/toolwidgets/toollinetext.py +79 -236
  278. meerk40t/gui/toolwidgets/toollinetext_inline.py +296 -0
  279. meerk40t/gui/toolwidgets/toolmeasure.py +163 -216
  280. meerk40t/gui/toolwidgets/toolnodeedit.py +2088 -2074
  281. meerk40t/gui/toolwidgets/toolnodemove.py +92 -94
  282. meerk40t/gui/toolwidgets/toolparameter.py +754 -668
  283. meerk40t/gui/toolwidgets/toolplacement.py +108 -108
  284. meerk40t/gui/toolwidgets/toolpoint.py +68 -59
  285. meerk40t/gui/toolwidgets/toolpointlistbuilder.py +294 -0
  286. meerk40t/gui/toolwidgets/toolpointmove.py +183 -0
  287. meerk40t/gui/toolwidgets/toolpolygon.py +288 -403
  288. meerk40t/gui/toolwidgets/toolpolyline.py +38 -196
  289. meerk40t/gui/toolwidgets/toolrect.py +211 -207
  290. meerk40t/gui/toolwidgets/toolrelocate.py +72 -72
  291. meerk40t/gui/toolwidgets/toolribbon.py +598 -113
  292. meerk40t/gui/toolwidgets/tooltabedit.py +546 -0
  293. meerk40t/gui/toolwidgets/tooltext.py +98 -89
  294. meerk40t/gui/toolwidgets/toolvector.py +213 -204
  295. meerk40t/gui/toolwidgets/toolwidget.py +39 -39
  296. meerk40t/gui/usbconnect.py +98 -91
  297. meerk40t/gui/utilitywidgets/buttonwidget.py +18 -18
  298. meerk40t/gui/utilitywidgets/checkboxwidget.py +90 -90
  299. meerk40t/gui/utilitywidgets/controlwidget.py +14 -14
  300. meerk40t/gui/utilitywidgets/cyclocycloidwidget.py +343 -340
  301. meerk40t/gui/utilitywidgets/debugwidgets.py +148 -0
  302. meerk40t/gui/utilitywidgets/handlewidget.py +27 -27
  303. meerk40t/gui/utilitywidgets/harmonograph.py +450 -447
  304. meerk40t/gui/utilitywidgets/openclosewidget.py +40 -40
  305. meerk40t/gui/utilitywidgets/rotationwidget.py +54 -54
  306. meerk40t/gui/utilitywidgets/scalewidget.py +75 -75
  307. meerk40t/gui/utilitywidgets/seekbarwidget.py +183 -183
  308. meerk40t/gui/utilitywidgets/togglewidget.py +142 -142
  309. meerk40t/gui/utilitywidgets/toolbarwidget.py +8 -8
  310. meerk40t/gui/wordlisteditor.py +985 -931
  311. meerk40t/gui/wxmeerk40t.py +1447 -1169
  312. meerk40t/gui/wxmmain.py +5644 -4112
  313. meerk40t/gui/wxmribbon.py +1591 -1076
  314. meerk40t/gui/wxmscene.py +1631 -1453
  315. meerk40t/gui/wxmtree.py +2416 -2089
  316. meerk40t/gui/wxutils.py +1769 -1099
  317. meerk40t/gui/zmatrix.py +102 -102
  318. meerk40t/image/__init__.py +1 -1
  319. meerk40t/image/dither.py +429 -0
  320. meerk40t/image/imagetools.py +2793 -2269
  321. meerk40t/internal_plugins.py +150 -130
  322. meerk40t/kernel/__init__.py +63 -12
  323. meerk40t/kernel/channel.py +259 -212
  324. meerk40t/kernel/context.py +538 -538
  325. meerk40t/kernel/exceptions.py +41 -41
  326. meerk40t/kernel/functions.py +463 -414
  327. meerk40t/kernel/jobs.py +100 -100
  328. meerk40t/kernel/kernel.py +3828 -3571
  329. meerk40t/kernel/lifecycles.py +71 -71
  330. meerk40t/kernel/module.py +49 -49
  331. meerk40t/kernel/service.py +147 -147
  332. meerk40t/kernel/settings.py +383 -343
  333. meerk40t/lihuiyu/controller.py +883 -876
  334. meerk40t/lihuiyu/device.py +1181 -1069
  335. meerk40t/lihuiyu/driver.py +1466 -1372
  336. meerk40t/lihuiyu/gui/gui.py +127 -106
  337. meerk40t/lihuiyu/gui/lhyaccelgui.py +377 -363
  338. meerk40t/lihuiyu/gui/lhycontrollergui.py +741 -651
  339. meerk40t/lihuiyu/gui/lhydrivergui.py +470 -446
  340. meerk40t/lihuiyu/gui/lhyoperationproperties.py +238 -237
  341. meerk40t/lihuiyu/gui/tcpcontroller.py +226 -190
  342. meerk40t/lihuiyu/interpreter.py +53 -53
  343. meerk40t/lihuiyu/laserspeed.py +450 -450
  344. meerk40t/lihuiyu/loader.py +90 -90
  345. meerk40t/lihuiyu/parser.py +404 -404
  346. meerk40t/lihuiyu/plugin.py +101 -102
  347. meerk40t/lihuiyu/tcp_connection.py +111 -109
  348. meerk40t/main.py +231 -165
  349. meerk40t/moshi/builder.py +788 -781
  350. meerk40t/moshi/controller.py +505 -499
  351. meerk40t/moshi/device.py +495 -442
  352. meerk40t/moshi/driver.py +862 -696
  353. meerk40t/moshi/gui/gui.py +78 -76
  354. meerk40t/moshi/gui/moshicontrollergui.py +538 -522
  355. meerk40t/moshi/gui/moshidrivergui.py +87 -75
  356. meerk40t/moshi/plugin.py +43 -43
  357. meerk40t/network/console_server.py +140 -57
  358. meerk40t/network/kernelserver.py +10 -9
  359. meerk40t/network/tcp_server.py +142 -140
  360. meerk40t/network/udp_server.py +103 -77
  361. meerk40t/network/web_server.py +404 -0
  362. meerk40t/newly/controller.py +1158 -1144
  363. meerk40t/newly/device.py +874 -732
  364. meerk40t/newly/driver.py +540 -412
  365. meerk40t/newly/gui/gui.py +219 -188
  366. meerk40t/newly/gui/newlyconfig.py +116 -101
  367. meerk40t/newly/gui/newlycontroller.py +193 -186
  368. meerk40t/newly/gui/operationproperties.py +51 -51
  369. meerk40t/newly/mock_connection.py +82 -82
  370. meerk40t/newly/newly_params.py +56 -56
  371. meerk40t/newly/plugin.py +1214 -1246
  372. meerk40t/newly/usb_connection.py +322 -322
  373. meerk40t/rotary/gui/gui.py +52 -46
  374. meerk40t/rotary/gui/rotarysettings.py +240 -232
  375. meerk40t/rotary/rotary.py +202 -98
  376. meerk40t/ruida/control.py +291 -91
  377. meerk40t/ruida/controller.py +138 -1088
  378. meerk40t/ruida/device.py +676 -231
  379. meerk40t/ruida/driver.py +534 -472
  380. meerk40t/ruida/emulator.py +1494 -1491
  381. meerk40t/ruida/exceptions.py +4 -4
  382. meerk40t/ruida/gui/gui.py +71 -76
  383. meerk40t/ruida/gui/ruidaconfig.py +239 -72
  384. meerk40t/ruida/gui/ruidacontroller.py +187 -184
  385. meerk40t/ruida/gui/ruidaoperationproperties.py +48 -47
  386. meerk40t/ruida/loader.py +54 -52
  387. meerk40t/ruida/mock_connection.py +57 -109
  388. meerk40t/ruida/plugin.py +124 -87
  389. meerk40t/ruida/rdjob.py +2084 -945
  390. meerk40t/ruida/serial_connection.py +116 -0
  391. meerk40t/ruida/tcp_connection.py +146 -0
  392. meerk40t/ruida/udp_connection.py +73 -0
  393. meerk40t/svgelements.py +9671 -9669
  394. meerk40t/tools/driver_to_path.py +584 -579
  395. meerk40t/tools/geomstr.py +5583 -4680
  396. meerk40t/tools/jhfparser.py +357 -292
  397. meerk40t/tools/kerftest.py +904 -890
  398. meerk40t/tools/livinghinges.py +1168 -1033
  399. meerk40t/tools/pathtools.py +987 -949
  400. meerk40t/tools/pmatrix.py +234 -0
  401. meerk40t/tools/pointfinder.py +942 -942
  402. meerk40t/tools/polybool.py +941 -940
  403. meerk40t/tools/rasterplotter.py +1660 -547
  404. meerk40t/tools/shxparser.py +1047 -901
  405. meerk40t/tools/ttfparser.py +726 -446
  406. meerk40t/tools/zinglplotter.py +595 -593
  407. {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/LICENSE +21 -21
  408. {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/METADATA +150 -139
  409. meerk40t-0.9.7020.dist-info/RECORD +446 -0
  410. {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/WHEEL +1 -1
  411. {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/top_level.txt +0 -1
  412. {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/zip-safe +1 -1
  413. meerk40t/balormk/elementlightjob.py +0 -159
  414. meerk40t-0.9.3001.dist-info/RECORD +0 -437
  415. test/bootstrap.py +0 -63
  416. test/test_cli.py +0 -12
  417. test/test_core_cutcode.py +0 -418
  418. test/test_core_elements.py +0 -144
  419. test/test_core_plotplanner.py +0 -397
  420. test/test_core_viewports.py +0 -312
  421. test/test_drivers_grbl.py +0 -108
  422. test/test_drivers_lihuiyu.py +0 -443
  423. test/test_drivers_newly.py +0 -113
  424. test/test_element_degenerate_points.py +0 -43
  425. test/test_elements_classify.py +0 -97
  426. test/test_elements_penbox.py +0 -22
  427. test/test_file_svg.py +0 -176
  428. test/test_fill.py +0 -155
  429. test/test_geomstr.py +0 -1523
  430. test/test_geomstr_nodes.py +0 -18
  431. test/test_imagetools_actualize.py +0 -306
  432. test/test_imagetools_wizard.py +0 -258
  433. test/test_kernel.py +0 -200
  434. test/test_laser_speeds.py +0 -3303
  435. test/test_length.py +0 -57
  436. test/test_lifecycle.py +0 -66
  437. test/test_operations.py +0 -251
  438. test/test_operations_hatch.py +0 -57
  439. test/test_ruida.py +0 -19
  440. test/test_spooler.py +0 -22
  441. test/test_tools_rasterplotter.py +0 -29
  442. test/test_wobble.py +0 -133
  443. test/test_zingl.py +0 -124
  444. {test → meerk40t/cylinder}/__init__.py +0 -0
  445. /meerk40t/{core/element_commands.py → cylinder/gui/__init__.py} +0 -0
  446. {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,403 @@
1
+ """
2
+ This module provides interfaces to coolants (airassist or others).
3
+ External modules can register the existence of an airassist.
4
+ Devices can then claim ownership of such a registered device
5
+ and react on device specific coolant commands
6
+ """
7
+
8
+
9
+ class Coolants:
10
+ """
11
+ Base class
12
+ """
13
+
14
+ def __init__(self, kernel):
15
+ self.kernel = kernel
16
+ self._coolants = []
17
+ # {
18
+ # "id": cool_id,
19
+ # "label": label,
20
+ # "function": cool_function,
21
+ # "config": config_function,
22
+ # "devices": [],
23
+ # "constraints": constraints,
24
+ # }
25
+
26
+ def remove_coolant_method(self, cool_id):
27
+ cool_id = cool_id.lower()
28
+ if cool_id in ("popup", "gcode_m7", "gcode_m8"):
29
+ # builtin...
30
+ return 0
31
+ to_be_deleted = []
32
+ for idx, cool in enumerate(self._coolants):
33
+ if cool_id == cool["id"]:
34
+ to_be_deleted.insert(0, idx)
35
+ for idx in to_be_deleted:
36
+ self._coolants.pop(idx)
37
+ return len(to_be_deleted)
38
+
39
+ def register_coolant_method(
40
+ self, cool_id, cool_function, config_function=None, label=None, constraints=None
41
+ ):
42
+ """
43
+ Announces the availability of a new coolant method.
44
+ Mainly used from plugins.
45
+ Args:
46
+ cool_id ([str]): unique identifier for the method. There are two predefined
47
+ methods generated from within meerk40t:
48
+ a) 'popup' which just popups an instruction message
49
+ to turn on / off the airassist
50
+ b) 'grbl' which uses the internal M7 / M9 commands ofa grbl compatible
51
+ device. So it has a 'grbl' constraint (see below)
52
+ cool_function ([function]): The routine to call when coolant needs
53
+ to be activated / deactivated. This routine expects two parameters:
54
+ def coolant_method (device, flag)
55
+ device: device that uses the routine
56
+ flag: indicator to turn it on (True) or off (False)
57
+ config_function ([function], optional): The routine to call, if you want
58
+ to edit parameters for this method. It expects one
59
+ Defaults to None, indicating it has no such function.
60
+ label ([str], optional): A description of the method.
61
+ Defaults to None which will use the cool_id as label
62
+ constraints ([str], optional): [description].
63
+ Defaults to None, so available to all devices.
64
+ Returns:
65
+ [type]: [description]
66
+ """
67
+ cool_id = cool_id.lower()
68
+
69
+ for cool in self._coolants:
70
+ # A coolant method with that id had already been registered
71
+ # so we just update it. Honestly this should not happen.
72
+ if cool_id == cool["id"]:
73
+ cool["label"] = label
74
+ cool["function"] = cool_function
75
+ cool["config"] = config_function
76
+ cool["constraints"] = constraints
77
+ return True
78
+ self._coolants.append(
79
+ {
80
+ "id": cool_id,
81
+ "label": label,
82
+ "function": cool_function,
83
+ "config": config_function,
84
+ "devices": [],
85
+ "constraints": constraints,
86
+ "current_state": [],
87
+ }
88
+ )
89
+ return True
90
+
91
+ def coolant_on(self, device):
92
+ for cool in self._coolants:
93
+ if device in cool["devices"]:
94
+ idx = cool["devices"].index(device)
95
+ if not cool["current_state"][idx]:
96
+ cool["current_state"][idx] = True
97
+ routine = cool["function"]
98
+ routine(device, True)
99
+ self.kernel.signal("coolant_set", device.label, True)
100
+ return True
101
+ return False
102
+
103
+ def coolant_off(self, device):
104
+ for cool in self._coolants:
105
+ if device in cool["devices"]:
106
+ idx = cool["devices"].index(device)
107
+ if cool["current_state"][idx]:
108
+ cool["current_state"][idx] = False
109
+ routine = cool["function"]
110
+ routine(device, False)
111
+ self.kernel.signal("coolant_set", device.label, False)
112
+ return True
113
+ return False
114
+
115
+ def coolant_toggle(self, device):
116
+ for cool in self._coolants:
117
+ if device in cool["devices"]:
118
+ idx = cool["devices"].index(device)
119
+ new_state = not cool["current_state"][idx]
120
+ cool["current_state"][idx] = new_state
121
+ routine = cool["function"]
122
+ routine(device, new_state)
123
+ self.kernel.signal("coolant_set", device.label, new_state)
124
+ return True
125
+ return False
126
+
127
+ def coolant_state(self, device):
128
+ for cool in self._coolants:
129
+ if device in cool["devices"]:
130
+ idx = cool["devices"].index(device)
131
+ return cool["current_state"][idx]
132
+ # Nothing found
133
+ return False
134
+
135
+ def coolant_on_by_id(self, identifier):
136
+ # Caveat, this will be executed independently of devices registered!
137
+ cool_id = identifier.lower()
138
+ for cool in self._coolants:
139
+ if cool_id == cool["id"]:
140
+ routine = cool["function"]
141
+ routine(None, True)
142
+ return True
143
+ return False
144
+
145
+ def coolant_off_by_id(self, identifier):
146
+ # Caveat, this will be executed independently of devices registered!
147
+ cool_id = identifier.lower()
148
+ for cool in self._coolants:
149
+ if cool_id == cool["id"]:
150
+ routine = cool["function"]
151
+ routine(None, False)
152
+ return True
153
+ return False
154
+
155
+ def registered_coolants(self):
156
+ """
157
+ Returns the dictionary of all registered coolants
158
+ """
159
+ return self._coolants
160
+
161
+ def claim_coolant(self, device, coolant):
162
+ found = None
163
+ if coolant is None:
164
+ coolant = ""
165
+ devname = device.name.lower()
166
+ # print (f"Claim: {device.label} ({devname}): {coolant}")
167
+ for cool in self._coolants:
168
+ relevant = True
169
+ if cool["constraints"]:
170
+ allowed = cool["constraints"].split(",")
171
+ relevant = any(candidate.lower() in devname for candidate in allowed)
172
+ if not relevant:
173
+ # Skipped as not relevant...
174
+ continue
175
+ if cool["id"] == coolant.lower():
176
+ found = cool["function"]
177
+ if device not in cool["devices"]:
178
+ cool["devices"].append(device)
179
+ cool["current_state"].append(False)
180
+ else:
181
+ try:
182
+ idx = cool["devices"].index(device)
183
+ cool["devices"].pop(idx)
184
+ cool["current_state"].pop(idx)
185
+ except ValueError:
186
+ # wasn't inside
187
+ pass
188
+
189
+ return found
190
+
191
+ def get_device_function(self, device, coolant=None):
192
+ found = None
193
+ for cool in self._coolants:
194
+ if coolant is None:
195
+ if device in cool["devices"]:
196
+ found = cool["function"]
197
+ break
198
+ elif cool["id"] == coolant.lower():
199
+ found = cool["function"]
200
+ break
201
+
202
+ return found
203
+
204
+ def get_device_coolant(self, device, coolant=None):
205
+ found = None
206
+ for cool in self._coolants:
207
+ if coolant is None:
208
+ if device in cool["devices"]:
209
+ found = cool
210
+ break
211
+ elif cool["id"] == coolant.lower():
212
+ found = cool
213
+ break
214
+
215
+ return found
216
+
217
+ def get_devices_using(self, coolant_id):
218
+ dev_str = ""
219
+ multiple = False
220
+ for cool in self._coolants:
221
+ if cool["id"] == coolant_id.lower():
222
+ for idx, dev in enumerate(cool["devices"]):
223
+ if multiple:
224
+ dev_str += ", "
225
+ multiple = True
226
+ dev_str += (
227
+ f"{dev.label} [{'on' if cool['current_state'][idx] else 'off'}]"
228
+ )
229
+ break
230
+
231
+ return dev_str
232
+
233
+ def coolant_choice_helper(self, device):
234
+ """
235
+ Sets the choices and display of the coolant values dynamically
236
+ @param choice_dict:
237
+ @return:
238
+ """
239
+
240
+ def update(choice_dict):
241
+ _ = self.kernel.translation
242
+ devname = device.name.lower()
243
+ choices = []
244
+ display = []
245
+ choices.append("")
246
+ display.append(_("Nothing"))
247
+ for cool in self._coolants:
248
+ relevant = True
249
+ if cool["constraints"]:
250
+ relevant = False
251
+ allowed = cool["constraints"].split(",")
252
+ for candidate in allowed:
253
+ if candidate.lower() in devname:
254
+ relevant = True
255
+ break
256
+ if not relevant:
257
+ continue
258
+ choices.append(cool["id"])
259
+ if cool["label"]:
260
+ display.append(cool["label"])
261
+ else:
262
+ display.append(cool["id"])
263
+ choice_dict["choices"] = choices
264
+ choice_dict["display"] = display
265
+
266
+ return update
267
+
268
+
269
+ def plugin(kernel, lifecycle):
270
+ if lifecycle == "register":
271
+ _ = kernel.translation
272
+ context = kernel.root
273
+ context.coolant = Coolants(kernel)
274
+
275
+ def base_coolant_popup(context, mode):
276
+ if hasattr(context, "label"):
277
+ lasername = context.label
278
+ else:
279
+ lasername = "your laser"
280
+ if mode:
281
+ msg = _("Please switch the airassist for {laser} on").format(
282
+ laser=lasername
283
+ )
284
+ else:
285
+ msg = _("Please switch the airassist for {laser} off").format(
286
+ laser=lasername
287
+ )
288
+ context.kernel.yesno(
289
+ msg, caption=_("Air-Assist"), option_yes=_("OK"), option_no=_("OK")
290
+ )
291
+
292
+ def base_coolant_grbl_m7(context, mode):
293
+ if mode:
294
+ context("gcode M7\n")
295
+ else:
296
+ context("gcode M9\n")
297
+
298
+ def base_coolant_grbl_m8(context, mode):
299
+ if mode:
300
+ context("gcode M8\n")
301
+ else:
302
+ context("gcode M9\n")
303
+
304
+ context.coolant.register_coolant_method(
305
+ "popup", base_coolant_popup, config_function=None, label=_("Warnmessage")
306
+ )
307
+ context.coolant.register_coolant_method(
308
+ "gcode_m7",
309
+ base_coolant_grbl_m7,
310
+ config_function=None,
311
+ label=_("GCode M7/M9"),
312
+ constraints="grbl",
313
+ )
314
+ context.coolant.register_coolant_method(
315
+ "gcode_m8",
316
+ base_coolant_grbl_m8,
317
+ config_function=None,
318
+ label=_("GCode M8/M9"),
319
+ constraints="grbl",
320
+ )
321
+
322
+ @context.console_command(
323
+ ("coolants", "vents"), help=_("displays registered coolant methods")
324
+ )
325
+ def display_coolant(command, channel, _, **kwargs):
326
+ # elements = context.elements
327
+ coolant = kernel.root.coolant
328
+ cool = coolant.registered_coolants()
329
+ if len(cool):
330
+ channel(_("Registered coolant-interfaces:"))
331
+ for cool_instance in cool:
332
+ c_name = cool_instance["id"]
333
+ c_label = cool_instance["label"]
334
+ claimed = coolant.get_devices_using(c_name)
335
+ if c_label:
336
+ c_name += " - " + c_label
337
+ if claimed == "":
338
+ claimed = _("Not used")
339
+
340
+ channel(_("{name}: {devices}").format(name=c_name, devices=claimed))
341
+
342
+ else:
343
+ channel(_("There are no coolant-interfaces known to MeerK40t"))
344
+
345
+ @context.console_command(
346
+ ("coolant_on", "vent_on"), help=_("Turns on the coolant for the active device")
347
+ )
348
+ def turn_coolant_on(command, channel, _, **kwargs):
349
+ try:
350
+ device = context.device
351
+ except AttributeError:
352
+ channel("No active device found")
353
+ return
354
+
355
+ coolant = kernel.root.coolant
356
+ if coolant.coolant_on(device):
357
+ channel("Coolant turned on")
358
+ else:
359
+ channel("Active device does not support coolant")
360
+
361
+ @context.console_command(
362
+ ("coolant_off", "vent_off"), help=_("Turns off the coolant for the active device")
363
+ )
364
+ def turn_coolant_off(command, channel, _, **kwargs):
365
+ try:
366
+ device = context.device
367
+ except AttributeError:
368
+ channel("No active device found")
369
+ return
370
+
371
+ coolant = kernel.root.coolant
372
+ if coolant.coolant_off(device):
373
+ channel("Coolant turned off")
374
+ else:
375
+ channel("Active device does not support coolant")
376
+
377
+ @context.console_argument("id", type=str)
378
+ @context.console_command(
379
+ ("coolant_on_by_id", "vent_on_by_id"), help=_("Turns the coolant on using the given method")
380
+ )
381
+ def turn_coolant_on_by_id(command, channel, _, id=None, **kwargs):
382
+ if id is None:
383
+ channel("You need to provide an identifier")
384
+ return
385
+ coolant = kernel.root.coolant
386
+ if coolant.coolant_on_by_id(id):
387
+ channel(f"Coolant {id} turned on")
388
+ else:
389
+ channel(f"Method {id} could not be found")
390
+
391
+ @context.console_argument("id", type=str)
392
+ @context.console_command(
393
+ ("coolant_off_by_id", "vent_off_by_id"), help=_("Turns the coolant off using the given method")
394
+ )
395
+ def turn_coolant_off_by_id(command, channel, _, id=None, **kwargs):
396
+ if id is None:
397
+ channel("You need to provide an identifier")
398
+ return
399
+ coolant = kernel.root.coolant
400
+ if coolant.coolant_off_by_id(id):
401
+ channel(f"Coolant {id} turned off")
402
+ else:
403
+ channel(f"Method {id} could not be found")
@@ -0,0 +1,204 @@
1
+ """
2
+ Try to detect some common encoding patterns.
3
+ Based on https://github.com/magnetikonline/py-encoding-detect
4
+
5
+ It will detect the following encodings of a text file:
6
+
7
+ ASCII
8
+ UTF-8
9
+ UTF-16BE
10
+ UTF-16LE
11
+
12
+ """
13
+
14
+
15
+ class EncodingDetectFile:
16
+ ENCODING_ASCII = "ascii"
17
+ ENCODING_CP1252 = "cp1252"
18
+ ENCODING_UTF_8 = "utf_8"
19
+ ENCODING_UTF_16_BE = "utf_16_be"
20
+ ENCODING_UTF_16_LE = "utf_16_le"
21
+
22
+ # http://unicode.org/faq/utf_bom.html#BOM
23
+ BOM_UTF_8 = "\xef\xbb\xbf"
24
+ BOM_UTF_16_BE = "\xfe\xff"
25
+ BOM_UTF_16_LE = "\xff\xfe"
26
+
27
+ BYTE_EOL = (13, 10) # \r\n
28
+
29
+ UTF_16_NULL_PERCENT_POSITIVE = 0.7
30
+ UTF_16_NULL_PERCENT_NEGATIVE = 0.1
31
+
32
+ def _detect_bom(self, fh):
33
+ def result(encoding, bom_marker):
34
+ return (encoding, bom_marker, None)
35
+
36
+ # test 2 byte UTF-16 BOMs
37
+ file_data = fh.read(2)
38
+ # print(f"first 2 bytes: {file_data}")
39
+ if file_data == EncodingDetectFile.BOM_UTF_16_BE:
40
+ return result(
41
+ EncodingDetectFile.ENCODING_UTF_16_BE, EncodingDetectFile.BOM_UTF_16_BE
42
+ )
43
+
44
+ if file_data == EncodingDetectFile.BOM_UTF_16_LE:
45
+ return result(
46
+ EncodingDetectFile.ENCODING_UTF_16_LE, EncodingDetectFile.BOM_UTF_16_LE
47
+ )
48
+
49
+ # test 3 byte UTF-8 BOM
50
+ file_data += fh.read(1)
51
+ # print(f"first 3 bytes: {file_data}")
52
+ if file_data == EncodingDetectFile.BOM_UTF_8:
53
+ return result(
54
+ EncodingDetectFile.ENCODING_UTF_8, EncodingDetectFile.BOM_UTF_8
55
+ )
56
+
57
+ # no BOM marker - return bytes read so far
58
+ return False, False, file_data
59
+
60
+ def _detect_ascii_utf8(self, file_data):
61
+ ascii_chars_only = True
62
+
63
+ byte_follow = 0
64
+ for file_byte in file_data:
65
+ # process additional character byte(s)
66
+ if byte_follow:
67
+ if 128 <= file_byte <= 191:
68
+ byte_follow -= 1
69
+ ascii_chars_only = False
70
+ continue
71
+
72
+ # not ASCII or UTF-8
73
+ return False
74
+
75
+ # determine byte length of character
76
+ # https://en.wikipedia.org/wiki/UTF-8#Codepage_layout
77
+ if 1 <= file_byte <= 127:
78
+ # single byte
79
+ continue
80
+
81
+ if 194 <= file_byte <= 223:
82
+ # one byte follows
83
+ byte_follow = 1
84
+ continue
85
+
86
+ if 224 <= file_byte <= 239:
87
+ # two bytes follow
88
+ byte_follow = 2
89
+ continue
90
+
91
+ if 240 <= file_byte <= 244:
92
+ # three bytes follow
93
+ byte_follow = 3
94
+ continue
95
+
96
+ # not ASCII or UTF-8
97
+ return EncodingDetectFile.ENCODING_CP1252
98
+
99
+ # end of file data [byte_follow] must be zero to ensure last character was consumed
100
+ if byte_follow:
101
+ return False
102
+
103
+ # success - return ASCII or UTF-8 result
104
+ return (
105
+ EncodingDetectFile.ENCODING_ASCII
106
+ if (ascii_chars_only)
107
+ else EncodingDetectFile.ENCODING_UTF_8
108
+ )
109
+
110
+ def _detect_utf16(self, file_data):
111
+ null_byte_odd, null_byte_even = 0, 0
112
+ eol_odd, eol_even = 0, 0
113
+
114
+ odd_byte = None
115
+ for file_byte in file_data:
116
+ # build pairs of bytes
117
+ if odd_byte is None:
118
+ odd_byte = file_byte
119
+ continue
120
+
121
+ # look for odd/even null byte and check other byte for EOL
122
+ if odd_byte == 0:
123
+ null_byte_odd += 1
124
+ if file_byte in EncodingDetectFile.BYTE_EOL:
125
+ eol_even += 1
126
+
127
+ elif file_byte == 0:
128
+ null_byte_even += 1
129
+ if odd_byte in EncodingDetectFile.BYTE_EOL:
130
+ eol_odd += 1
131
+
132
+ odd_byte = None
133
+
134
+ # attempt detection based on line endings
135
+ if (not eol_odd) and eol_even:
136
+ return EncodingDetectFile.ENCODING_UTF_16_BE
137
+
138
+ if eol_odd and (not eol_even):
139
+ return EncodingDetectFile.ENCODING_UTF_16_LE
140
+
141
+ # can't detect on line endings - evaluate ratio of null bytes in odd/even positions
142
+ # this will give an indication of how much ASCII (1-127) level text is present
143
+ data_size_half = len(file_data) / 2
144
+ threshold_positive = int(
145
+ data_size_half * EncodingDetectFile.UTF_16_NULL_PERCENT_POSITIVE
146
+ )
147
+ threshold_negative = int(
148
+ data_size_half * EncodingDetectFile.UTF_16_NULL_PERCENT_NEGATIVE
149
+ )
150
+
151
+ # must have enough file data to have value ([threshold_positive] must be non-zero)
152
+ if threshold_positive:
153
+ if (null_byte_odd > threshold_positive) and (
154
+ null_byte_even < threshold_negative
155
+ ):
156
+ return EncodingDetectFile.ENCODING_UTF_16_BE
157
+
158
+ if (null_byte_odd < threshold_negative) and (
159
+ null_byte_even > threshold_positive
160
+ ):
161
+ return EncodingDetectFile.ENCODING_UTF_16_LE
162
+
163
+ # not UTF-16 - or insufficient data to determine with confidence
164
+ return False
165
+
166
+ def load(self, file_path):
167
+ # open file
168
+ try:
169
+ fh = open(file_path, "rb")
170
+ except Exception:
171
+ return False
172
+
173
+ # detect a byte order mark (BOM)
174
+ file_encoding, bom_marker, file_data = self._detect_bom(fh)
175
+ if file_encoding:
176
+ # file has a BOM - decode everything past it
177
+ try:
178
+ decode = fh.read().decode(file_encoding)
179
+ except UnicodeDecodeError:
180
+ return False
181
+ # print(f"decoded: {decode}")
182
+ fh.close()
183
+
184
+ return (file_encoding, bom_marker, decode)
185
+
186
+ # no BOM - read remaining file data
187
+ file_data += fh.read()
188
+ # print(f"All bytes: {file_data}")
189
+ fh.close()
190
+
191
+ # test for ASCII/UTF-8
192
+ file_encoding = self._detect_ascii_utf8(file_data)
193
+ if file_encoding:
194
+ # file is ASCII or UTF-8 (without BOM)
195
+ return (file_encoding, None, file_data.decode(file_encoding))
196
+
197
+ # test for UTF-16
198
+ file_encoding = self._detect_utf16(file_data)
199
+ if file_encoding:
200
+ # file is UTF-16(-like) (without BOM)
201
+ return (file_encoding, None, file_data.decode(file_encoding))
202
+
203
+ # can't determine encoding
204
+ return False