snappy 3.0.3__cp38-cp38-macosx_11_0_arm64.whl → 3.2__cp38-cp38-macosx_11_0_arm64.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (401) hide show
  1. snappy/CyOpenGL.cpython-38-darwin.so +0 -0
  2. snappy/SnapPy.cpython-38-darwin.so +0 -0
  3. snappy/SnapPyHP.cpython-38-darwin.so +0 -0
  4. snappy/__init__.py +373 -426
  5. snappy/app.py +240 -75
  6. snappy/app_menus.py +93 -78
  7. snappy/browser.py +87 -63
  8. snappy/cache.py +5 -8
  9. snappy/canonical.py +249 -0
  10. snappy/{verify/cusp_shapes.py → cusps/__init__.py} +11 -19
  11. snappy/cusps/cusp_area_matrix.py +101 -0
  12. snappy/{verify/cusp_areas.py → cusps/cusp_areas_from_matrix.py} +39 -54
  13. snappy/cusps/maximal_cusp_area_matrix.py +136 -0
  14. snappy/cusps/test.py +21 -0
  15. snappy/cusps/trig_cusp_area_matrix.py +63 -0
  16. snappy/database.py +40 -31
  17. snappy/db_utilities.py +13 -14
  18. snappy/decorated_isosig.py +377 -133
  19. snappy/dev/extended_ptolemy/complexVolumesClosed.py +42 -9
  20. snappy/dev/extended_ptolemy/extended.py +32 -25
  21. snappy/dev/extended_ptolemy/giac_rur.py +23 -8
  22. snappy/dev/extended_ptolemy/phc_wrapper.py +10 -10
  23. snappy/dev/vericlosed/computeApproxHyperbolicStructureOrb.py +2 -1
  24. snappy/dev/vericlosed/gimbalLoopFinder.py +5 -5
  25. snappy/dev/vericlosed/hyperbolicStructure.py +3 -3
  26. snappy/dev/vericlosed/oneVertexTruncatedComplex.py +2 -2
  27. snappy/dev/vericlosed/truncatedComplex.py +3 -2
  28. snappy/dev/vericlosed/verifyHyperbolicStructureEngine.py +4 -3
  29. snappy/doc/_images/geodesics.jpg +0 -0
  30. snappy/doc/_images/m004_paper_plane_on_systole.jpg +0 -0
  31. snappy/doc/_images/m125_paper_plane.jpg +0 -0
  32. snappy/doc/_images/o9_00000_systole_paper_plane.jpg +0 -0
  33. snappy/doc/_images/o9_00000_systole_paper_plane_closer.jpg +0 -0
  34. snappy/doc/_sources/additional_classes.rst.txt +1 -0
  35. snappy/doc/_sources/credits.rst.txt +6 -1
  36. snappy/doc/_sources/development.rst.txt +69 -50
  37. snappy/doc/_sources/index.rst.txt +101 -66
  38. snappy/doc/_sources/installing.rst.txt +148 -165
  39. snappy/doc/_sources/news.rst.txt +136 -32
  40. snappy/doc/_sources/ptolemy.rst.txt +1 -1
  41. snappy/doc/_sources/ptolemy_examples1.rst.txt +9 -8
  42. snappy/doc/_sources/ptolemy_examples2.rst.txt +3 -3
  43. snappy/doc/_sources/ptolemy_examples3.rst.txt +14 -14
  44. snappy/doc/_sources/ptolemy_prelim.rst.txt +1 -1
  45. snappy/doc/_sources/snap.rst.txt +2 -2
  46. snappy/doc/_sources/snappy.rst.txt +1 -1
  47. snappy/doc/_sources/triangulation.rst.txt +3 -2
  48. snappy/doc/_sources/verify.rst.txt +89 -29
  49. snappy/doc/_sources/verify_internals.rst.txt +5 -16
  50. snappy/doc/_static/SnapPy-horizontal-128.png +0 -0
  51. snappy/doc/_static/SnapPy.ico +0 -0
  52. snappy/doc/_static/_sphinx_javascript_frameworks_compat.js +123 -0
  53. snappy/doc/_static/basic.css +47 -27
  54. snappy/doc/_static/css/badge_only.css +1 -0
  55. snappy/doc/_static/css/fonts/Roboto-Slab-Bold.woff +0 -0
  56. snappy/doc/_static/css/fonts/Roboto-Slab-Bold.woff2 +0 -0
  57. snappy/doc/_static/css/fonts/Roboto-Slab-Regular.woff +0 -0
  58. snappy/doc/_static/css/fonts/Roboto-Slab-Regular.woff2 +0 -0
  59. snappy/doc/_static/css/fonts/fontawesome-webfont.eot +0 -0
  60. snappy/doc/_static/css/fonts/fontawesome-webfont.svg +2671 -0
  61. snappy/doc/_static/css/fonts/fontawesome-webfont.ttf +0 -0
  62. snappy/doc/_static/css/fonts/fontawesome-webfont.woff +0 -0
  63. snappy/doc/_static/css/fonts/fontawesome-webfont.woff2 +0 -0
  64. snappy/doc/_static/css/fonts/lato-bold-italic.woff +0 -0
  65. snappy/doc/_static/css/fonts/lato-bold-italic.woff2 +0 -0
  66. snappy/doc/_static/css/fonts/lato-bold.woff +0 -0
  67. snappy/doc/_static/css/fonts/lato-bold.woff2 +0 -0
  68. snappy/doc/_static/css/fonts/lato-normal-italic.woff +0 -0
  69. snappy/doc/_static/css/fonts/lato-normal-italic.woff2 +0 -0
  70. snappy/doc/_static/css/fonts/lato-normal.woff +0 -0
  71. snappy/doc/_static/css/fonts/lato-normal.woff2 +0 -0
  72. snappy/doc/_static/css/theme.css +4 -0
  73. snappy/doc/_static/doctools.js +107 -274
  74. snappy/doc/_static/documentation_options.js +6 -5
  75. snappy/doc/_static/fonts/Lato/lato-bold.eot +0 -0
  76. snappy/doc/_static/fonts/Lato/lato-bold.ttf +0 -0
  77. snappy/doc/_static/fonts/Lato/lato-bold.woff +0 -0
  78. snappy/doc/_static/fonts/Lato/lato-bold.woff2 +0 -0
  79. snappy/doc/_static/fonts/Lato/lato-bolditalic.eot +0 -0
  80. snappy/doc/_static/fonts/Lato/lato-bolditalic.ttf +0 -0
  81. snappy/doc/_static/fonts/Lato/lato-bolditalic.woff +0 -0
  82. snappy/doc/_static/fonts/Lato/lato-bolditalic.woff2 +0 -0
  83. snappy/doc/_static/fonts/Lato/lato-italic.eot +0 -0
  84. snappy/doc/_static/fonts/Lato/lato-italic.ttf +0 -0
  85. snappy/doc/_static/fonts/Lato/lato-italic.woff +0 -0
  86. snappy/doc/_static/fonts/Lato/lato-italic.woff2 +0 -0
  87. snappy/doc/_static/fonts/Lato/lato-regular.eot +0 -0
  88. snappy/doc/_static/fonts/Lato/lato-regular.ttf +0 -0
  89. snappy/doc/_static/fonts/Lato/lato-regular.woff +0 -0
  90. snappy/doc/_static/fonts/Lato/lato-regular.woff2 +0 -0
  91. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot +0 -0
  92. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf +0 -0
  93. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff +0 -0
  94. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 +0 -0
  95. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot +0 -0
  96. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf +0 -0
  97. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff +0 -0
  98. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 +0 -0
  99. snappy/doc/_static/jquery.js +2 -2
  100. snappy/doc/_static/js/badge_only.js +1 -0
  101. snappy/doc/_static/js/theme.js +1 -0
  102. snappy/doc/_static/js/versions.js +228 -0
  103. snappy/doc/_static/language_data.js +3 -101
  104. snappy/doc/_static/pygments.css +1 -0
  105. snappy/doc/_static/searchtools.js +489 -398
  106. snappy/doc/_static/snappy_furo.css +33 -0
  107. snappy/doc/_static/snappy_sphinx_rtd_theme.css +42 -0
  108. snappy/doc/_static/sphinx_highlight.js +154 -0
  109. snappy/doc/additional_classes.html +688 -263
  110. snappy/doc/bugs.html +107 -94
  111. snappy/doc/censuses.html +155 -127
  112. snappy/doc/credits.html +115 -104
  113. snappy/doc/development.html +184 -146
  114. snappy/doc/genindex.html +287 -204
  115. snappy/doc/index.html +189 -150
  116. snappy/doc/installing.html +259 -266
  117. snappy/doc/manifold.html +1626 -592
  118. snappy/doc/manifoldhp.html +119 -105
  119. snappy/doc/news.html +198 -104
  120. snappy/doc/objects.inv +0 -0
  121. snappy/doc/other.html +117 -105
  122. snappy/doc/platonic_census.html +161 -114
  123. snappy/doc/plink.html +113 -105
  124. snappy/doc/ptolemy.html +131 -108
  125. snappy/doc/ptolemy_classes.html +242 -223
  126. snappy/doc/ptolemy_examples1.html +144 -130
  127. snappy/doc/ptolemy_examples2.html +141 -129
  128. snappy/doc/ptolemy_examples3.html +148 -132
  129. snappy/doc/ptolemy_examples4.html +131 -111
  130. snappy/doc/ptolemy_prelim.html +162 -138
  131. snappy/doc/py-modindex.html +104 -69
  132. snappy/doc/screenshots.html +117 -108
  133. snappy/doc/search.html +115 -84
  134. snappy/doc/searchindex.js +1 -1
  135. snappy/doc/snap.html +109 -96
  136. snappy/doc/snappy.html +134 -97
  137. snappy/doc/spherogram.html +259 -187
  138. snappy/doc/todo.html +107 -94
  139. snappy/doc/triangulation.html +1380 -111
  140. snappy/doc/tutorial.html +107 -94
  141. snappy/doc/verify.html +194 -125
  142. snappy/doc/verify_internals.html +248 -686
  143. snappy/drilling/__init__.py +456 -0
  144. snappy/drilling/barycentric.py +103 -0
  145. snappy/drilling/constants.py +5 -0
  146. snappy/drilling/crush.py +270 -0
  147. snappy/drilling/cusps.py +125 -0
  148. snappy/drilling/debug.py +242 -0
  149. snappy/drilling/epsilons.py +6 -0
  150. snappy/drilling/exceptions.py +55 -0
  151. snappy/drilling/moves.py +620 -0
  152. snappy/drilling/peripheral_curves.py +210 -0
  153. snappy/drilling/perturb.py +188 -0
  154. snappy/drilling/shorten.py +36 -0
  155. snappy/drilling/subdivide.py +274 -0
  156. snappy/drilling/test.py +23 -0
  157. snappy/drilling/test_cases.py +126 -0
  158. snappy/drilling/tracing.py +351 -0
  159. snappy/exceptions.py +23 -3
  160. snappy/export_stl.py +20 -14
  161. snappy/exterior_to_link/__init__.py +2 -0
  162. snappy/exterior_to_link/barycentric_geometry.py +463 -0
  163. snappy/exterior_to_link/exceptions.py +6 -0
  164. snappy/exterior_to_link/geodesic_map.json +14408 -0
  165. snappy/exterior_to_link/hyp_utils.py +112 -0
  166. snappy/exterior_to_link/link_projection.py +323 -0
  167. snappy/exterior_to_link/main.py +197 -0
  168. snappy/exterior_to_link/mcomplex_with_expansion.py +261 -0
  169. snappy/exterior_to_link/mcomplex_with_link.py +687 -0
  170. snappy/exterior_to_link/mcomplex_with_memory.py +162 -0
  171. snappy/exterior_to_link/pl_utils.py +491 -0
  172. snappy/exterior_to_link/put_in_S3.py +156 -0
  173. snappy/exterior_to_link/rational_linear_algebra.py +123 -0
  174. snappy/exterior_to_link/rational_linear_algebra_wrapped.py +135 -0
  175. snappy/exterior_to_link/simplify_to_base_tri.py +114 -0
  176. snappy/exterior_to_link/stored_moves.py +475 -0
  177. snappy/exterior_to_link/test.py +31 -0
  178. snappy/geometric_structure/__init__.py +212 -0
  179. snappy/geometric_structure/cusp_neighborhood/__init__.py +3 -0
  180. snappy/geometric_structure/cusp_neighborhood/complex_cusp_cross_section.py +697 -0
  181. snappy/geometric_structure/cusp_neighborhood/cusp_cross_section_base.py +484 -0
  182. snappy/geometric_structure/cusp_neighborhood/exceptions.py +42 -0
  183. snappy/geometric_structure/cusp_neighborhood/real_cusp_cross_section.py +298 -0
  184. snappy/geometric_structure/cusp_neighborhood/tiles_for_cusp_neighborhood.py +159 -0
  185. snappy/geometric_structure/cusp_neighborhood/vertices.py +32 -0
  186. snappy/geometric_structure/geodesic/__init__.py +0 -0
  187. snappy/geometric_structure/geodesic/add_core_curves.py +152 -0
  188. snappy/geometric_structure/geodesic/avoid_core_curves.py +369 -0
  189. snappy/geometric_structure/geodesic/canonical_keys.py +52 -0
  190. snappy/geometric_structure/geodesic/check_away_from_core_curve.py +60 -0
  191. snappy/geometric_structure/geodesic/constants.py +6 -0
  192. snappy/geometric_structure/geodesic/exceptions.py +22 -0
  193. snappy/geometric_structure/geodesic/fixed_points.py +93 -0
  194. snappy/geometric_structure/geodesic/geodesic_start_point_info.py +435 -0
  195. snappy/geometric_structure/geodesic/graph_trace_helper.py +67 -0
  196. snappy/geometric_structure/geodesic/line.py +30 -0
  197. snappy/geometric_structure/geodesic/multiplicity.py +127 -0
  198. snappy/geometric_structure/geodesic/tiles_for_geodesic.py +101 -0
  199. snappy/geometric_structure/test.py +22 -0
  200. snappy/gui.py +36 -36
  201. snappy/horoviewer.py +50 -48
  202. snappy/hyperboloid/__init__.py +212 -0
  203. snappy/hyperboloid/distances.py +245 -0
  204. snappy/hyperboloid/horoball.py +19 -0
  205. snappy/hyperboloid/line.py +35 -0
  206. snappy/hyperboloid/point.py +9 -0
  207. snappy/hyperboloid/triangle.py +29 -0
  208. snappy/{infodialog.py → infowindow.py} +32 -33
  209. snappy/isometry_signature.py +382 -0
  210. snappy/len_spec/__init__.py +596 -0
  211. snappy/len_spec/geodesic_info.py +110 -0
  212. snappy/len_spec/geodesic_key_info_dict.py +117 -0
  213. snappy/len_spec/geodesic_piece.py +143 -0
  214. snappy/len_spec/geometric_structure.py +182 -0
  215. snappy/len_spec/geometry.py +80 -0
  216. snappy/len_spec/length_spectrum_geodesic_info.py +170 -0
  217. snappy/len_spec/spine.py +206 -0
  218. snappy/len_spec/test.py +24 -0
  219. snappy/len_spec/test_cases.py +69 -0
  220. snappy/len_spec/tile.py +275 -0
  221. snappy/len_spec/word.py +86 -0
  222. snappy/manifolds/__init__.py +1 -1
  223. snappy/math_basics.py +176 -0
  224. snappy/matrix.py +525 -0
  225. snappy/number.py +97 -21
  226. snappy/numeric_output_checker.py +37 -27
  227. snappy/pari.py +30 -69
  228. snappy/phone_home.py +25 -20
  229. snappy/polyviewer.py +39 -37
  230. snappy/ptolemy/__init__.py +4 -6
  231. snappy/ptolemy/component.py +14 -12
  232. snappy/ptolemy/coordinates.py +312 -295
  233. snappy/ptolemy/fieldExtensions.py +14 -12
  234. snappy/ptolemy/findLoops.py +43 -31
  235. snappy/ptolemy/geometricRep.py +24 -26
  236. snappy/ptolemy/homology.py +12 -7
  237. snappy/ptolemy/manifoldMethods.py +69 -70
  238. snappy/ptolemy/matrix.py +65 -26
  239. snappy/ptolemy/numericalSolutionsToGroebnerBasis.py +18 -14
  240. snappy/ptolemy/polynomial.py +125 -119
  241. snappy/ptolemy/processComponents.py +36 -30
  242. snappy/ptolemy/processFileBase.py +79 -18
  243. snappy/ptolemy/processFileDispatch.py +13 -14
  244. snappy/ptolemy/processMagmaFile.py +44 -39
  245. snappy/ptolemy/processRurFile.py +18 -11
  246. snappy/ptolemy/ptolemyGeneralizedObstructionClass.py +20 -17
  247. snappy/ptolemy/ptolemyObstructionClass.py +13 -17
  248. snappy/ptolemy/ptolemyVariety.py +190 -121
  249. snappy/ptolemy/ptolemyVarietyPrimeIdealGroebnerBasis.py +20 -19
  250. snappy/ptolemy/reginaWrapper.py +25 -29
  251. snappy/ptolemy/rur.py +6 -14
  252. snappy/ptolemy/solutionsToPrimeIdealGroebnerBasis.py +27 -22
  253. snappy/ptolemy/test.py +247 -188
  254. snappy/ptolemy/utilities.py +41 -43
  255. snappy/raytracing/__init__.py +64 -0
  256. snappy/raytracing/additional_horospheres.py +64 -0
  257. snappy/raytracing/additional_len_spec_choices.py +63 -0
  258. snappy/raytracing/cohomology_fractal.py +10 -6
  259. snappy/raytracing/eyeball.py +123 -0
  260. snappy/raytracing/finite_raytracing_data.py +48 -38
  261. snappy/raytracing/finite_viewer.py +218 -210
  262. snappy/raytracing/geodesic_tube_info.py +174 -0
  263. snappy/raytracing/geodesics.py +246 -0
  264. snappy/raytracing/geodesics_window.py +258 -0
  265. snappy/raytracing/gui_utilities.py +152 -40
  266. snappy/raytracing/hyperboloid_navigation.py +102 -52
  267. snappy/raytracing/hyperboloid_utilities.py +114 -261
  268. snappy/raytracing/ideal_raytracing_data.py +256 -179
  269. snappy/raytracing/inside_viewer.py +522 -253
  270. snappy/raytracing/pack.py +22 -0
  271. snappy/raytracing/raytracing_data.py +46 -34
  272. snappy/raytracing/raytracing_view.py +190 -109
  273. snappy/raytracing/shaders/Eye.png +0 -0
  274. snappy/raytracing/shaders/NonGeometric.png +0 -0
  275. snappy/raytracing/shaders/__init__.py +60 -4
  276. snappy/raytracing/shaders/fragment.glsl +575 -148
  277. snappy/raytracing/test.py +29 -0
  278. snappy/raytracing/tooltip.py +146 -0
  279. snappy/raytracing/upper_halfspace_utilities.py +98 -0
  280. snappy/raytracing/view_scale_controller.py +98 -0
  281. snappy/raytracing/zoom_slider/__init__.py +32 -29
  282. snappy/raytracing/zoom_slider/test.py +2 -0
  283. snappy/sage_helper.py +69 -123
  284. snappy/{preferences.py → settings.py} +167 -145
  285. snappy/shell.py +4 -0
  286. snappy/snap/__init__.py +12 -8
  287. snappy/snap/character_varieties.py +24 -18
  288. snappy/snap/find_field.py +35 -34
  289. snappy/snap/fundamental_polyhedron.py +99 -85
  290. snappy/snap/generators.py +6 -8
  291. snappy/snap/interval_reps.py +18 -6
  292. snappy/snap/kernel_structures.py +8 -3
  293. snappy/snap/mcomplex_base.py +1 -2
  294. snappy/snap/nsagetools.py +107 -53
  295. snappy/snap/peripheral/__init__.py +1 -1
  296. snappy/snap/peripheral/dual_cellulation.py +15 -7
  297. snappy/snap/peripheral/link.py +20 -16
  298. snappy/snap/peripheral/peripheral.py +22 -14
  299. snappy/snap/peripheral/surface.py +47 -50
  300. snappy/snap/peripheral/test.py +8 -8
  301. snappy/snap/polished_reps.py +65 -40
  302. snappy/snap/shapes.py +41 -22
  303. snappy/snap/slice_obs_HKL.py +64 -25
  304. snappy/snap/t3mlite/arrow.py +88 -51
  305. snappy/snap/t3mlite/corner.py +5 -6
  306. snappy/snap/t3mlite/edge.py +32 -21
  307. snappy/snap/t3mlite/face.py +7 -9
  308. snappy/snap/t3mlite/files.py +31 -23
  309. snappy/snap/t3mlite/homology.py +14 -10
  310. snappy/snap/t3mlite/linalg.py +158 -56
  311. snappy/snap/t3mlite/mcomplex.py +739 -291
  312. snappy/snap/t3mlite/perm4.py +236 -84
  313. snappy/snap/t3mlite/setup.py +9 -10
  314. snappy/snap/t3mlite/simplex.py +65 -48
  315. snappy/snap/t3mlite/spun.py +42 -30
  316. snappy/snap/t3mlite/surface.py +45 -45
  317. snappy/snap/t3mlite/test.py +3 -0
  318. snappy/snap/t3mlite/test_vs_regina.py +17 -13
  319. snappy/snap/t3mlite/tetrahedron.py +25 -24
  320. snappy/snap/t3mlite/vertex.py +8 -13
  321. snappy/snap/test.py +45 -52
  322. snappy/snap/utilities.py +66 -65
  323. snappy/test.py +155 -158
  324. snappy/test_cases.py +263 -0
  325. snappy/testing.py +131 -0
  326. snappy/tiling/__init__.py +2 -0
  327. snappy/tiling/canonical_key_dict.py +59 -0
  328. snappy/tiling/dict_based_set.py +79 -0
  329. snappy/tiling/floor.py +49 -0
  330. snappy/tiling/hyperboloid_dict.py +54 -0
  331. snappy/tiling/iter_utils.py +78 -0
  332. snappy/tiling/lifted_tetrahedron.py +22 -0
  333. snappy/tiling/lifted_tetrahedron_set.py +54 -0
  334. snappy/tiling/real_hash_dict.py +164 -0
  335. snappy/tiling/test.py +23 -0
  336. snappy/tiling/tile.py +215 -0
  337. snappy/tiling/triangle.py +33 -0
  338. snappy/tkterminal.py +313 -203
  339. snappy/twister/main.py +1 -8
  340. snappy/twister/twister_core.cpython-38-darwin.so +0 -0
  341. snappy/upper_halfspace/__init__.py +146 -0
  342. snappy/upper_halfspace/ideal_point.py +26 -0
  343. snappy/verify/__init__.py +4 -8
  344. snappy/verify/{verifyCanonical.py → canonical.py} +114 -97
  345. snappy/verify/complex_volume/__init__.py +3 -2
  346. snappy/verify/complex_volume/adjust_torsion.py +13 -11
  347. snappy/verify/complex_volume/closed.py +29 -24
  348. snappy/verify/complex_volume/compute_ptolemys.py +8 -6
  349. snappy/verify/complex_volume/cusped.py +10 -9
  350. snappy/verify/complex_volume/extended_bloch.py +14 -12
  351. snappy/verify/{cuspTranslations.py → cusp_translations.py} +15 -14
  352. snappy/verify/edge_equations.py +80 -0
  353. snappy/verify/exceptions.py +23 -56
  354. snappy/verify/{verifyHyperbolicity.py → hyperbolicity.py} +19 -15
  355. snappy/verify/interval_newton_shapes_engine.py +51 -211
  356. snappy/verify/interval_tree.py +27 -25
  357. snappy/verify/krawczyk_shapes_engine.py +47 -50
  358. snappy/verify/maximal_cusp_area_matrix/__init__.py +17 -86
  359. snappy/verify/maximal_cusp_area_matrix/cusp_tiling_engine.py +58 -48
  360. snappy/verify/maximal_cusp_area_matrix/cusp_translate_engine.py +53 -57
  361. snappy/verify/{realAlgebra.py → real_algebra.py} +26 -20
  362. snappy/verify/shapes.py +10 -7
  363. snappy/verify/short_slopes.py +41 -42
  364. snappy/verify/{squareExtensions.py → square_extensions.py} +96 -92
  365. snappy/verify/test.py +59 -57
  366. snappy/verify/upper_halfspace/extended_matrix.py +5 -5
  367. snappy/verify/upper_halfspace/finite_point.py +44 -31
  368. snappy/verify/upper_halfspace/ideal_point.py +69 -57
  369. snappy/verify/volume.py +15 -12
  370. snappy/version.py +2 -3
  371. {snappy-3.0.3.dist-info → snappy-3.2.dist-info}/METADATA +14 -12
  372. snappy-3.2.dist-info/RECORD +503 -0
  373. {snappy-3.0.3.dist-info → snappy-3.2.dist-info}/WHEEL +1 -1
  374. {snappy-3.0.3.dist-info → snappy-3.2.dist-info}/entry_points.txt +0 -1
  375. {snappy-3.0.3.dist-info → snappy-3.2.dist-info}/top_level.txt +10 -1
  376. snappy/doc/_sources/verify_canon.rst.txt +0 -90
  377. snappy/doc/_static/classic.css +0 -266
  378. snappy/doc/_static/jquery-3.5.1.js +0 -10872
  379. snappy/doc/_static/sidebar.js +0 -159
  380. snappy/doc/_static/underscore-1.13.1.js +0 -2042
  381. snappy/doc/_static/underscore.js +0 -6
  382. snappy/doc/verify_canon.html +0 -283
  383. snappy/ppm_to_png.py +0 -243
  384. snappy/togl/__init__.py +0 -3
  385. snappy/togl/darwin-tk8.6/Togl2.1/LICENSE +0 -28
  386. snappy/togl/darwin-tk8.6/Togl2.1/libTogl2.1.dylib +0 -0
  387. snappy/togl/darwin-tk8.6/Togl2.1/pkgIndex.tcl +0 -5
  388. snappy/togl/linux2-x86_64-tk8.6/Togl2.1/LICENSE +0 -28
  389. snappy/togl/linux2-x86_64-tk8.6/Togl2.1/libTogl2.1.so +0 -0
  390. snappy/togl/linux2-x86_64-tk8.6/Togl2.1/pkgIndex.tcl +0 -5
  391. snappy/togl/win32VC-tk8.6/Togl2.1/LICENSE +0 -28
  392. snappy/togl/win32VC-tk8.6/Togl2.1/Togl21.dll +0 -0
  393. snappy/togl/win32VC-tk8.6/Togl2.1/Togl21.lib +0 -0
  394. snappy/togl/win32VC-tk8.6/Togl2.1/pkgIndex.tcl +0 -6
  395. snappy/togl/win32VC-x86_64-tk8.6/Togl2.1/LICENSE +0 -28
  396. snappy/togl/win32VC-x86_64-tk8.6/Togl2.1/Togl21.dll +0 -0
  397. snappy/togl/win32VC-x86_64-tk8.6/Togl2.1/Togl21.lib +0 -0
  398. snappy/togl/win32VC-x86_64-tk8.6/Togl2.1/pkgIndex.tcl +0 -6
  399. snappy/verify/cuspCrossSection.py +0 -1413
  400. snappy/verify/mathHelpers.py +0 -64
  401. snappy-3.0.3.dist-info/RECORD +0 -360
