passagemath-repl 10.5.22__py3-none-any.whl → 10.5.23__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 (30) hide show
  1. {passagemath_repl-10.5.22.dist-info → passagemath_repl-10.5.23.dist-info}/METADATA +8 -8
  2. {passagemath_repl-10.5.22.dist-info → passagemath_repl-10.5.23.dist-info}/RECORD +30 -30
  3. {passagemath_repl-10.5.22.dist-info → passagemath_repl-10.5.23.dist-info}/WHEEL +1 -1
  4. sage/doctest/forker.py +2 -2
  5. sage/doctest/parsing.py +9 -39
  6. sage/doctest/sources.py +9 -9
  7. sage/doctest/util.py +151 -0
  8. sage/interfaces/quit.py +40 -25
  9. sage/misc/cython.py +1 -1
  10. sage/misc/sage_input.py +4 -4
  11. sage/tests/book_stein_ent.py +5 -5
  12. {passagemath_repl-10.5.22.data → passagemath_repl-10.5.23.data}/scripts/sage-cachegrind +0 -0
  13. {passagemath_repl-10.5.22.data → passagemath_repl-10.5.23.data}/scripts/sage-callgrind +0 -0
  14. {passagemath_repl-10.5.22.data → passagemath_repl-10.5.23.data}/scripts/sage-cleaner +0 -0
  15. {passagemath_repl-10.5.22.data → passagemath_repl-10.5.23.data}/scripts/sage-coverage +0 -0
  16. {passagemath_repl-10.5.22.data → passagemath_repl-10.5.23.data}/scripts/sage-eval +0 -0
  17. {passagemath_repl-10.5.22.data → passagemath_repl-10.5.23.data}/scripts/sage-fixdoctests +0 -0
  18. {passagemath_repl-10.5.22.data → passagemath_repl-10.5.23.data}/scripts/sage-inline-fortran +0 -0
  19. {passagemath_repl-10.5.22.data → passagemath_repl-10.5.23.data}/scripts/sage-ipynb2rst +0 -0
  20. {passagemath_repl-10.5.22.data → passagemath_repl-10.5.23.data}/scripts/sage-ipython +0 -0
  21. {passagemath_repl-10.5.22.data → passagemath_repl-10.5.23.data}/scripts/sage-massif +0 -0
  22. {passagemath_repl-10.5.22.data → passagemath_repl-10.5.23.data}/scripts/sage-notebook +0 -0
  23. {passagemath_repl-10.5.22.data → passagemath_repl-10.5.23.data}/scripts/sage-omega +0 -0
  24. {passagemath_repl-10.5.22.data → passagemath_repl-10.5.23.data}/scripts/sage-preparse +0 -0
  25. {passagemath_repl-10.5.22.data → passagemath_repl-10.5.23.data}/scripts/sage-run +0 -0
  26. {passagemath_repl-10.5.22.data → passagemath_repl-10.5.23.data}/scripts/sage-run-cython +0 -0
  27. {passagemath_repl-10.5.22.data → passagemath_repl-10.5.23.data}/scripts/sage-runtests +0 -0
  28. {passagemath_repl-10.5.22.data → passagemath_repl-10.5.23.data}/scripts/sage-startuptime.py +0 -0
  29. {passagemath_repl-10.5.22.data → passagemath_repl-10.5.23.data}/scripts/sage-valgrind +0 -0
  30. {passagemath_repl-10.5.22.dist-info → passagemath_repl-10.5.23.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: passagemath-repl
3
- Version: 10.5.22
3
+ Version: 10.5.23
4
4
  Summary: passagemath: IPython kernel, Sage preparser, doctester
5
5
  Author-email: The Sage Developers <sage-support@googlegroups.com>
6
6
  Maintainer: Matthias Köppe, passagemath contributors
@@ -29,14 +29,14 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
29
29
  Classifier: Topic :: Scientific/Engineering :: Mathematics
30
30
  Requires-Python: <3.14,>=3.9
31
31
  Description-Content-Type: text/x-rst
32
- Requires-Dist: passagemath-objects ~=10.5.22.0
33
- Requires-Dist: passagemath-environment ~=10.5.22.0
34
- Requires-Dist: ipykernel >=5.2.1
35
- Requires-Dist: ipython >=7.13.0
36
- Requires-Dist: ipywidgets >=7.5.1
32
+ Requires-Dist: passagemath-objects~=10.5.23.0
33
+ Requires-Dist: passagemath-environment~=10.5.23.0
34
+ Requires-Dist: ipykernel>=5.2.1
35
+ Requires-Dist: ipython>=7.13.0
36
+ Requires-Dist: ipywidgets>=7.5.1
37
37
  Requires-Dist: jupyter-client
38
38
  Provides-Extra: sphinx
39
- Requires-Dist: sphinx <9,>=5.2 ; extra == 'sphinx'
39
+ Requires-Dist: sphinx<9,>=5.2; extra == "sphinx"
40
40
 
41
41
  ===================================================================================
42
42
  passagemath: IPython kernel, Sage preparser, doctester
@@ -1,21 +1,21 @@
1
- passagemath_repl-10.5.22.data/scripts/sage-cachegrind,sha256=FRrT4BoRsrATlQOrXALHAbDI_KLhz0XuDOD6xzECEl8,651
2
- passagemath_repl-10.5.22.data/scripts/sage-callgrind,sha256=pWhrI8NsVa_XSuay052htjxcM3thrpX8rI6Uj_pK5Uo,442
3
- passagemath_repl-10.5.22.data/scripts/sage-cleaner,sha256=vM0CkzbxiSCE0Z85AViQIvoxb5oUz5WOmVOvShbLDUY,7778
4
- passagemath_repl-10.5.22.data/scripts/sage-coverage,sha256=IhvqnFvmvNJBMQtiSu5_Qy52a67hG-r3cAeyhYOOj7w,10199
5
- passagemath_repl-10.5.22.data/scripts/sage-eval,sha256=4IHv01xH34wJPj61wzcL5ufhoO6Y3UTTGz7b-0YKJFw,266
6
- passagemath_repl-10.5.22.data/scripts/sage-fixdoctests,sha256=cTWoFr9rAdOF-xeW6ytNeX3EzhKcs1mTN4UilP4kiGg,36877
7
- passagemath_repl-10.5.22.data/scripts/sage-inline-fortran,sha256=T3U943WNPKrxQJuanBhTpXU3jJ5vjaXd56R8yWv_8PM,234
8
- passagemath_repl-10.5.22.data/scripts/sage-ipynb2rst,sha256=PynBPdthnpwGbILDRA38IwpT319Ze-g8UMmWaaTnimQ,1345
9
- passagemath_repl-10.5.22.data/scripts/sage-ipython,sha256=RYYd8-gmE5JE_-dCkOSDpC6rRsX6i6tma3pqgmXYJvM,342
10
- passagemath_repl-10.5.22.data/scripts/sage-massif,sha256=Tfqb6ON9d0OZnt6VlGS21asbdMq8zWzx8ZnvV1n_buI,613
11
- passagemath_repl-10.5.22.data/scripts/sage-notebook,sha256=QJ1Y4eTptc6TbNVXZswpcsn-NqaQNuSwjWE-lYmGpW8,8453
12
- passagemath_repl-10.5.22.data/scripts/sage-omega,sha256=4ARnHyZyB69ltxHj9xYpzad_YCBT3Nk0Wq3Ke09gExM,595
13
- passagemath_repl-10.5.22.data/scripts/sage-preparse,sha256=3L1KKgvSApvoK467Wza0S4WQLCXiYvivrhDKIvA1omc,10595
14
- passagemath_repl-10.5.22.data/scripts/sage-run,sha256=F1oAgPN7Kh5dO1smCyfGVT0Dy46NQ_dQ3OQZ8Wa6foM,689
15
- passagemath_repl-10.5.22.data/scripts/sage-run-cython,sha256=02mTGXokayRxISoCWWsDcKZwGrmh5B0mJJxTT87J01Q,235
16
- passagemath_repl-10.5.22.data/scripts/sage-runtests,sha256=nUvI3fCrBjqPUict01wIxwYPjvaZf4ttLp85tavUEpY,111
17
- passagemath_repl-10.5.22.data/scripts/sage-startuptime.py,sha256=RtIuC7jM3SOwROXTa6nnpJhzK0sQ24nDqyE6zXpCWEI,6209
18
- passagemath_repl-10.5.22.data/scripts/sage-valgrind,sha256=fZxy00oXU4PpHf_wc2uYKb7lzqSBY4VkhUxiuvXHKhA,1201
1
+ passagemath_repl-10.5.23.data/scripts/sage-cachegrind,sha256=FRrT4BoRsrATlQOrXALHAbDI_KLhz0XuDOD6xzECEl8,651
2
+ passagemath_repl-10.5.23.data/scripts/sage-callgrind,sha256=pWhrI8NsVa_XSuay052htjxcM3thrpX8rI6Uj_pK5Uo,442
3
+ passagemath_repl-10.5.23.data/scripts/sage-cleaner,sha256=vM0CkzbxiSCE0Z85AViQIvoxb5oUz5WOmVOvShbLDUY,7778
4
+ passagemath_repl-10.5.23.data/scripts/sage-coverage,sha256=IhvqnFvmvNJBMQtiSu5_Qy52a67hG-r3cAeyhYOOj7w,10199
5
+ passagemath_repl-10.5.23.data/scripts/sage-eval,sha256=4IHv01xH34wJPj61wzcL5ufhoO6Y3UTTGz7b-0YKJFw,266
6
+ passagemath_repl-10.5.23.data/scripts/sage-fixdoctests,sha256=cTWoFr9rAdOF-xeW6ytNeX3EzhKcs1mTN4UilP4kiGg,36877
7
+ passagemath_repl-10.5.23.data/scripts/sage-inline-fortran,sha256=T3U943WNPKrxQJuanBhTpXU3jJ5vjaXd56R8yWv_8PM,234
8
+ passagemath_repl-10.5.23.data/scripts/sage-ipynb2rst,sha256=PynBPdthnpwGbILDRA38IwpT319Ze-g8UMmWaaTnimQ,1345
9
+ passagemath_repl-10.5.23.data/scripts/sage-ipython,sha256=RYYd8-gmE5JE_-dCkOSDpC6rRsX6i6tma3pqgmXYJvM,342
10
+ passagemath_repl-10.5.23.data/scripts/sage-massif,sha256=Tfqb6ON9d0OZnt6VlGS21asbdMq8zWzx8ZnvV1n_buI,613
11
+ passagemath_repl-10.5.23.data/scripts/sage-notebook,sha256=QJ1Y4eTptc6TbNVXZswpcsn-NqaQNuSwjWE-lYmGpW8,8453
12
+ passagemath_repl-10.5.23.data/scripts/sage-omega,sha256=4ARnHyZyB69ltxHj9xYpzad_YCBT3Nk0Wq3Ke09gExM,595
13
+ passagemath_repl-10.5.23.data/scripts/sage-preparse,sha256=3L1KKgvSApvoK467Wza0S4WQLCXiYvivrhDKIvA1omc,10595
14
+ passagemath_repl-10.5.23.data/scripts/sage-run,sha256=F1oAgPN7Kh5dO1smCyfGVT0Dy46NQ_dQ3OQZ8Wa6foM,689
15
+ passagemath_repl-10.5.23.data/scripts/sage-run-cython,sha256=02mTGXokayRxISoCWWsDcKZwGrmh5B0mJJxTT87J01Q,235
16
+ passagemath_repl-10.5.23.data/scripts/sage-runtests,sha256=nUvI3fCrBjqPUict01wIxwYPjvaZf4ttLp85tavUEpY,111
17
+ passagemath_repl-10.5.23.data/scripts/sage-startuptime.py,sha256=RtIuC7jM3SOwROXTa6nnpJhzK0sQ24nDqyE6zXpCWEI,6209
18
+ passagemath_repl-10.5.23.data/scripts/sage-valgrind,sha256=fZxy00oXU4PpHf_wc2uYKb7lzqSBY4VkhUxiuvXHKhA,1201
19
19
  sage/all__sagemath_repl.py,sha256=z6lERTYuw3I4LQ7-hnEYbY1i-hMJj2uAm2ujOmWitSo,5713
20
20
  sage/doctest/__init__.py,sha256=JJMNkq7Rh3gCshtynqXDTLJgUKweNFlUhpnbvTLRMwg,166
21
21
  sage/doctest/__main__.py,sha256=wGVNiaPbhQwzoAs3Y1xhYBlB18pBieEDhi71ggF8NkQ,13647
@@ -24,15 +24,15 @@ sage/doctest/check_tolerance.py,sha256=YnYr981uSUZWfuv5OrXdytXsZx6PtJnQ7Mg8-Lj7p
24
24
  sage/doctest/control.py,sha256=4JBsC9GRFdAPPDTunknFx29Ea2KcFHVjJAceIHSGEyY,67877
25
25
  sage/doctest/external.py,sha256=ddr7S0bt1bqAHWyAQj0z4O1SrjwgpdY7ghDt4KZzDRo,15601
26
26
  sage/doctest/fixtures.py,sha256=UDSykekKanmnD737VXFv7r5QzcZmqzfwn1Noc_fKcnE,12784
27
- sage/doctest/forker.py,sha256=ej8-5TwrZZhnlC6apJ7jaGx0-06FxUe083PrSESkxRU,111238
27
+ sage/doctest/forker.py,sha256=tfE1vO0LTgEZkXIhutD5mJFU8x1t_fton73mES8Y2LU,111239
28
28
  sage/doctest/marked_output.py,sha256=EJThXbkhYvYR5r1uuZyfPjeYHiLpHUgqTm1QZ5JTDgw,3034
29
- sage/doctest/parsing.py,sha256=GJRQRKX1cwr8fM5Gu2WxbxU3q8avsIskbH-7I2okjss,72167
29
+ sage/doctest/parsing.py,sha256=5g1R7niBaa_6RE5WcGFF_Eqmzak1SpXWHEGnow_8Ifw,71130
30
30
  sage/doctest/parsing_test.py,sha256=7v3Y6kgLr7x5UF3CkdyNbRyhH4VRX275QPdCqG-jMxg,2652
31
31
  sage/doctest/reporting.py,sha256=8SBJ7I6Ea8OAENNdtfns4TlhLNvgF8Ss1Y8tef5-02o,33383
32
32
  sage/doctest/rif_tol.py,sha256=m8XljRCPyaj_Kpng-sNxsRSo0BJR3QY3CArhjEZ9c5s,4973
33
- sage/doctest/sources.py,sha256=T7GHWVrIG-qypXGnHr_-F9KJSvU_n-09LSzDqkJgyyE,63592
33
+ sage/doctest/sources.py,sha256=ERm6ZwBAVlZ60tHBCLJy_WnLKZaTsU0mL8lOsInn3GY,63652
34
34
  sage/doctest/test.py,sha256=XU8RASl7HPLM_YoPcyQ9uIwG9oUTUyjl7N7xH74vzdo,22616
35
- sage/doctest/util.py,sha256=tvFeYl09UCHEpNUlRQWhRqvoZtpKGODfUTh5-vfv12I,23952
35
+ sage/doctest/util.py,sha256=hEB0VduaItsQLmOJBY0unDphjv3XBdd8LvqbpzDQqaA,30871
36
36
  sage/doctest/tests/1second.rst,sha256=CHBQjhfvPPyBQmTslo-G7kC8Jr6i5DujXTT19AewsIk,74
37
37
  sage/doctest/tests/99seconds.rst,sha256=1FUWC-u5vVHqYd2VUUe_GELikmMvUEDZDt-kAU8u4TA,75
38
38
  sage/doctest/tests/abort.rst,sha256=lqKD_TZvcnO38zmXrp76HyLlVZNKd72rbaGGGhPgywQ,164
@@ -51,13 +51,13 @@ sage/doctest/tests/simple_failure.rst,sha256=063m5EMsTntr40npoAP4OYddiq9cPIA0Wrc
51
51
  sage/doctest/tests/sleep_and_raise.rst,sha256=QXRNJ5-kGU86KGNMVQZiJvxbMZxqf7dWzhjtjrPtZEY,900
52
52
  sage/doctest/tests/tolerance.rst,sha256=D5MeN4ZUkkTdQMEpYEtElPdQ-8p7DG-4LzOEnSsmapg,747
53
53
  sage/interfaces/cleaner.py,sha256=sd8_F8xGC7OMSoWcCPL3VAOPOuXZAOZu0ys1FExKYjQ,1560
54
- sage/interfaces/quit.py,sha256=SUtK6OR1-7klO_PgyW-kCQgDETSZ8cgY4T-Tq40P33Q,5329
54
+ sage/interfaces/quit.py,sha256=iKuZ8m98g_2CNF4J9pfc-0KbE0HAadFZxwHPSydbrcA,5935
55
55
  sage/misc/all__sagemath_repl.py,sha256=Qxsf_bNAVB4CScgVoD0Lb9_RFwdK8BI3S0aqjFBz88c,1791
56
56
  sage/misc/banner.py,sha256=69sC578x0-t8a_l14w08xMLPBp0wcd8RsdTrcJq7ERQ,7883
57
57
  sage/misc/benchmark.py,sha256=4hW6hTGWfPb_E_U8V19Y_CPRN9_mUMsefrIb1rkzhfQ,6162
58
58
  sage/misc/classgraph.py,sha256=e9xZbH4cZhkY8uuNL-PrS1tyFXm8JcnhyE8uTDYOCoE,5155
59
59
  sage/misc/copying.py,sha256=jyY_AyAAFHAYGkj6Ca-kRd-PcW4qg18kDIUp1dVPk0M,423
60
- sage/misc/cython.py,sha256=5BfZp_zldl3OxEplkEwk-UkNYjxz-rpVXvi9-LGD9Vw,25849
60
+ sage/misc/cython.py,sha256=0x7ohaPlQc-rxwaCoYxztBI2H9P-0aeZ8JOCml4nmbM,25865
61
61
  sage/misc/dev_tools.py,sha256=7Op4JFUXiYjUHN1lxO7blEVDr3vwYzDujO70XjwNDUE,28380
62
62
  sage/misc/edit_module.py,sha256=A3EctK2BgolhFtsCXtiShKzr_c0r3eGmb9HYnKPyOto,10528
63
63
  sage/misc/explain_pickle.py,sha256=KLuoOx_7xEeawgnLvheim4qmgMhPPOL0CcRxbP7CpWM,107704
@@ -69,7 +69,7 @@ sage/misc/profiler.py,sha256=r9M0GKmxEzWpZVuemY1ch03fd_zZz8kKpcEDXD8W-0k,5753
69
69
  sage/misc/python.py,sha256=qUdAqlft8VD4oG8U0iWN-r8RXGpGwD70K_00r4REXlo,1840
70
70
  sage/misc/remote_file.py,sha256=p3t4NT4_c0xUI8pLqWaw4RE0NX_O3a5K0VL3-W8wZqo,1545
71
71
  sage/misc/sage_eval.py,sha256=hvBRBay5CoInQM6NDNOaTV1_AYTgj2O_VGIst1uLuQ8,7780
72
- sage/misc/sage_input.py,sha256=MWivkHNX5SnWBvE5UM-baPK2kOhRip8rHgs7OyEE-Rg,121020
72
+ sage/misc/sage_input.py,sha256=W-OU7dI_cNJfhAFcquE3m5G8X50Fizmart2T-4PYT3k,121062
73
73
  sage/misc/sagedoc.py,sha256=W2ZQxJd3JsbzdhnpZx5gvlzJgAav3byr8iHXUzfIW6U,67584
74
74
  sage/misc/sh.py,sha256=4aogzam8JR0jtvWOM5CXycjPjWqUNs7Pc9l0fNwmwuw,1446
75
75
  sage/misc/trace.py,sha256=xEwmVVALZ7aCciIRpspoY4IJuE1T9502P5KL2VH0yl0,2978
@@ -141,7 +141,7 @@ sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py,sha256=bam9TtDj7Wic1Fs5X
141
141
  sage/tests/arxiv_0812_2725.py,sha256=x1oO2O50QnrCm-zK2Wopzr5SnOlRz0LzNUo_AUORdZE,9942
142
142
  sage/tests/benchmark.py,sha256=XY3VTPMklhoM2m-8dxs3sypbeoo-gLFS9ZbWD7UBbYU,55488
143
143
  sage/tests/book_schilling_zabrocki_kschur_primer.py,sha256=mIr3XlcQKQXxjmagRuvBdpRG98PsDmx6ZCsGQfVdsq8,27118
144
- sage/tests/book_stein_ent.py,sha256=3k1T56sB-csaLzJEsEyVJ9YaMBKtgc0W1_z7cuwiz-Y,19767
144
+ sage/tests/book_stein_ent.py,sha256=0cspmZEJvqibRTtt2F3cv75oLL0lvizEbKJANH50oeo,19782
145
145
  sage/tests/book_stein_modform.py,sha256=zX0Y1OqrjXT5pEFSrhn6AwHkx43PhgpiLVh8lnPwKaM,21168
146
146
  sage/tests/cmdline.py,sha256=2JiDN3yvOjlHOYtcGHXBZa4y_qc3KGlR3vPTzShVxN8,26316
147
147
  sage/tests/combinatorial_hopf_algebras.py,sha256=FTzMq8JyyKLAU3vFacMZZAer7PxALQpg3SFdEjBdo_s,1849
@@ -156,7 +156,7 @@ sage/tests/startup.py,sha256=G8Co8afXEC1FO9pyFlryBzLXXwY40_BcWrimaPadw3w,1185
156
156
  sage/tests/symbolic-series.py,sha256=5WlGSwW4eq-Ydev0jYtLDtuk1KCIJ7QCNE0IhZpc37Q,2991
157
157
  sage/tests/sympy.py,sha256=SGzxN4faL0Y3lokTYV_n_IYjf65pc1foBfLbxDhPDgk,431
158
158
  sage/tests/test_deprecation.py,sha256=Y2uvLozCshTPhQgfAxT_pAkkgX5Q16yJwQ0CleKHDJw,917
159
- passagemath_repl-10.5.22.dist-info/METADATA,sha256=SdA1b_Gcf35zlVK0riJjz8eiDn22E-ybbU04KD8ZIDI,3199
160
- passagemath_repl-10.5.22.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
161
- passagemath_repl-10.5.22.dist-info/top_level.txt,sha256=hibFyzQHiLOMK68qL1OWsNKaXOmSXqZjeLTBem6Yy7I,5
162
- passagemath_repl-10.5.22.dist-info/RECORD,,
159
+ passagemath_repl-10.5.23.dist-info/METADATA,sha256=tyMxRK4h8MSThIayupsIkaH7DscdIR9tWII4inM2YX4,3192
160
+ passagemath_repl-10.5.23.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
161
+ passagemath_repl-10.5.23.dist-info/top_level.txt,sha256=hibFyzQHiLOMK68qL1OWsNKaXOmSXqZjeLTBem6Yy7I,5
162
+ passagemath_repl-10.5.23.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (73.0.1)
2
+ Generator: setuptools (78.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
sage/doctest/forker.py CHANGED
@@ -1829,8 +1829,8 @@ class DocTestDispatcher(SageObject):
1829
1829
 
1830
1830
  sage: # needs sage.all
1831
1831
  sage: from tempfile import NamedTemporaryFile as NTF
1832
- sage: with NTF(suffix='.py', mode='w+t') as f1, \
1833
- ....: NTF(suffix='.py', mode='w+t') as f2:
1832
+ sage: with (NTF(suffix='.py', mode='w+t') as f1,
1833
+ ....: NTF(suffix='.py', mode='w+t') as f2):
1834
1834
  ....: _ = f1.write("'''\nsage: import time; time.sleep(60)\n'''")
1835
1835
  ....: f1.flush()
1836
1836
  ....: _ = f2.write("'''\nsage: True\nFalse\n'''")
sage/doctest/parsing.py CHANGED
@@ -880,26 +880,6 @@ class SageDocTestParser(doctest.DocTestParser):
880
880
  sage: ex.source
881
881
  'for i in range(Integer(4)):\n print(i)\n'
882
882
 
883
- Sage currently accepts backslashes as indicating that the end
884
- of the current line should be joined to the next line. This
885
- feature allows for breaking large integers over multiple lines
886
- but is not standard for Python doctesting. It's not
887
- guaranteed to persist::
888
-
889
- sage: n = 1234\
890
- ....: 5678
891
- sage: print(n)
892
- 12345678
893
- sage: type(n)
894
- <class 'sage.rings.integer.Integer'>
895
-
896
- It also works without the line continuation::
897
-
898
- sage: m = 8765\
899
- 4321
900
- sage: print(m)
901
- 87654321
902
-
903
883
  Optional tags at the start of an example block persist to the end of
904
884
  the block (delimited by a blank line)::
905
885
 
@@ -994,15 +974,15 @@ class SageDocTestParser(doctest.DocTestParser):
994
974
  sage: # needs sage.combinat
995
975
  sage: parse("::\n\n sage: # needs sage.combinat\n sage: from sage.geometry.polyhedron.combinatorial_polyhedron.conversions \\\n ....: import incidence_matrix_to_bit_rep_of_Vrep\n sage: P = polytopes.associahedron(['A',3])\n\n")
996
976
  ['::\n\n',
997
- '',
998
- (None,
999
- 'from sage.geometry.polyhedron.combinatorial_polyhedron.conversions import incidence_matrix_to_bit_rep_of_Vrep\n',
1000
- 'from sage.geometry.polyhedron.combinatorial_polyhedron.conversions import incidence_matrix_to_bit_rep_of_Vrep\n'),
1001
- '',
1002
- (None,
1003
- "P = polytopes.associahedron(['A',3])\n",
1004
- "P = polytopes.associahedron(['A',Integer(3)])\n"),
1005
- '\n']
977
+ '',
978
+ (None,
979
+ 'from sage.geometry.polyhedron.combinatorial_polyhedron.conversions \\\n import incidence_matrix_to_bit_rep_of_Vrep\n',
980
+ 'from sage.geometry.polyhedron.combinatorial_polyhedron.conversions import incidence_matrix_to_bit_rep_of_Vrep\n'),
981
+ '',
982
+ (None,
983
+ "P = polytopes.associahedron(['A',3])\n",
984
+ "P = polytopes.associahedron(['A',Integer(3)])\n"),
985
+ '\n']
1006
986
 
1007
987
  sage: example4 = '::\n\n sage: C.minimum_distance(algorithm="guava") # optional - guava\n ...\n 24\n\n'
1008
988
  sage: parsed4 = DTP.parse(example4)
@@ -1017,20 +997,10 @@ class SageDocTestParser(doctest.DocTestParser):
1017
997
  find_sage_continuation = re.compile(r"^(\s*)\.\.\.\.:", re.M)
1018
998
  find_python_continuation = re.compile(r"^(\s*)\.\.\.([^\.])", re.M)
1019
999
  python_prompt = re.compile(r"^(\s*)>>>", re.M)
1020
- backslash_replacer = re.compile(r"""(\s*)sage:(.*)\\\ *
1021
- \ *((\.){4}:)?\ *""")
1022
1000
 
1023
1001
  # The following are used to allow ... at the beginning of output
1024
1002
  ellipsis_tag = "<TEMP_ELLIPSIS_TAG>"
1025
1003
 
1026
- # Hack for non-standard backslash line escapes accepted by the current
1027
- # doctest system.
1028
- m = backslash_replacer.search(string)
1029
- while m is not None:
1030
- g = m.groups()
1031
- string = string[:m.start()] + g[0] + "sage:" + g[1] + string[m.end():]
1032
- m = backslash_replacer.search(string, m.start())
1033
-
1034
1004
  replace_ellipsis = not python_prompt.search(string)
1035
1005
  if replace_ellipsis:
1036
1006
  # There are no >>> prompts, so we can allow ... to begin the output
sage/doctest/sources.py CHANGED
@@ -212,7 +212,7 @@ class DocTestSource:
212
212
  sage: from sage.doctest.control import DocTestDefaults
213
213
  sage: from sage.doctest.sources import FileDocTestSource
214
214
  sage: from sage.doctest.parsing import SageDocTestParser
215
- sage: filename = sage.doctest.util.__file__
215
+ sage: filename = sage.doctest.marked_output.__file__
216
216
  sage: FDS = FileDocTestSource(filename, DocTestDefaults())
217
217
  sage: doctests, _ = FDS.create_doctests({})
218
218
  sage: manual_doctests = []
@@ -923,7 +923,7 @@ class SourceLanguage:
923
923
  sage: from sage.doctest.sources import FileDocTestSource
924
924
  sage: from sage.doctest.parsing import SageDocTestParser
925
925
  sage: from sage.doctest.util import NestedName
926
- sage: filename = sage.doctest.util.__file__
926
+ sage: filename = sage.doctest.marked_output.__file__
927
927
  sage: FDS = FileDocTestSource(filename, DocTestDefaults())
928
928
  sage: doctests, _ = FDS.create_doctests({})
929
929
  sage: for dt in doctests:
@@ -943,7 +943,7 @@ class PythonSource(SourceLanguage):
943
943
 
944
944
  sage: from sage.doctest.control import DocTestDefaults
945
945
  sage: from sage.doctest.sources import FileDocTestSource
946
- sage: filename = sage.doctest.sources.__file__
946
+ sage: filename = sage.doctest.marked_output.__file__
947
947
  sage: FDS = FileDocTestSource(filename, DocTestDefaults())
948
948
  sage: type(FDS)
949
949
  <class 'sage.doctest.sources.PythonFileSource'>
@@ -959,7 +959,7 @@ class PythonSource(SourceLanguage):
959
959
 
960
960
  sage: from sage.doctest.control import DocTestDefaults
961
961
  sage: from sage.doctest.sources import FileDocTestSource
962
- sage: filename = sage.doctest.sources.__file__
962
+ sage: filename = sage.doctest.marked_output.__file__
963
963
  sage: FDS = FileDocTestSource(filename, DocTestDefaults())
964
964
  sage: FDS._init()
965
965
  sage: FDS.last_indent
@@ -994,7 +994,7 @@ class PythonSource(SourceLanguage):
994
994
 
995
995
  sage: from sage.doctest.control import DocTestDefaults
996
996
  sage: from sage.doctest.sources import FileDocTestSource
997
- sage: filename = sage.doctest.sources.__file__
997
+ sage: filename = sage.doctest.marked_output.__file__
998
998
  sage: FDS = FileDocTestSource(filename, DocTestDefaults())
999
999
  sage: FDS._init()
1000
1000
  sage: FDS._update_quotetype('\"\"\"'); print(" ".join(list(FDS.quotetype)))
@@ -1087,7 +1087,7 @@ class PythonSource(SourceLanguage):
1087
1087
  sage: from sage.doctest.control import DocTestDefaults
1088
1088
  sage: from sage.doctest.sources import FileDocTestSource
1089
1089
  sage: from sage.doctest.util import NestedName
1090
- sage: filename = sage.doctest.sources.__file__
1090
+ sage: filename = sage.doctest.marked_output.__file__
1091
1091
  sage: FDS = FileDocTestSource(filename, DocTestDefaults())
1092
1092
  sage: FDS._init()
1093
1093
  sage: FDS.starting_docstring("r'''")
@@ -1100,7 +1100,7 @@ class PythonSource(SourceLanguage):
1100
1100
  sage: FDS.starting_docstring(" '''")
1101
1101
  <...Match object...>
1102
1102
  sage: FDS.qualified_name
1103
- sage.doctest.sources.MyClass.hello_world
1103
+ sage.doctest.marked_output.MyClass.hello_world
1104
1104
  sage: FDS.ending_docstring(" '''")
1105
1105
  <...Match object...>
1106
1106
  sage: FDS.starting_docstring("class NewClass():")
@@ -1109,7 +1109,7 @@ class PythonSource(SourceLanguage):
1109
1109
  sage: FDS.ending_docstring(" '''")
1110
1110
  <...Match object...>
1111
1111
  sage: FDS.qualified_name
1112
- sage.doctest.sources.NewClass
1112
+ sage.doctest.marked_output.NewClass
1113
1113
  sage: FDS.starting_docstring("print(")
1114
1114
  sage: FDS.starting_docstring(" '''Not a docstring")
1115
1115
  sage: FDS.starting_docstring(" ''')")
@@ -1160,7 +1160,7 @@ class PythonSource(SourceLanguage):
1160
1160
  sage: from sage.doctest.control import DocTestDefaults
1161
1161
  sage: from sage.doctest.sources import FileDocTestSource
1162
1162
  sage: from sage.doctest.util import NestedName
1163
- sage: filename = sage.doctest.sources.__file__
1163
+ sage: filename = sage.doctest.marked_output.__file__
1164
1164
  sage: FDS = FileDocTestSource(filename, DocTestDefaults())
1165
1165
  sage: FDS._init()
1166
1166
  sage: FDS.quotetype = "'''"
sage/doctest/util.py CHANGED
@@ -25,6 +25,8 @@ AUTHORS:
25
25
 
26
26
  from time import time as walltime
27
27
  from os import sysconf, times
28
+ from contextlib import contextmanager
29
+ from cysignals.alarm import alarm, cancel_alarm, AlarmInterrupt
28
30
 
29
31
 
30
32
  def count_noun(number, noun, plural=None, pad_number=False, pad_noun=False):
@@ -750,3 +752,152 @@ class NestedName:
750
752
  True
751
753
  """
752
754
  return not (self == other)
755
+
756
+
757
+ @contextmanager
758
+ def ensure_interruptible_after(seconds: float, max_wait_after_interrupt: float = 0.2, inaccuracy_tolerance: float = 0.1):
759
+ """
760
+ Helper function for doctesting to ensure that the code is interruptible after a certain amount of time.
761
+ This should only be used for internal doctesting purposes.
762
+
763
+ EXAMPLES::
764
+
765
+ sage: from sage.doctest.util import ensure_interruptible_after
766
+ sage: with ensure_interruptible_after(1) as data: sleep(3)
767
+
768
+ ``as data`` is optional, but if it is used, it will contain a few useful values::
769
+
770
+ sage: data
771
+ {'alarm_raised': True, 'elapsed': 1...}
772
+
773
+ ``max_wait_after_interrupt`` can be passed if the function may take longer than usual to be interrupted::
774
+
775
+ sage: # needs sage.misc.cython
776
+ sage: cython(r'''
777
+ ....: from posix.time cimport clock_gettime, CLOCK_REALTIME, timespec, time_t
778
+ ....: from cysignals.signals cimport sig_check
779
+ ....:
780
+ ....: cpdef void uninterruptible_sleep(double seconds):
781
+ ....: cdef timespec start_time, target_time
782
+ ....: clock_gettime(CLOCK_REALTIME, &start_time)
783
+ ....:
784
+ ....: cdef time_t floor_seconds = <time_t>seconds
785
+ ....: target_time.tv_sec = start_time.tv_sec + floor_seconds
786
+ ....: target_time.tv_nsec = start_time.tv_nsec + <long>((seconds - floor_seconds) * 1e9)
787
+ ....: if target_time.tv_nsec >= 1000000000:
788
+ ....: target_time.tv_nsec -= 1000000000
789
+ ....: target_time.tv_sec += 1
790
+ ....:
791
+ ....: while True:
792
+ ....: clock_gettime(CLOCK_REALTIME, &start_time)
793
+ ....: if start_time.tv_sec > target_time.tv_sec or (start_time.tv_sec == target_time.tv_sec and start_time.tv_nsec >= target_time.tv_nsec):
794
+ ....: break
795
+ ....:
796
+ ....: cpdef void check_interrupt_only_occasionally():
797
+ ....: for i in range(10):
798
+ ....: uninterruptible_sleep(0.8)
799
+ ....: sig_check()
800
+ ....: ''')
801
+ sage: with ensure_interruptible_after(1): # not passing max_wait_after_interrupt will raise an error
802
+ ....: check_interrupt_only_occasionally()
803
+ Traceback (most recent call last):
804
+ ...
805
+ RuntimeError: Function is not interruptible within 1.0000 seconds, only after 1.60... seconds
806
+ sage: with ensure_interruptible_after(1, max_wait_after_interrupt=0.9):
807
+ ....: check_interrupt_only_occasionally()
808
+
809
+ TESTS::
810
+
811
+ sage: with ensure_interruptible_after(2) as data: sleep(1)
812
+ Traceback (most recent call last):
813
+ ...
814
+ RuntimeError: Function terminates early after 1... < 2.0000 seconds
815
+ sage: data
816
+ {'alarm_raised': False, 'elapsed': 1...}
817
+
818
+ The test above requires a large tolerance, because both ``time.sleep`` and
819
+ ``from posix.unistd cimport usleep`` may have slowdown on the order of 0.1s on Mac,
820
+ likely because the system is idle and GitHub CI switches the program out,
821
+ and context switch back takes time. Besides, there is an issue with ``Integer``
822
+ destructor, see `<https://github.com/sagemath/cysignals/issues/215>`_
823
+ So we use busy wait and Python integers::
824
+
825
+ sage: # needs sage.misc.cython
826
+ sage: cython(r'''
827
+ ....: from posix.time cimport clock_gettime, CLOCK_REALTIME, timespec, time_t
828
+ ....: from cysignals.signals cimport sig_check
829
+ ....:
830
+ ....: cpdef void interruptible_sleep(double seconds):
831
+ ....: cdef timespec start_time, target_time
832
+ ....: clock_gettime(CLOCK_REALTIME, &start_time)
833
+ ....:
834
+ ....: cdef time_t floor_seconds = <time_t>seconds
835
+ ....: target_time.tv_sec = start_time.tv_sec + floor_seconds
836
+ ....: target_time.tv_nsec = start_time.tv_nsec + <long>((seconds - floor_seconds) * 1e9)
837
+ ....: if target_time.tv_nsec >= 1000000000:
838
+ ....: target_time.tv_nsec -= 1000000000
839
+ ....: target_time.tv_sec += 1
840
+ ....:
841
+ ....: while True:
842
+ ....: sig_check()
843
+ ....: clock_gettime(CLOCK_REALTIME, &start_time)
844
+ ....: if start_time.tv_sec > target_time.tv_sec or (start_time.tv_sec == target_time.tv_sec and start_time.tv_nsec >= target_time.tv_nsec):
845
+ ....: break
846
+ ....: ''')
847
+ sage: with ensure_interruptible_after(2) as data: interruptible_sleep(1r)
848
+ Traceback (most recent call last):
849
+ ...
850
+ RuntimeError: Function terminates early after 1.00... < 2.0000 seconds
851
+ sage: with ensure_interruptible_after(1) as data: uninterruptible_sleep(2r)
852
+ Traceback (most recent call last):
853
+ ...
854
+ RuntimeError: Function is not interruptible within 1.0000 seconds, only after 2.00... seconds
855
+ sage: data
856
+ {'alarm_raised': True, 'elapsed': 2.0...}
857
+ sage: with ensure_interruptible_after(1): uninterruptible_sleep(2r); raise RuntimeError
858
+ Traceback (most recent call last):
859
+ ...
860
+ RuntimeError: Function is not interruptible within 1.0000 seconds, only after 2.00... seconds
861
+ sage: data
862
+ {'alarm_raised': True, 'elapsed': 2.0...}
863
+
864
+ ::
865
+
866
+ sage: with ensure_interruptible_after(1) as data: raise ValueError
867
+ Traceback (most recent call last):
868
+ ...
869
+ ValueError
870
+ sage: data
871
+ {'alarm_raised': False, 'elapsed': ...}
872
+ """
873
+ seconds = float(seconds)
874
+ max_wait_after_interrupt = float(max_wait_after_interrupt)
875
+ inaccuracy_tolerance = float(inaccuracy_tolerance)
876
+ # use Python float to avoid slowdown with Sage Integer (see https://github.com/sagemath/cysignals/issues/215)
877
+ data = {}
878
+ start_time = walltime()
879
+ alarm(seconds)
880
+ alarm_raised = False
881
+
882
+ try:
883
+ yield data
884
+ except AlarmInterrupt as e:
885
+ e.__traceback__ = None # workaround for https://github.com/python/cpython/pull/129276
886
+ alarm_raised = True
887
+ finally:
888
+ before_cancel_alarm_elapsed = walltime() - start_time
889
+ cancel_alarm()
890
+ elapsed = walltime() - start_time
891
+ data["elapsed"] = elapsed
892
+ data["alarm_raised"] = alarm_raised
893
+
894
+ if elapsed > seconds + max_wait_after_interrupt:
895
+ raise RuntimeError(
896
+ f"Function is not interruptible within {seconds:.4f} seconds, only after {elapsed:.4f} seconds"
897
+ + ("" if alarm_raised else " (__exit__ called before interrupt check)"))
898
+
899
+ if alarm_raised:
900
+ if elapsed < seconds - inaccuracy_tolerance:
901
+ raise RuntimeError(f"Interrupted too early: {elapsed:.4f} < {seconds:.4f}, this should not happen")
902
+ else:
903
+ raise RuntimeError(f"Function terminates early after {elapsed:.4f} < {seconds:.4f} seconds")
sage/interfaces/quit.py CHANGED
@@ -12,13 +12,24 @@ Quitting interfaces
12
12
  # https://www.gnu.org/licenses/
13
13
  ################################################################################
14
14
 
15
+ from __future__ import annotations
16
+
15
17
  import os
18
+ import subprocess
19
+ import sys
20
+ from typing import TYPE_CHECKING
16
21
 
22
+ from sage.env import DOT_SAGE, HOSTNAME
17
23
  from sage.misc.cachefunc import cached_function
18
24
 
25
+ if TYPE_CHECKING:
26
+ from weakref import ReferenceType
27
+
28
+ from sage.interfaces.expect import Expect
29
+
19
30
 
20
31
  @cached_function
21
- def sage_spawned_process_file():
32
+ def sage_spawned_process_file() -> str:
22
33
  """
23
34
  EXAMPLES::
24
35
 
@@ -29,23 +40,22 @@ def sage_spawned_process_file():
29
40
  # This is the old value of SAGE_TMP. Until sage-cleaner is
30
41
  # completely removed, we need to leave these spawned_processes
31
42
  # files where sage-cleaner will look for them.
32
- from sage.env import DOT_SAGE, HOSTNAME
33
43
  d = os.path.join(DOT_SAGE, "temp", HOSTNAME, str(os.getpid()))
34
44
  os.makedirs(d, exist_ok=True)
35
45
  return os.path.join(d, "spawned_processes")
36
46
 
37
47
 
38
- def register_spawned_process(pid, cmd=''):
48
+ def register_spawned_process(pid: int, cmd: str = "") -> None:
39
49
  """
40
50
  Write a line to the ``spawned_processes`` file with the given
41
51
  ``pid`` and ``cmd``.
42
52
  """
43
- if cmd != '':
53
+ if cmd != "":
44
54
  cmd = cmd.strip().split()[0]
45
55
  # This is safe, since only this process writes to this file.
46
56
  try:
47
- with open(sage_spawned_process_file(), 'a') as o:
48
- o.write('%s %s\n' % (pid, cmd))
57
+ with open(sage_spawned_process_file(), "a") as file:
58
+ file.write("%s %s\n" % (pid, cmd))
49
59
  except OSError:
50
60
  pass
51
61
  else:
@@ -53,13 +63,14 @@ def register_spawned_process(pid, cmd=''):
53
63
  # the cleaner ourselves upon being told that there will be
54
64
  # something to clean.
55
65
  from sage.interfaces.cleaner import start_cleaner
66
+
56
67
  start_cleaner()
57
68
 
58
69
 
59
- expect_objects = []
70
+ expect_objects: list[ReferenceType[Expect]] = []
60
71
 
61
72
 
62
- def expect_quitall(verbose=False):
73
+ def expect_quitall(verbose: bool = False) -> None:
63
74
  """
64
75
  EXAMPLES::
65
76
 
@@ -74,17 +85,17 @@ def expect_quitall(verbose=False):
74
85
  sage: sage.interfaces.quit.expect_quitall(verbose=True) # needs sage.libs.pari
75
86
  Exiting PARI/GP interpreter with PID ... running .../gp --fast --emacs --quiet --stacksize 10000000
76
87
  """
77
- for P in expect_objects:
78
- R = P()
79
- if R is not None:
88
+ for reference in expect_objects:
89
+ process = reference()
90
+ if process is not None:
80
91
  try:
81
- R.quit(verbose=verbose)
92
+ process.quit(verbose=verbose)
82
93
  except RuntimeError:
83
94
  pass
84
95
  kill_spawned_jobs()
85
96
 
86
97
 
87
- def kill_spawned_jobs(verbose=False):
98
+ def kill_spawned_jobs(verbose: bool = False):
88
99
  """
89
100
  INPUT:
90
101
 
@@ -110,19 +121,23 @@ def kill_spawned_jobs(verbose=False):
110
121
  if not os.path.exists(fname):
111
122
  return
112
123
 
113
- with open(fname) as f:
114
- for L in f:
115
- i = L.find(' ')
116
- pid = L[:i].strip()
124
+ with open(fname) as file:
125
+ for line in file:
126
+ i = line.find(" ")
127
+ pid = line[:i].strip()
117
128
  try:
118
129
  if verbose:
119
130
  print("Killing spawned job %s" % pid)
120
- os.killpg(int(pid), 9)
131
+ if sys.platform == "win32":
132
+ # From https://stackoverflow.com/a/47756757/873661
133
+ subprocess.call(["taskkill", "/F", "/T", "/PID", pid])
134
+ else:
135
+ os.killpg(int(pid), 9)
121
136
  except OSError:
122
137
  pass
123
138
 
124
139
 
125
- def is_running(pid):
140
+ def is_running(pid: int) -> bool:
126
141
  """
127
142
  Return ``True`` if and only if there is a process with id pid running.
128
143
  """
@@ -133,11 +148,11 @@ def is_running(pid):
133
148
  return False
134
149
 
135
150
 
136
- def invalidate_all():
151
+ def invalidate_all() -> None:
137
152
  """
138
153
  Invalidate all of the expect interfaces.
139
154
 
140
- This is used, e.g., by the fork-based @parallel decorator.
155
+ This is used, e.g., by the fork-based ``@parallel`` decorator.
141
156
 
142
157
  EXAMPLES::
143
158
 
@@ -157,7 +172,7 @@ def invalidate_all():
157
172
  sage: a, b # needs sage.libs.pari sage.symbolic
158
173
  (2, 3)
159
174
  """
160
- for I in expect_objects:
161
- I1 = I()
162
- if I1:
163
- I1.detach()
175
+ for reference in expect_objects:
176
+ process = reference()
177
+ if process:
178
+ process.detach()
sage/misc/cython.py CHANGED
@@ -61,7 +61,7 @@ def _standard_libs_libdirs_incdirs_aliases():
61
61
  if SAGE_LOCAL:
62
62
  standard_libdirs.append(os.path.join(SAGE_LOCAL, "lib"))
63
63
  standard_libdirs.extend(aliases["CBLAS_LIBDIR"] + aliases["NTL_LIBDIR"])
64
- standard_incdirs = sage_include_directories() + aliases["CBLAS_INCDIR"] + aliases["NTL_INCDIR"]
64
+ standard_incdirs = sage_include_directories(use_sources=True) + aliases["CBLAS_INCDIR"] + aliases["NTL_INCDIR"]
65
65
  return standard_libs, standard_libdirs, standard_incdirs, aliases
66
66
 
67
67
  ################################################################
sage/misc/sage_input.py CHANGED
@@ -1405,10 +1405,10 @@ class SageInputExpression:
1405
1405
  sage: sie(4)
1406
1406
  {call: {atomic:3}({atomic:4})}
1407
1407
  """
1408
- args = [self._sie_builder(_) for _ in args]
1409
- for k in kwargs:
1410
- kwargs[k] = self._sie_builder(kwargs[k])
1411
- return SIE_call(self._sie_builder, self, args, kwargs)
1408
+ new_args = [self._sie_builder(arg) for arg in args]
1409
+ new_kwargs = {key: self._sie_builder(val)
1410
+ for key, val in kwargs.items()}
1411
+ return SIE_call(self._sie_builder, self, new_args, new_kwargs)
1412
1412
 
1413
1413
  def __getitem__(self, key):
1414
1414
  r"""
@@ -21,11 +21,11 @@ sage: factor(2007)
21
21
  3^2 * 223
22
22
  sage: factor(31415926535898)
23
23
  2 * 3 * 53 * 73 * 2531 * 534697
24
- sage: n = 7403756347956171282804679609742957314259318888\
25
- ....: 9231289084936232638972765034028266276891996419625117\
26
- ....: 8439958943305021275853701189680982867331732731089309\
27
- ....: 0055250511687706329907239638078671008609696253793465\
28
- ....: 0563796359
24
+ sage: n = Integer('7403756347956171282804679609742957314259318888'
25
+ ....: '9231289084936232638972765034028266276891996419625117'
26
+ ....: '8439958943305021275853701189680982867331732731089309'
27
+ ....: '0055250511687706329907239638078671008609696253793465'
28
+ ....: '0563796359')
29
29
  sage: len(n.str(2))
30
30
  704
31
31
  sage: len(n.str(10))