snappy/tkterminal.py CHANGED
@@ -1,35 +1,71 @@
1
1
  # -*- coding: utf-8 -*-
2
- import os, sys, re, signal, IPython
3
- from builtins import range
4
- from IPython.utils import io
5
- from IPython.core.autocall import IPyAutocall
6
- import snappy
2
+ import os
3
+ import sys
4
+ import re
7
5
  from urllib.request import pathname2url
8
- from .gui import *
6
+ import tkinter as Tk_
7
+ from tkinter import ttk
8
+ from tkinter.font import Font
9
+ from tkinter.font import families as font_families
10
+ from tkinter.messagebox import askyesno
11
+ from IPython.utils import io
9
12
 
10
- snappy_path = os.path.abspath(os.path.dirname(snappy.__file__))
11
- icon_file = os.path.join(snappy_path, 'info_icon.gif')
12
- debug_Tk = False
13
+ debug_Tk = True
13
14
  ansi_seqs = re.compile(r'(?:\x01*\x1b\[((?:[0-9]*;)*[0-9]*.)\x02*)*([^\x01\x1b]*)',
14
15
  re.MULTILINE)
15
- ansi_colors = {'0;30m': 'Black',
16
- '0;31m': 'Red',
17
- '0;32m': 'Green',
18
- '0;33m': 'Brown',
19
- '0;34m': 'Blue',
20
- '0;35m': 'Purple',
21
- '0;36m': 'Cyan',
22
- '0;37m': 'LightGray',
23
- '1;30m': 'Black', #'DarkGray',
24
- '1;31m': 'DarkRed',
25
- '1;32m': 'SeaGreen',
26
- '1;33m': 'Yellow',
27
- '1;34m': 'LightBlue',
28
- '1;35m': 'MediumPurple',
29
- '1;36m': 'LightCyan',
30
- '1;37m': 'White'}
16
+ ansi_colors = {'0;30m': 'Black',
17
+ '0;31m': 'Red',
18
+ '0;32m': 'Green',
19
+ '0;33m': 'Brown',
20
+ '0;34m': 'Blue',
21
+ '0;35m': 'Purple',
22
+ '0;36m': 'Cyan',
23
+ '0;37m': 'LightGray',
24
+ '1;30m': 'Black', # 'DarkGray',
25
+ '1;31m': 'DarkRed',
26
+ '1;32m': 'SeaGreen',
27
+ '1;33m': 'Yellow',
28
+ '1;34m': 'LightBlue',
29
+ '1;35m': 'MediumPurple',
30
+ '1;36m': 'LightCyan',
31
+ '1;37m': 'White'}
31
32
  delims = re.compile(r'[\s\[\]\{\}\(\)\+\-\=\'`~!@#\$\^\&\*]+')
32
33
 
34
+
35
+ class FontChoice:
36
+ def __init__(self, family, size, weight, slant):
37
+ self.family = family
38
+ self.size = size
39
+ self.weight = weight
40
+ self.slant = slant
41
+ self.rest = f'{self.weight} {self.slant}'
42
+
43
+ def as_tuple(self):
44
+ size = self.size
45
+ if sys.platform == 'darwin' and Tk_.TkVersion >= 9.0:
46
+ size = int(size/1.3)
47
+ return (self.family, size, self.rest)
48
+
49
+ def __repr__(self):
50
+ return 'FontChoice' + repr((self.family, self.size, self.weight, self.slant))
51
+
52
+ def bold(self):
53
+ return FontChoice(self.family, self.size, 'bold', self.slant)
54
+
55
+
56
+ def default_terminal_font():
57
+ size = 13 if sys.platform == 'darwin' else 11
58
+ family = Font(font='TkFixedFont').actual()['family']
59
+ if sys.platform == 'win32':
60
+ # Default is Courier New which is ugly and appears blurry.
61
+ available = font_families()
62
+ for better in ['Consolas', 'Cascadia Mono SemiLight']:
63
+ if better in available:
64
+ family = better
65
+
66
+ return FontChoice(family, size, 'normal', 'roman')
67
+
68
+
33
69
  class Tk(Tk_.Tk):
34
70
  def __init__(self, error_handler=None):
35
71
  Tk_.Tk.__init__(self, className='snappy')
@@ -37,14 +73,9 @@ class Tk(Tk_.Tk):
37
73
  # calls this function to report their occurrence.
38
74
  if error_handler:
39
75
  self.report_callback_exception = error_handler
40
- # In Python 2.7 the _default root does not get set correctly.
41
- if not Tk_._default_root:
42
- Tk_._default_root = self
43
76
 
44
- # Some ideas for the TkTerm class were borrowed from code written by
45
- # Eitan Isaacson, IBM Corp.
46
77
 
47
- class TkTerm:
78
+ class TkTerminalBase:
48
79
  """
49
80
  A Tkinter terminal window that runs an IPython shell. This class
50
81
  supports the IOStream interface, and can function as a replacement
@@ -56,8 +87,6 @@ class TkTerm:
56
87
  io.stdout = sys.stdout = self
57
88
  else:
58
89
  self.window = window = Tk(self.report_callback_exception)
59
- self.encoding = sys.stdout.encoding
60
- self.saved_io = (sys.stdout, sys.stderr)
61
90
  io.stdout = io.stderr = sys.stdout = sys.stderr = self
62
91
  self._input_buffer = ''
63
92
  self._current_indent = 0
@@ -65,7 +94,6 @@ class TkTerm:
65
94
  window.option_add('*Menu.tearOff', 0)
66
95
  window.title(name)
67
96
  window.protocol("WM_DELETE_WINDOW", self.close)
68
- self.icon = Tk_.PhotoImage(file=icon_file)
69
97
  self.frame = frame = Tk_.Frame(window)
70
98
  self.text = text = Tk_.Text(frame,
71
99
  width=85,
@@ -77,7 +105,7 @@ class TkTerm:
77
105
  highlightthickness=0,
78
106
  relief=Tk_.FLAT
79
107
  )
80
- self.set_font(Font(text, text.cget('font')))
108
+ self.set_font(default_terminal_font())
81
109
  self.scroller = scroller = Tk_.Scrollbar(frame, command=text.yview)
82
110
  text.config(yscrollcommand=scroller.set)
83
111
  scroller.pack(side=Tk_.RIGHT, fill=Tk_.Y, pady=10)
@@ -85,19 +113,16 @@ class TkTerm:
85
113
  frame.pack(fill=Tk_.BOTH, expand=Tk_.YES)
86
114
  text.focus_set()
87
115
  window.bind('<FocusIn>', lambda event=None: text.focus_set())
116
+ text.bind('<Control-c>', self.handle_control_c)
88
117
  text.bind('<KeyPress>', self.handle_keypress)
89
118
  text.bind('<KeyRelease>', self.handle_keyrelease)
90
- if not sys.platform == 'darwin':
91
- text.bind('<Control-c>', self.handle_keypress)
92
119
  text.bind('<Return>', self.handle_return)
93
120
  text.bind('<Shift-Return>', self.handle_shift_return)
94
121
  text.bind('<BackSpace>', self.handle_backspace)
95
122
  text.bind('<Delete>', self.handle_backspace)
96
123
  text.bind('<Tab>', self.handle_tab)
97
124
  text.bind('<Up>', self.handle_up)
98
- text.bind('<Shift-Up>', lambda event : None)
99
125
  text.bind('<Down>', self.handle_down)
100
- text.bind('<Shift-Down>', lambda event : None)
101
126
  text.bind('<Home>', self.go_to_beginning)
102
127
  text.bind('<<Cut>>', self.protect_text)
103
128
  text.bind('<<Copy>>', self.edit_copy)
@@ -113,12 +138,14 @@ class TkTerm:
113
138
  if sys.platform == 'darwin':
114
139
  self.window.bind_all('<Command-Key-q>', self.close)
115
140
  self.window.bind_all('<Command-Key-Left>', self.go_to_beginning)
141
+ self.text.bind('<Command-Key-Up>', self.jump_up)
116
142
  elif sys.platform == 'linux2' or sys.platform == 'linux':
117
143
  self.window.bind_all('<Alt-Key-q>', self.close)
118
144
  self.add_bindings()
119
145
  # 'output_end' marks the end of the text written by us.
120
146
  # Everything above this position should be
121
147
  # immutable, and tagged with the "output" style.
148
+ # Normally it is set at the end of the input prompt.
122
149
  self.text.mark_set('output_end', Tk_.INSERT)
123
150
  self.text.mark_gravity('output_end', Tk_.LEFT)
124
151
  text.tag_config('output')
@@ -157,7 +184,7 @@ class TkTerm:
157
184
  self.banner = shell.banner1
158
185
  else:
159
186
  cprt = 'Type "copyright", "credits" or "license" for more information.'
160
- self.banner = "Python %s on %s\n%s\n(%s)\n" %(
187
+ self.banner = "Python %s on %s\n%s\n(%s)\n" % (
161
188
  sys.version, sys.platform, cprt,
162
189
  self.__class__.__name__)
163
190
  self.quiet = False
@@ -171,6 +198,10 @@ class TkTerm:
171
198
  self.showing_traceback = False
172
199
  self.closed = False
173
200
  self._saved_index = Tk_.END
201
+ # This flag is set to prevent quitting the app.
202
+ self.blockers = {}
203
+ self.can_quit = True
204
+ self.close_callback = lambda :None
174
205
 
175
206
  # Emulate a ListedWindow. We are listed, even though we are unique.
176
207
  def bring_to_front(self):
@@ -194,12 +225,12 @@ class TkTerm:
194
225
  traceback = '\n' + self.IP.InteractiveTB.stb2text(stb)
195
226
  if etype == KeyboardInterrupt:
196
227
  self.write('KeyboardInterrupt: ', style='msg')
197
- self.write('%s'%evalue)
228
+ self.write('%s' % evalue)
198
229
  else:
199
230
  self.write(traceback)
200
231
  self.reset()
201
232
  self.showing_traceback = True
202
- self.send_code('\n')
233
+ self.process_return('\n')
203
234
 
204
235
  def SnapPea_callback(self, interrupted=False):
205
236
  """
@@ -224,12 +255,14 @@ class TkTerm:
224
255
  source_raw = self.reset()
225
256
  self.IP.history_manager.store_inputs(self.IP.execution_count, source_raw)
226
257
  self.IP.execution_count += 1
227
- raise KeyboardInterrupt('Halted')
228
258
  else:
229
259
  self.interrupted = True
230
260
  # Inform the SnapPea kernel about the interrupt.
231
261
  snappy.SnapPy.SnapPea_interrupt()
232
262
  snappy.SnapPyHP.SnapPea_interrupt()
263
+ # For some reason we need to raise a KeyboardInterrupt here. Otherwise
264
+ # the call to KeyboardInterrupt('Halted') will be ignored.
265
+ raise KeyboardInterrupt('Interrupted')
233
266
 
234
267
  def report_callback_exception(self, exc, value, traceback):
235
268
  """
@@ -240,22 +273,49 @@ class TkTerm:
240
273
  sys.last_traceback = traceback
241
274
  self.IP.showtraceback()
242
275
 
243
- def set_font(self, fontdesc):
244
- self.text.config(font=fontdesc)
245
- normal_font = Font(self.text, self.text.cget('font'))
246
- self.bold_font = bold_font = Font(self.text, self.text.cget('font'))
247
- self.bold_font.config(weight='bold')
276
+ def set_font(self, font_choice):
277
+ normal_tuple = font_choice.as_tuple()
278
+ bold_tuple = font_choice.bold().as_tuple()
279
+ normal_font = Font(font=font_choice.as_tuple())
248
280
  self.char_size = normal_font.measure('M')
281
+ self.text.config(font=normal_tuple)
249
282
  text = self.text
250
- text.tag_config('output', font=normal_font)
251
- text.tag_config('Prompt', foreground='#0000cc', font=normal_font)
252
- text.tag_config('PromptNum', foreground='#0000bb', font=bold_font)
253
- text.tag_config('OutPrompt', foreground='#cc0000', font=normal_font)
254
- text.tag_config('OutPromptNum', foreground='#bb0000', font=bold_font)
283
+ text.tag_config('output', font=normal_tuple)
284
+ text.tag_config('Prompt', foreground='#0000cc', font=normal_tuple)
285
+ text.tag_config('PromptNum', foreground='#0000bb', font=bold_tuple)
286
+ text.tag_config('OutPrompt', foreground='#cc0000', font=normal_tuple)
287
+ text.tag_config('OutPromptNum', foreground='#bb0000', font=bold_tuple)
288
+
289
+ def add_blocker(self, window, message):
290
+ self.blockers[window] = message
291
+
292
+ def remove_blocker(self, window):
293
+ self.blockers.pop(window)
255
294
 
256
295
  def close(self, event=None):
257
- self.window.quit()
258
- self.closed = True
296
+ can_quit = True
297
+ topmost = None
298
+ for blocker in self.blockers:
299
+ if blocker.attributes('-topmost'):
300
+ topmost = blocker
301
+ blocker.attributes('-topmost', False)
302
+ message = self.blockers[blocker]
303
+ answer = askyesno('Quit',
304
+ message + '\nDo you want to quit anyway?')
305
+ if not answer:
306
+ can_quit = False
307
+ break;
308
+ if topmost:
309
+ topmost.attributes('-topmost', True)
310
+ if can_quit:
311
+ for blocker in self.blockers:
312
+ blocker.destroy()
313
+ self.window.quit()
314
+ self.closed = True
315
+
316
+ def handle_control_c(self, event):
317
+ self.interrupt()
318
+ self.interrupted = False
259
319
 
260
320
  def handle_keypress(self, event):
261
321
  self.clear_completions()
@@ -265,8 +325,27 @@ class TkTerm:
265
325
  return
266
326
  keysym = event.keysym
267
327
  if keysym == 'Left':
268
- # Don't go past the prompt
269
- if self.text.compare(Tk_.INSERT, '<', 'output_end+1c'):
328
+ # Don't go into the prompt or continuation prompt
329
+ line, pos = map(int, self.text.index(Tk_.INSERT).split('.'))
330
+ if pos <= self._prompt_size:
331
+ prompt_line = int(self.text.index('output_end').split('.')[0])
332
+ insert_line = int(self.text.index(Tk_.INSERT).split('.')[0])
333
+ if line > prompt_line:
334
+ self.text.mark_set(Tk_.INSERT, '%s.0-1c' % insert_line)
335
+ else:
336
+ self.window.bell()
337
+ return 'break'
338
+ return
339
+ if keysym == 'Right':
340
+ # Don't go into a continuation prompt or past the end
341
+ insert_pos = int(self.text.index('%s+1c' % Tk_.INSERT).split('.')[1])
342
+ if insert_pos < self._prompt_size:
343
+ insert_line = int(self.text.index(Tk_.INSERT).split('.')[0])
344
+ if self.text.compare(Tk_.INSERT, '>=', '%s-2c' % Tk_.END):
345
+ self.window.bell()
346
+ else:
347
+ self.text.mark_set(Tk_.INSERT, '%d.%d' % (
348
+ insert_line + 1, self._prompt_size))
270
349
  return 'break'
271
350
  return
272
351
  # Check for a control character
@@ -307,59 +386,62 @@ class TkTerm:
307
386
  if self.editing_hist and self.multiline:
308
387
  self.text.tag_add('history', 'output_end', Tk_.INSERT)
309
388
 
310
- def handle_return(self, event):
389
+ def handle_return(self, event=None):
390
+ # If the input consists of one complete line of code we run it,
391
+ # regardless of where the insert cursor is located. Otherwise we only
392
+ # run the code if the cursor is at the end of the input
311
393
  self.clear_completions()
312
- line = self.text.get('output_end', Tk_.END)
313
- if self.editing_hist:
314
- insert = self.text.index(Tk_.INSERT)
315
- newline = self.text.index('output_end')
316
- tail = self.text.get('%s.0'%insert.split('.')[0], Tk_.END)
317
- if tail.strip() != '':
318
- return
319
- prompt_size = self.text.index('output_end-1c').split('.')[1]
320
- first = self.text.index('output_end').split('.')[0]
321
- last = self.text.index(Tk_.END).split('.')[0]
322
- prompt = self._continuation_prompt(int(prompt_size)).pop()
323
- for line_number in range(int(first) + 1, int(last) - 1):
324
- self.write(prompt[1], style=prompt[0], advance=False,
325
- mark='%s.0'%line_number)
326
- self.text.delete(newline+'-1c', newline)
327
- else:
328
- self.text.insert(Tk_.END, '\n')
329
- self.text.tag_add('output', 'output_end', Tk_.END)
330
- self.text.mark_set('output_end', Tk_.END)
331
- if not self.running_code:
332
- self.send_code(line)
394
+ if self.running_code:
395
+ return 'break'
396
+ cursor = int(self.text.index(Tk_.INSERT).split('.')[0])
397
+ last = int(self.text.index(Tk_.END).split('.')[0])
398
+ first = int(self.text.index('output_end').split('.')[0])
399
+ if cursor == first == last - 1: # single line input
400
+ self.text.mark_set(Tk_.INSERT, Tk_.END)
401
+ self.text.insert(Tk_.INSERT, '\n')
402
+ cell = self.text.get('output_end', Tk_.INSERT)
403
+ try:
404
+ self.interact_handle_input(cell)
405
+ except KeyboardInterrupt:
406
+ self.write('(IP) Keyboard Interrupt: ')
407
+ self.reset()
408
+ self.hist_pointer = 0
409
+ self.hist_stem = ''
410
+ self.interact_prompt()
411
+ self.text.see(Tk_.INSERT)
412
+ if self.IP.more:
413
+ self.text.insert(Tk_.INSERT, ' '*self._current_indent, ())
414
+ self.hist_pointer = 0
415
+ self.hist_stem = ''
333
416
  return 'break'
334
417
 
335
418
  def handle_shift_return(self, event):
336
- if self.editing_hist or self.hist_pointer == 0:
337
- return 'break'
338
- l1, c1 = map(int, self.text.index('output_end').split('.'))
339
- l2, c2 = map(int, self.text.index(Tk_.INSERT).split('.'))
340
- index = '%d.%d'%(l1 + 1, c2 - c1)
341
- self.text.delete('output_end', Tk_.END)
342
- self.write_history(force_multiline=True)
343
- self.text.mark_set(Tk_.INSERT, index)
419
+ self.text.mark_set(Tk_.INSERT, Tk_.END)
420
+ return self.handle_return()
344
421
 
345
- def handle_up(self, event):
422
+ def jump_up(self, event):
423
+ return self.handle_up(event, jump=True)
424
+
425
+ def handle_up(self, event, jump=False):
346
426
  if self.text.compare(Tk_.INSERT, '<', 'output_end'):
347
427
  return
348
- insert_line = str(self.text.index(Tk_.INSERT)).split('.')[0]
349
- prompt_line = str(self.text.index('output_end')).split('.')[0]
350
- if insert_line != prompt_line:
428
+ insert_line_number = str(self.text.index(Tk_.INSERT)).split('.')[0]
429
+ prompt_line_number = str(self.text.index('output_end')).split('.')[0]
430
+ if insert_line_number != prompt_line_number:
351
431
  return
352
432
  if self.hist_pointer == 0:
353
433
  input_history = self.IP.history_manager.input_hist_raw
354
434
  self.hist_stem = self.text.get('output_end', Tk_.END).strip()
355
435
  self.filtered_hist = [x for x in input_history
356
- if x.startswith(self.hist_stem)]
436
+ if x and x.startswith(self.hist_stem)]
357
437
  if self.hist_pointer >= len(self.filtered_hist):
358
438
  self.window.bell()
359
439
  return 'break'
360
440
  self.text.delete('output_end', Tk_.END)
361
441
  self.hist_pointer += 1
362
442
  self.write_history()
443
+ if jump:
444
+ self.text.mark_set(Tk_.INSERT, 'output_end')
363
445
  return 'break'
364
446
 
365
447
  def handle_down(self, event):
@@ -368,11 +450,10 @@ class TkTerm:
368
450
  if self.editing_hist:
369
451
  insert_line = int(str(self.text.index(Tk_.INSERT)).split('.')[0])
370
452
  bottom_line = int(str(self.text.index('history_end')).split('.')[0])
371
- if insert_line < bottom_line - 1:
453
+ if insert_line < bottom_line:
372
454
  return
373
455
  if self.hist_pointer == 0:
374
- self.window.bell()
375
- return 'break'
456
+ return
376
457
  self.text.delete('output_end', Tk_.END)
377
458
  self.hist_pointer -= 1
378
459
  if self.hist_pointer == 0:
@@ -388,6 +469,14 @@ class TkTerm:
388
469
  if self.text.compare(Tk_.INSERT, '<=', 'output_end'):
389
470
  self.window.bell()
390
471
  return 'break'
472
+ line, pos = map(int, self.text.index(Tk_.INSERT).split('.'))
473
+ first_line = int(self.text.index('output_end').split('.')[0])
474
+ if pos <= self._prompt_size + 1 and line != first_line:
475
+ start = '%d.end' % (line - 1)
476
+ end = '%d.end' % (line)
477
+ self.text.mark_set(Tk_.INSERT, start)
478
+ self.text.delete(start, '%s.%s' % (line, self._prompt_size))
479
+ return 'break'
391
480
  if self._current_indent >= 4:
392
481
  if self.text.get(Tk_.INSERT+'-4c', Tk_.INSERT) == ' ':
393
482
  self.text.delete(Tk_.INSERT+'-4c', Tk_.INSERT)
@@ -404,23 +493,35 @@ class TkTerm:
404
493
  line = self.text.get('output_end', self.tab_index).strip('\n')
405
494
  word = delims.split(line)[-1]
406
495
  try:
407
- completions = self.IP.complete(word)[1]
496
+ stem, completions = self.IP.complete(word)
408
497
  except TypeError:
409
498
  completions = []
410
499
  if word.find('_') == -1:
411
500
  completions = [x for x in completions
412
501
  if x.find('__') == -1 and x.find('._') == -1]
413
- if len(completions) == 0:
502
+ # No meaningful completions. Ring the bell.
503
+ if len(completions) == 0 or len(completions) == 1 and completions[0] == stem:
414
504
  self.window.bell()
415
505
  self.tab_count = 0
416
506
  return 'break'
417
- stem = self.stem(completions)
418
- if len(stem) > len(word):
419
- self.do_completion(word, stem)
420
- elif len(completions) > 60 and self.tab_count == 1:
421
- self.show_completions(['%s possibilities -- hit tab again to view them all'%len(completions)])
507
+ # Only one completion. Use it.
508
+ if len(completions) == 1:
509
+ self.do_completion(stem, completions[0])
510
+ self.tab_count = 0
511
+ return 'break'
512
+ max_stem = self.max_stem(stem, completions)
513
+ # Add the maximal stem of all completions if it extends the word,
514
+ if len(max_stem) > len(word):
515
+ self.do_completion(stem, max_stem)
516
+ self.tab_count = 0
517
+ return 'break'
518
+ # Show the possible completions, with a warning if there are lots.
519
+ if len(completions) > 60 and self.tab_count == 1:
520
+ self.show_completions('', '',
521
+ ['%s possibilities -- hit tab again to view them all' %
522
+ len(completions)])
422
523
  else:
423
- self.show_completions(completions)
524
+ self.show_completions(word, stem, completions)
424
525
  if len(completions) <= 60:
425
526
  self.tab_count += 1
426
527
  return 'break'
@@ -429,24 +530,25 @@ class TkTerm:
429
530
  self.text.mark_set(Tk_.INSERT, 'output_end')
430
531
  return 'break'
431
532
 
432
- def do_completion(self, word, completion):
433
- tail = completion[len(word):]
533
+ def do_completion(self, stem, completion):
534
+ tail = completion[len(stem):]
434
535
  self.text.insert(self.tab_index, tail)
435
536
  self.tab_index = Tk_.END
436
537
  self.tab_count = 0
437
538
 
438
- def show_completions(self, comps):
539
+ def show_completions(self, word, stem, comps):
540
+ n = len(stem)
541
+ comps = [word + c[n:] for c in comps]
439
542
  self.text.delete(self.tab_index, Tk_.END)
440
543
  width = self.text.winfo_width()
441
- font = Font(self.text, self.text.cget('font'))
442
- charwidth = width//self.char_size
544
+ charwidth = width // self.char_size
443
545
  biggest = 2 + max([len(x) for x in comps])
444
- num_cols = charwidth//biggest
445
- num_rows = (len(comps) + num_cols -1)//num_cols
546
+ num_cols = max(charwidth // biggest, 1)
547
+ num_rows = (len(comps) + num_cols - 1) // num_cols
446
548
  rows = []
447
- format = '%%-%ds'%biggest
448
- for n in range(0, num_rows):
449
- rows.append(''.join([format%x for x in comps[n:len(comps):num_rows]]))
549
+ format = '%%-%ds' % biggest
550
+ for n in range(num_rows):
551
+ rows.append(''.join(format % x for x in comps[n:len(comps):num_rows]))
450
552
  view = '\n'.join(rows)
451
553
  self.text.insert(self.tab_index, '\n'+view)
452
554
  self.text.mark_set(Tk_.INSERT, self.tab_index)
@@ -458,33 +560,40 @@ class TkTerm:
458
560
  self.tab_index = None
459
561
  self.tab_count = 0
460
562
 
461
- def stem(self, wordlist):
462
- if len(wordlist) == 1:
463
- return wordlist[0]
464
- result = ''
465
- for n in range(1,100):
466
- heads = set(w[:n] for w in wordlist)
563
+ def max_stem(self, stem, completions):
564
+ if len(completions) == 1:
565
+ return completions[0]
566
+ result = stem
567
+ for n in range(len(stem) + 1, 100):
568
+ heads = {w[:n] for w in completions}
467
569
  if len(heads) > 1:
468
570
  return result
469
571
  elif len(heads) == 1:
470
572
  result = heads.pop()
471
- return wordlist[0][:100]
573
+ return result
574
+
575
+ def write_continuation_prompt(self):
576
+ prompt_tokens = self._continuation_prompt(self._prompt_size)
577
+ for style, text in prompt_tokens:
578
+ self.write(text, style, mark=Tk_.INSERT, advance=True)
472
579
 
473
580
  def write_history(self, force_multiline=False):
474
581
  self.text.see('output_end')
475
582
  input = self.filtered_hist[-self.hist_pointer]
476
583
  input = re.sub('\n+', '\n', input).rstrip()
477
- if input.find('\n') > 0 or force_multiline:
584
+ lines = input.split('\n')
585
+ if len(lines) > 1 or force_multiline:
478
586
  self.editing_hist = True
479
587
  self.multiline = True
480
- # Add a newline to place the editing box below the prompt.
481
- self.write('\n')
482
- self.text.tag_config('history',
483
- background='White')
484
- self.text.tag_lower('history')
485
- self.write(input + '\n\n', style=('history',), advance=False)
588
+ self.text.delete('output_end', Tk_.END)
589
+ self.write(lines[0] + '\n', mark=Tk_.INSERT, advance=True)
590
+ prompt_tokens = self._continuation_prompt(self._prompt_size)
591
+ for line in lines[1:-1]:
592
+ self.write_continuation_prompt()
593
+ self.write(line + '\n', mark=Tk_.INSERT)
594
+ self.write_continuation_prompt()
595
+ self.write(lines[-1], mark=Tk_.INSERT)
486
596
  self.text.mark_set('history_end', Tk_.INSERT)
487
- self.text.mark_set(Tk_.INSERT, 'output_end')
488
597
  else:
489
598
  self.multiline = False
490
599
  self.write(input, style=(), advance=False)
@@ -605,33 +714,20 @@ class TkTerm:
605
714
 
606
715
  def start_interaction(self):
607
716
  """
608
- Print the banner and issue the first prompt.
717
+ Display a banner and prepare to begin interaction.
609
718
  """
610
- self.text.image_create(Tk_.END, image=self.icon)
611
- banner_label = Tk_.Label(self.text, text=self.banner,
612
- background='#ec0fffec0',
613
- foreground='DarkGreen',
614
- anchor=Tk_.W,
615
- justify=Tk_.LEFT,
616
- font=self.prefs['font'])
719
+ # Subclasses should override this method
720
+ banner_label = Tk_.Label(self.text,
721
+ text="Please override the start_interaction method.",
722
+ anchor=Tk_.W,
723
+ justify=Tk_.LEFT)
617
724
  self.text.window_create(Tk_.END, window=banner_label)
618
725
  self.text.insert(Tk_.END, '\n')
619
726
  self.text.mark_set('output_end', '2.0')
620
- # Set a reasonable default directory for files to be saved to.
621
- try:
622
- home = os.environ['HOME']
623
- except KeyError:
624
- home = os.path.expanduser("~")
625
- desktop = os.path.join(home, "Desktop")
626
- default_save_dir = desktop if os.path.exists(desktop) else home
627
- self.IP.magics_manager.magics['line']['cd']("-q " + default_save_dir)
628
- # Create the prompt and go!
629
- self.interact_prompt()
630
- self.text.mark_set('output_end',Tk_.INSERT)
631
727
 
632
728
  def _input_prompt(self):
633
729
  result = [('Prompt', 'In['),
634
- ('PromptNum', '%d'%self.IP.execution_count),
730
+ ('PromptNum', '%d' % self.IP.execution_count),
635
731
  ('Prompt', ']: ')]
636
732
  self._prompt_size = sum(len(token[1]) for token in result)
637
733
  return result
@@ -642,57 +738,90 @@ class TkTerm:
642
738
 
643
739
  def interact_prompt(self):
644
740
  """
645
- Print an input prompt or a continuation prompt.
741
+ Print an input prompt or a continuation prompt. For an input
742
+ prompt set the output_end mark at the end of the prompt.
646
743
  """
647
744
  if self.showing_traceback:
648
745
  self.showing_traceback = False
649
746
  return
650
747
  try:
651
- if self.IP.more:
652
- prompt_tokens = self._continuation_prompt(self._prompt_size)
748
+ if self.IP.more or self.editing_hist:
749
+ self.write_continuation_prompt()
653
750
  else:
654
- self.write(self.IP.separate_in)
751
+ if int(self.text.index('output_end').split('.')[1]) != 0:
752
+ self.write('\n\n', mark='output_end')
655
753
  prompt_tokens = self._input_prompt()
754
+ for style, text in prompt_tokens:
755
+ self.write(text, style, mark='output_end')
656
756
  except:
657
757
  self.IP.showtraceback()
658
- for style, text in prompt_tokens:
659
- self.write(text, style)
660
-
661
- def interact_handle_input(self, code, script=False):
662
- transformer = self.IP.input_transformer_manager
663
- assert code.endswith('\n')
664
- code = re.sub('\n+', '\n', code).rstrip() + '\n'
665
- self._input_buffer += code
666
- status, indent = transformer.check_complete(self._input_buffer)
758
+
759
+ def clean_code(self, code):
760
+ """
761
+ Remove blank lines and continuation prompts.
762
+ """
763
+ if not code.strip():
764
+ return '\n'
765
+ lines = list(code.split('\n'))
766
+ clean_lines = [lines[0].lstrip()]
767
+ for line in lines[1:]:
768
+ try:
769
+ clean_lines.append(line.split(': ', 1)[1])
770
+ except IndexError:
771
+ pass
772
+ return '\n'.join(clean_lines)
773
+
774
+ def interact_handle_input(self, cell, script=False):
775
+ """
776
+ Validate the code in the cell. If the code is valid but
777
+ incomplete, set the indent that should follow a continuation
778
+ prompt and set the 'more' flag. If the code is valid and
779
+ complete then run the code.
780
+ """
781
+ assert cell.endswith('\n')
782
+ if not cell.strip():
783
+ self._current_indent = 0
784
+ return
667
785
  if script:
668
- # We are running a script. If adding a newline would make the
669
- # buffer complete and the indent 0 then we want to run the code.
670
- # So add the newline to force the buffer to be run.
671
- Xstatus, Xindent = transformer.check_complete(self._input_buffer + '\n')
672
- if Xstatus == 'complete' and Xindent is None:
673
- self._input_buffer += '\n'
674
- status, indent = Xstatus, Xindent
786
+ self._input_buffer += cell
787
+ else:
788
+ self._input_buffer = self.clean_code(cell)
789
+ transformed_cell = self.IP.transform_cell(self._input_buffer)
790
+ status, indent = self.IP.check_complete(transformed_cell)
791
+ self._current_indent = indent or 0
675
792
  if status == 'incomplete':
676
793
  self.IP.more = True
677
- self._current_indent = indent or 0
678
794
  return
679
795
  if status == 'invalid':
680
796
  # Force display of the SyntaxError
797
+ self.text.mark_set(Tk_.INSERT, self.text.index('output_end-1line'))
681
798
  self.IP.run_cell(self._input_buffer, store_history=True)
799
+ self.text.insert('output_end-1line', '\n')
682
800
  self.reset()
801
+ self.text.delete('output_end', Tk_.END)
683
802
  return
684
- # The code is complete, but we only run it if the indent level is 0 or
685
- # if there is an empty line at the end.
686
- if self._current_indent == 0 or self._input_buffer.endswith('\n\n'):
687
- self.editing_hist = False
688
- self.multiline = False
803
+ # The code is complete, but we only run it if the cursor is on the
804
+ # last line of the input and that line is blank.
805
+ insert_line = int(self.text.index(Tk_.INSERT).split('.')[0])
806
+ prompt_line = int(self.text.index('output_end').split('.')[0])
807
+ tail = self.text.get('%d.%d' % (insert_line, self._prompt_size), Tk_.END)
808
+ if not tail.strip():
689
809
  self.text.tag_delete('history')
690
810
  self._input_buffer = self._input_buffer.rstrip() + '\n'
691
- if self._input_buffer.count('\n') > 1:
692
- self.write('\n')
811
+ self.text.delete(Tk_.INSERT, Tk_.END)
812
+ self.text.insert(Tk_.INSERT, '\n')
813
+ self.text.mark_set('output_end', Tk_.INSERT)
814
+ self.multiline = False
693
815
  self.running_code = True
694
- result = self.IP.run_cell(self._input_buffer, store_history=True)
816
+ self.editing_hist = False
817
+ last_line = insert_line - 1
818
+ if last_line > prompt_line:
819
+ # Delete the last continuation prompt.
820
+ self.text.delete('%d.0' % last_line, '%d.0 lineend' % last_line)
821
+ self.IP.run_cell(self._input_buffer, store_history=True)
822
+ # Add a newline after the output.
695
823
  self.write('\n')
824
+ self.text.tag_add('output', 'output_end', Tk_.END)
696
825
  self.reset()
697
826
  else:
698
827
  self.IP.more = True
@@ -706,29 +835,9 @@ class TkTerm:
706
835
  self.multiline = False
707
836
  self.running_code = False
708
837
  self.IP.more = False
709
-
710
838
  self.text.tag_delete('history')
711
839
  return result
712
840
 
713
- def send_code(self, code):
714
- """
715
- Accumulate some lines of code and either issue a continuation
716
- prompt or execute the code, print the result and issue a new
717
- input prompt.
718
- """
719
- try:
720
- self.interact_handle_input(code)
721
- except KeyboardInterrupt:
722
- self.write('(IP) Keyboard Interrupt: ')
723
- self.reset()
724
- self.interact_prompt()
725
- self.text.see(Tk_.INSERT)
726
- self.text.mark_set('output_end',Tk_.INSERT)
727
- if self.IP.more:
728
- self.text.insert(Tk_.INSERT, ' '*self._current_indent, ())
729
- self.hist_pointer = 0
730
- self.hist_stem = ''
731
-
732
841
  def write(self, string, style=('output',), advance=True,
733
842
  mark='output_end', see=True):
734
843
  """
@@ -738,10 +847,11 @@ class TkTerm:
738
847
  """
739
848
  if self.quiet:
740
849
  return
741
- #if self.interrupted:
850
+ # if self.interrupted:
742
851
  # self.interrupted = False
743
852
  # raise KeyboardInterrupt('Writing')
744
- self.text.mark_set(Tk_.INSERT, mark)
853
+ if mark != Tk_.INSERT:
854
+ self.text.mark_set(Tk_.INSERT, mark)
745
855
  pairs = ansi_seqs.findall(string)
746
856
  for pair in pairs:
747
857
  code, text = pair
@@ -754,13 +864,14 @@ class TkTerm:
754
864
  if see:
755
865
  self.text.see(Tk_.INSERT)
756
866
  # Give the Text widget a chance to update itself every
757
- # so often (but let's not overdo it!)
867
+ # so often. In order to force processing of key events
868
+ # we have to call the evil update method, unfortunately.
758
869
  if self.output_count > 2000:
759
870
  self.output_count = 0
760
- self.text.update_idletasks()
871
+ self.text.update()
761
872
  if self.interrupted:
762
873
  self.interrupted = False
763
- self.interrupt()
874
+ raise KeyboardInterrupt('Halted')
764
875
 
765
876
  def write2(self, string):
766
877
  """
@@ -802,7 +913,6 @@ class TkTerm:
802
913
  # else:
803
914
  # self.text.mark_set(Tk_.INSERT, '%s.0'%(insert_line + scroll_amount))
804
915
 
805
-
806
916
  def flush(self):
807
917
  """
808
918
  Required for a stdout / stderr proxy.