passagemath-objects 10.6.41__cp314-cp314t-macosx_13_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-objects might be problematic. Click here for more details.
- passagemath_objects/.dylibs/libgmp.10.dylib +0 -0
- passagemath_objects/__init__.py +3 -0
- passagemath_objects-10.6.41.dist-info/METADATA +115 -0
- passagemath_objects-10.6.41.dist-info/RECORD +280 -0
- passagemath_objects-10.6.41.dist-info/WHEEL +6 -0
- passagemath_objects-10.6.41.dist-info/top_level.txt +3 -0
- sage/all__sagemath_objects.py +37 -0
- sage/arith/all__sagemath_objects.py +5 -0
- sage/arith/long.pxd +411 -0
- sage/arith/numerical_approx.cpython-314t-darwin.so +0 -0
- sage/arith/numerical_approx.pxd +35 -0
- sage/arith/numerical_approx.pyx +75 -0
- sage/arith/power.cpython-314t-darwin.so +0 -0
- sage/arith/power.pxd +31 -0
- sage/arith/power.pyx +127 -0
- sage/categories/action.cpython-314t-darwin.so +0 -0
- sage/categories/action.pxd +29 -0
- sage/categories/action.pyx +641 -0
- sage/categories/algebra_functor.py +745 -0
- sage/categories/all__sagemath_objects.py +33 -0
- sage/categories/basic.py +62 -0
- sage/categories/cartesian_product.py +295 -0
- sage/categories/category.py +3401 -0
- sage/categories/category_cy_helper.cpython-314t-darwin.so +0 -0
- sage/categories/category_cy_helper.pxd +8 -0
- sage/categories/category_cy_helper.pyx +322 -0
- sage/categories/category_singleton.cpython-314t-darwin.so +0 -0
- sage/categories/category_singleton.pxd +3 -0
- sage/categories/category_singleton.pyx +342 -0
- sage/categories/category_types.py +637 -0
- sage/categories/category_with_axiom.py +2876 -0
- sage/categories/covariant_functorial_construction.py +703 -0
- sage/categories/facade_sets.py +228 -0
- sage/categories/functor.cpython-314t-darwin.so +0 -0
- sage/categories/functor.pxd +7 -0
- sage/categories/functor.pyx +691 -0
- sage/categories/homset.py +1338 -0
- sage/categories/homsets.py +364 -0
- sage/categories/isomorphic_objects.py +73 -0
- sage/categories/map.cpython-314t-darwin.so +0 -0
- sage/categories/map.pxd +34 -0
- sage/categories/map.pyx +2112 -0
- sage/categories/morphism.cpython-314t-darwin.so +0 -0
- sage/categories/morphism.pxd +14 -0
- sage/categories/morphism.pyx +895 -0
- sage/categories/objects.py +167 -0
- sage/categories/primer.py +1696 -0
- sage/categories/pushout.py +4834 -0
- sage/categories/quotients.py +64 -0
- sage/categories/realizations.py +200 -0
- sage/categories/sets_cat.py +3228 -0
- sage/categories/sets_with_partial_maps.py +52 -0
- sage/categories/subobjects.py +64 -0
- sage/categories/subquotients.py +21 -0
- sage/categories/with_realizations.py +311 -0
- sage/cpython/__init__.py +19 -0
- sage/cpython/_py2_random.py +619 -0
- sage/cpython/all.py +3 -0
- sage/cpython/atexit.cpython-314t-darwin.so +0 -0
- sage/cpython/atexit.pyx +269 -0
- sage/cpython/builtin_types.cpython-314t-darwin.so +0 -0
- sage/cpython/builtin_types.pyx +7 -0
- sage/cpython/cython_metaclass.cpython-314t-darwin.so +0 -0
- sage/cpython/cython_metaclass.h +117 -0
- sage/cpython/cython_metaclass.pxd +3 -0
- sage/cpython/cython_metaclass.pyx +130 -0
- sage/cpython/debug.cpython-314t-darwin.so +0 -0
- sage/cpython/debug.pyx +302 -0
- sage/cpython/dict_del_by_value.cpython-314t-darwin.so +0 -0
- sage/cpython/dict_del_by_value.pxd +9 -0
- sage/cpython/dict_del_by_value.pyx +191 -0
- sage/cpython/dict_internal.h +245 -0
- sage/cpython/getattr.cpython-314t-darwin.so +0 -0
- sage/cpython/getattr.pxd +9 -0
- sage/cpython/getattr.pyx +439 -0
- sage/cpython/pycore_long.h +97 -0
- sage/cpython/pycore_long.pxd +10 -0
- sage/cpython/python_debug.h +44 -0
- sage/cpython/python_debug.pxd +47 -0
- sage/cpython/pyx_visit.h +13 -0
- sage/cpython/string.cpython-314t-darwin.so +0 -0
- sage/cpython/string.pxd +76 -0
- sage/cpython/string.pyx +34 -0
- sage/cpython/string_impl.h +60 -0
- sage/cpython/type.cpython-314t-darwin.so +0 -0
- sage/cpython/type.pxd +2 -0
- sage/cpython/type.pyx +40 -0
- sage/cpython/wrapperdescr.pxd +67 -0
- sage/ext/all__sagemath_objects.py +3 -0
- sage/ext/ccobject.h +64 -0
- sage/ext/cplusplus.pxd +17 -0
- sage/ext/mod_int.h +30 -0
- sage/ext/mod_int.pxd +24 -0
- sage/ext/stdsage.pxd +39 -0
- sage/groups/all__sagemath_objects.py +1 -0
- sage/groups/group.cpython-314t-darwin.so +0 -0
- sage/groups/group.pxd +14 -0
- sage/groups/group.pyx +322 -0
- sage/groups/old.cpython-314t-darwin.so +0 -0
- sage/groups/old.pxd +14 -0
- sage/groups/old.pyx +219 -0
- sage/libs/all__sagemath_objects.py +3 -0
- sage/libs/gmp/__init__.py +1 -0
- sage/libs/gmp/all.pxd +6 -0
- sage/libs/gmp/binop.pxd +23 -0
- sage/libs/gmp/misc.pxd +8 -0
- sage/libs/gmp/mpf.pxd +88 -0
- sage/libs/gmp/mpn.pxd +57 -0
- sage/libs/gmp/mpq.pxd +57 -0
- sage/libs/gmp/mpz.pxd +202 -0
- sage/libs/gmp/pylong.cpython-314t-darwin.so +0 -0
- sage/libs/gmp/pylong.pxd +12 -0
- sage/libs/gmp/pylong.pyx +150 -0
- sage/libs/gmp/random.pxd +25 -0
- sage/libs/gmp/randomize.pxd +59 -0
- sage/libs/gmp/types.pxd +53 -0
- sage/libs/gmpxx.pxd +19 -0
- sage/misc/abstract_method.py +276 -0
- sage/misc/all__sagemath_objects.py +43 -0
- sage/misc/bindable_class.py +253 -0
- sage/misc/c3_controlled.cpython-314t-darwin.so +0 -0
- sage/misc/c3_controlled.pxd +2 -0
- sage/misc/c3_controlled.pyx +1402 -0
- sage/misc/cachefunc.cpython-314t-darwin.so +0 -0
- sage/misc/cachefunc.pxd +43 -0
- sage/misc/cachefunc.pyx +3781 -0
- sage/misc/call.py +188 -0
- sage/misc/classcall_metaclass.cpython-314t-darwin.so +0 -0
- sage/misc/classcall_metaclass.pxd +14 -0
- sage/misc/classcall_metaclass.pyx +599 -0
- sage/misc/constant_function.cpython-314t-darwin.so +0 -0
- sage/misc/constant_function.pyx +130 -0
- sage/misc/decorators.py +747 -0
- sage/misc/fast_methods.cpython-314t-darwin.so +0 -0
- sage/misc/fast_methods.pxd +20 -0
- sage/misc/fast_methods.pyx +351 -0
- sage/misc/flatten.py +90 -0
- sage/misc/fpickle.cpython-314t-darwin.so +0 -0
- sage/misc/fpickle.pyx +177 -0
- sage/misc/function_mangling.cpython-314t-darwin.so +0 -0
- sage/misc/function_mangling.pxd +11 -0
- sage/misc/function_mangling.pyx +308 -0
- sage/misc/inherit_comparison.cpython-314t-darwin.so +0 -0
- sage/misc/inherit_comparison.pxd +5 -0
- sage/misc/inherit_comparison.pyx +105 -0
- sage/misc/instancedoc.cpython-314t-darwin.so +0 -0
- sage/misc/instancedoc.pyx +331 -0
- sage/misc/lazy_attribute.cpython-314t-darwin.so +0 -0
- sage/misc/lazy_attribute.pyx +607 -0
- sage/misc/lazy_format.py +135 -0
- sage/misc/lazy_import.cpython-314t-darwin.so +0 -0
- sage/misc/lazy_import.pyx +1299 -0
- sage/misc/lazy_import_cache.py +36 -0
- sage/misc/lazy_list.cpython-314t-darwin.so +0 -0
- sage/misc/lazy_list.pxd +19 -0
- sage/misc/lazy_list.pyx +1187 -0
- sage/misc/lazy_string.cpython-314t-darwin.so +0 -0
- sage/misc/lazy_string.pxd +7 -0
- sage/misc/lazy_string.pyx +546 -0
- sage/misc/misc.py +1066 -0
- sage/misc/misc_c.cpython-314t-darwin.so +0 -0
- sage/misc/misc_c.pxd +3 -0
- sage/misc/misc_c.pyx +766 -0
- sage/misc/namespace_package.py +37 -0
- sage/misc/nested_class.cpython-314t-darwin.so +0 -0
- sage/misc/nested_class.pxd +3 -0
- sage/misc/nested_class.pyx +394 -0
- sage/misc/persist.cpython-314t-darwin.so +0 -0
- sage/misc/persist.pyx +1251 -0
- sage/misc/prandom.py +418 -0
- sage/misc/randstate.cpython-314t-darwin.so +0 -0
- sage/misc/randstate.pxd +30 -0
- sage/misc/randstate.pyx +1059 -0
- sage/misc/repr.py +203 -0
- sage/misc/reset.cpython-314t-darwin.so +0 -0
- sage/misc/reset.pyx +196 -0
- sage/misc/sage_ostools.cpython-314t-darwin.so +0 -0
- sage/misc/sage_ostools.pyx +323 -0
- sage/misc/sage_timeit.py +276 -0
- sage/misc/sage_timeit_class.cpython-314t-darwin.so +0 -0
- sage/misc/sage_timeit_class.pyx +120 -0
- sage/misc/sage_unittest.py +637 -0
- sage/misc/sageinspect.py +2768 -0
- sage/misc/session.cpython-314t-darwin.so +0 -0
- sage/misc/session.pyx +392 -0
- sage/misc/superseded.py +557 -0
- sage/misc/test_nested_class.py +228 -0
- sage/misc/timing.py +264 -0
- sage/misc/unknown.py +222 -0
- sage/misc/verbose.py +253 -0
- sage/misc/weak_dict.cpython-314t-darwin.so +0 -0
- sage/misc/weak_dict.pxd +15 -0
- sage/misc/weak_dict.pyx +1231 -0
- sage/modules/all__sagemath_objects.py +1 -0
- sage/modules/module.cpython-314t-darwin.so +0 -0
- sage/modules/module.pxd +5 -0
- sage/modules/module.pyx +329 -0
- sage/rings/all__sagemath_objects.py +3 -0
- sage/rings/integer_fake.h +22 -0
- sage/rings/integer_fake.pxd +55 -0
- sage/sets/all__sagemath_objects.py +3 -0
- sage/sets/pythonclass.cpython-314t-darwin.so +0 -0
- sage/sets/pythonclass.pxd +9 -0
- sage/sets/pythonclass.pyx +247 -0
- sage/structure/__init__.py +4 -0
- sage/structure/all.py +30 -0
- sage/structure/category_object.cpython-314t-darwin.so +0 -0
- sage/structure/category_object.pxd +28 -0
- sage/structure/category_object.pyx +1087 -0
- sage/structure/coerce.cpython-314t-darwin.so +0 -0
- sage/structure/coerce.pxd +44 -0
- sage/structure/coerce.pyx +2107 -0
- sage/structure/coerce_actions.cpython-314t-darwin.so +0 -0
- sage/structure/coerce_actions.pxd +27 -0
- sage/structure/coerce_actions.pyx +988 -0
- sage/structure/coerce_dict.cpython-314t-darwin.so +0 -0
- sage/structure/coerce_dict.pxd +51 -0
- sage/structure/coerce_dict.pyx +1557 -0
- sage/structure/coerce_exceptions.py +23 -0
- sage/structure/coerce_maps.cpython-314t-darwin.so +0 -0
- sage/structure/coerce_maps.pxd +28 -0
- sage/structure/coerce_maps.pyx +718 -0
- sage/structure/debug_options.cpython-314t-darwin.so +0 -0
- sage/structure/debug_options.pxd +6 -0
- sage/structure/debug_options.pyx +54 -0
- sage/structure/dynamic_class.py +541 -0
- sage/structure/element.cpython-314t-darwin.so +0 -0
- sage/structure/element.pxd +272 -0
- sage/structure/element.pyx +4772 -0
- sage/structure/element_wrapper.cpython-314t-darwin.so +0 -0
- sage/structure/element_wrapper.pxd +12 -0
- sage/structure/element_wrapper.pyx +582 -0
- sage/structure/factorization.py +1422 -0
- sage/structure/factorization_integer.py +105 -0
- sage/structure/factory.cpython-314t-darwin.so +0 -0
- sage/structure/factory.pyx +786 -0
- sage/structure/formal_sum.py +489 -0
- sage/structure/gens_py.py +73 -0
- sage/structure/global_options.py +1743 -0
- sage/structure/indexed_generators.py +863 -0
- sage/structure/list_clone.cpython-314t-darwin.so +0 -0
- sage/structure/list_clone.pxd +65 -0
- sage/structure/list_clone.pyx +1867 -0
- sage/structure/list_clone_demo.cpython-314t-darwin.so +0 -0
- sage/structure/list_clone_demo.pyx +248 -0
- sage/structure/list_clone_timings.py +179 -0
- sage/structure/list_clone_timings_cy.cpython-314t-darwin.so +0 -0
- sage/structure/list_clone_timings_cy.pyx +86 -0
- sage/structure/mutability.cpython-314t-darwin.so +0 -0
- sage/structure/mutability.pxd +21 -0
- sage/structure/mutability.pyx +348 -0
- sage/structure/nonexact.py +69 -0
- sage/structure/parent.cpython-314t-darwin.so +0 -0
- sage/structure/parent.pxd +112 -0
- sage/structure/parent.pyx +3093 -0
- sage/structure/parent_base.cpython-314t-darwin.so +0 -0
- sage/structure/parent_base.pxd +13 -0
- sage/structure/parent_base.pyx +44 -0
- sage/structure/parent_gens.cpython-314t-darwin.so +0 -0
- sage/structure/parent_gens.pxd +22 -0
- sage/structure/parent_gens.pyx +377 -0
- sage/structure/parent_old.cpython-314t-darwin.so +0 -0
- sage/structure/parent_old.pxd +25 -0
- sage/structure/parent_old.pyx +294 -0
- sage/structure/proof/__init__.py +1 -0
- sage/structure/proof/all.py +243 -0
- sage/structure/proof/proof.py +300 -0
- sage/structure/richcmp.cpython-314t-darwin.so +0 -0
- sage/structure/richcmp.pxd +213 -0
- sage/structure/richcmp.pyx +495 -0
- sage/structure/sage_object.cpython-314t-darwin.so +0 -0
- sage/structure/sage_object.pxd +3 -0
- sage/structure/sage_object.pyx +988 -0
- sage/structure/sage_object_test.py +19 -0
- sage/structure/sequence.py +937 -0
- sage/structure/set_factories.py +1178 -0
- sage/structure/set_factories_example.py +527 -0
- sage/structure/support_view.py +179 -0
- sage/structure/test_factory.py +56 -0
- sage/structure/unique_representation.py +1359 -0
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-objects
|
|
2
|
+
"""
|
|
3
|
+
Miscellaneous operating system functions
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
IF UNAME_SYSNAME == "Linux" or UNAME_SYSNAME == "Darwin":
|
|
7
|
+
|
|
8
|
+
from posix.unistd cimport dup, dup2, close
|
|
9
|
+
|
|
10
|
+
from cpython.exc cimport PyErr_SetFromErrno
|
|
11
|
+
|
|
12
|
+
ELSE:
|
|
13
|
+
|
|
14
|
+
def dup(x):
|
|
15
|
+
return -1
|
|
16
|
+
|
|
17
|
+
def dup2(x, y):
|
|
18
|
+
return -1
|
|
19
|
+
|
|
20
|
+
def close():
|
|
21
|
+
return
|
|
22
|
+
|
|
23
|
+
def PyErr_SetFromErrno(x):
|
|
24
|
+
return
|
|
25
|
+
|
|
26
|
+
import os
|
|
27
|
+
import contextlib
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def have_program(program, path=None) -> bool:
|
|
31
|
+
"""
|
|
32
|
+
Return ``True`` if a ``program`` executable is found in the path
|
|
33
|
+
given by ``path``.
|
|
34
|
+
|
|
35
|
+
INPUT:
|
|
36
|
+
|
|
37
|
+
- ``program`` -- string, the name of the program to check
|
|
38
|
+
|
|
39
|
+
- ``path`` -- string or ``None``. Paths to search for ``program``,
|
|
40
|
+
separated by ``os.pathsep``. If ``None``, use the :envvar:`PATH`
|
|
41
|
+
environment variable.
|
|
42
|
+
|
|
43
|
+
OUTPUT: boolean
|
|
44
|
+
|
|
45
|
+
EXAMPLES::
|
|
46
|
+
|
|
47
|
+
sage: from sage.misc.sage_ostools import have_program
|
|
48
|
+
sage: have_program('ls')
|
|
49
|
+
True
|
|
50
|
+
sage: have_program('there_is_not_a_program_with_this_name')
|
|
51
|
+
False
|
|
52
|
+
sage: have_program('sh', '/bin')
|
|
53
|
+
True
|
|
54
|
+
sage: have_program('sage', '/there_is_not_a_path_with_this_name')
|
|
55
|
+
False
|
|
56
|
+
sage: have_program('there_is_not_a_program_with_this_name', "/bin")
|
|
57
|
+
False
|
|
58
|
+
"""
|
|
59
|
+
if path is None:
|
|
60
|
+
path = os.environ.get('PATH', "")
|
|
61
|
+
for p in path.split(os.pathsep):
|
|
62
|
+
try:
|
|
63
|
+
if os.access(os.path.join(p, program), os.X_OK):
|
|
64
|
+
return True
|
|
65
|
+
except OSError:
|
|
66
|
+
pass
|
|
67
|
+
return False
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@contextlib.contextmanager
|
|
71
|
+
def restore_cwd(chdir=None):
|
|
72
|
+
"""
|
|
73
|
+
Context manager that restores the original working directory upon exiting.
|
|
74
|
+
|
|
75
|
+
INPUT:
|
|
76
|
+
|
|
77
|
+
- ``chdir`` -- optionally change directories to the given directory
|
|
78
|
+
upon entering the context manager
|
|
79
|
+
|
|
80
|
+
EXAMPLES::
|
|
81
|
+
|
|
82
|
+
sage: from sage.misc.sage_ostools import restore_cwd
|
|
83
|
+
sage: import tempfile
|
|
84
|
+
sage: orig_cwd = os.getcwd()
|
|
85
|
+
sage: with tempfile.TemporaryDirectory() as d:
|
|
86
|
+
....: with restore_cwd(d):
|
|
87
|
+
....: print(os.getcwd() == orig_cwd)
|
|
88
|
+
False
|
|
89
|
+
sage: os.getcwd() == orig_cwd
|
|
90
|
+
True
|
|
91
|
+
"""
|
|
92
|
+
orig_cwd = os.getcwd()
|
|
93
|
+
if chdir is not None:
|
|
94
|
+
os.chdir(chdir)
|
|
95
|
+
try:
|
|
96
|
+
yield
|
|
97
|
+
finally:
|
|
98
|
+
os.chdir(orig_cwd)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
cdef file_and_fd(x, int* fd):
|
|
102
|
+
"""
|
|
103
|
+
If ``x`` is a file, return ``x`` and set ``*fd`` to its file
|
|
104
|
+
descriptor. If ``x`` is an integer, return ``None`` and set
|
|
105
|
+
``*fd`` to ``x``. Otherwise, set ``*fd = -1`` and raise a
|
|
106
|
+
:exc:`TypeError`.
|
|
107
|
+
"""
|
|
108
|
+
fd[0] = -1
|
|
109
|
+
try:
|
|
110
|
+
m = x.fileno
|
|
111
|
+
except AttributeError:
|
|
112
|
+
try:
|
|
113
|
+
fd[0] = x
|
|
114
|
+
except Exception: # Some objects raise bizarre exceptions when calling int()
|
|
115
|
+
raise TypeError(f"{x} must be a Python file or an integer")
|
|
116
|
+
return None
|
|
117
|
+
fd[0] = m()
|
|
118
|
+
return x
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
cdef class redirection:
|
|
122
|
+
r"""
|
|
123
|
+
Context to implement redirection of files, analogous to the
|
|
124
|
+
``>file`` or ``1>&2`` syntax in POSIX shells.
|
|
125
|
+
|
|
126
|
+
Unlike the ``redirect_stdout`` and ``redirect_stderr`` contexts in
|
|
127
|
+
the Python 3.4 standard library, this acts on the OS level, not on
|
|
128
|
+
the Python level. This implies that it only works for true files,
|
|
129
|
+
not duck-type file objects such as ``StringIO``.
|
|
130
|
+
|
|
131
|
+
INPUT:
|
|
132
|
+
|
|
133
|
+
- ``source`` -- the file to be redirected
|
|
134
|
+
|
|
135
|
+
- ``dest`` -- where the source file should be redirected to
|
|
136
|
+
|
|
137
|
+
- ``close`` -- boolean (default: ``True``); whether to close the
|
|
138
|
+
destination file upon exiting the context. This is only supported
|
|
139
|
+
if ``dest`` is a Python file.
|
|
140
|
+
|
|
141
|
+
The ``source`` and ``dest`` arguments can be either Python files
|
|
142
|
+
or file descriptors.
|
|
143
|
+
|
|
144
|
+
EXAMPLES::
|
|
145
|
+
|
|
146
|
+
sage: from sage.misc.sage_ostools import redirection
|
|
147
|
+
sage: fn = tmp_filename()
|
|
148
|
+
|
|
149
|
+
::
|
|
150
|
+
|
|
151
|
+
sage: with redirection(sys.stdout, open(fn, 'w')):
|
|
152
|
+
....: print("hello world!")
|
|
153
|
+
sage: with open(fn) as f:
|
|
154
|
+
....: _ = sys.stdout.write(f.read())
|
|
155
|
+
hello world!
|
|
156
|
+
|
|
157
|
+
We can do the same using a file descriptor as source::
|
|
158
|
+
|
|
159
|
+
sage: fd = sys.stdout.fileno()
|
|
160
|
+
sage: with redirection(fd, open(fn, 'wb')):
|
|
161
|
+
....: _ = os.write(fd, b"hello world!\n")
|
|
162
|
+
sage: with open(fn) as f:
|
|
163
|
+
....: _ = sys.stdout.write(f.read())
|
|
164
|
+
hello world!
|
|
165
|
+
|
|
166
|
+
The converse also works::
|
|
167
|
+
|
|
168
|
+
sage: with open(fn, 'w') as f:
|
|
169
|
+
....: _ = f.write("This goes to the file\n")
|
|
170
|
+
....: with redirection(f, sys.stdout, close=False):
|
|
171
|
+
....: _ = f.write("This goes to stdout\n")
|
|
172
|
+
....: _ = f.write("This goes to the file again\n")
|
|
173
|
+
This goes to stdout
|
|
174
|
+
sage: with open(fn) as f:
|
|
175
|
+
....: _ = sys.stdout.write(f.read())
|
|
176
|
+
This goes to the file
|
|
177
|
+
This goes to the file again
|
|
178
|
+
|
|
179
|
+
The same :class:`redirection` instance can be reused multiple times,
|
|
180
|
+
provided that ``close=False``::
|
|
181
|
+
|
|
182
|
+
sage: f = open(fn, 'w+')
|
|
183
|
+
sage: r = redirection(sys.stdout, f, close=False)
|
|
184
|
+
sage: with r:
|
|
185
|
+
....: print("Line 1")
|
|
186
|
+
sage: with r:
|
|
187
|
+
....: print("Line 2")
|
|
188
|
+
sage: with f:
|
|
189
|
+
....: _ = f.seek(0)
|
|
190
|
+
....: _ = sys.stdout.write(f.read())
|
|
191
|
+
Line 1
|
|
192
|
+
Line 2
|
|
193
|
+
|
|
194
|
+
The redirection also works for subprocesses::
|
|
195
|
+
|
|
196
|
+
sage: import subprocess
|
|
197
|
+
sage: with redirection(sys.stdout, open(fn, 'w')):
|
|
198
|
+
....: _ = subprocess.call(["echo", "hello world"])
|
|
199
|
+
sage: with open(fn) as f:
|
|
200
|
+
....: _ = sys.stdout.write(f.read())
|
|
201
|
+
hello world
|
|
202
|
+
|
|
203
|
+
TESTS::
|
|
204
|
+
|
|
205
|
+
sage: import io
|
|
206
|
+
sage: redirection(sys.stdout, io.StringIO())
|
|
207
|
+
Traceback (most recent call last):
|
|
208
|
+
...
|
|
209
|
+
io.UnsupportedOperation: fileno
|
|
210
|
+
|
|
211
|
+
The redirection is removed and the destination file is closed even
|
|
212
|
+
in the case of errors::
|
|
213
|
+
|
|
214
|
+
sage: f = open(os.devnull, 'w')
|
|
215
|
+
sage: with redirection(sys.stdout, f):
|
|
216
|
+
....: raise KeyboardInterrupt
|
|
217
|
+
Traceback (most recent call last):
|
|
218
|
+
...
|
|
219
|
+
KeyboardInterrupt
|
|
220
|
+
sage: f.closed
|
|
221
|
+
True
|
|
222
|
+
|
|
223
|
+
Reusing a :class:`redirection` instance with ``close=True``::
|
|
224
|
+
|
|
225
|
+
sage: f = open(fn, 'w+')
|
|
226
|
+
sage: r = redirection(sys.stdout, f, close=True)
|
|
227
|
+
sage: with r:
|
|
228
|
+
....: print("Line 1")
|
|
229
|
+
sage: with r:
|
|
230
|
+
....: print("Line 2")
|
|
231
|
+
Traceback (most recent call last):
|
|
232
|
+
...
|
|
233
|
+
ValueError: invalid destination file
|
|
234
|
+
|
|
235
|
+
Using ``close=True`` on a non-file::
|
|
236
|
+
|
|
237
|
+
sage: redirection(sys.stdout, 0, close=True)
|
|
238
|
+
Traceback (most recent call last):
|
|
239
|
+
...
|
|
240
|
+
ValueError: close=True requires a Python destination file
|
|
241
|
+
|
|
242
|
+
Passing invalid file descriptors::
|
|
243
|
+
|
|
244
|
+
sage: with redirection(-123, open(os.devnull, 'w')):
|
|
245
|
+
....: pass
|
|
246
|
+
Traceback (most recent call last):
|
|
247
|
+
...
|
|
248
|
+
OSError: [Errno 9] Bad file descriptor
|
|
249
|
+
sage: with redirection(sys.stdout, -123):
|
|
250
|
+
....: pass
|
|
251
|
+
Traceback (most recent call last):
|
|
252
|
+
...
|
|
253
|
+
OSError: [Errno 9] Bad file descriptor
|
|
254
|
+
|
|
255
|
+
Nesting the same :class:`redirection` object is not allowed::
|
|
256
|
+
|
|
257
|
+
sage: with redirection(sys.stdout, open(os.devnull, 'w')) as r:
|
|
258
|
+
....: with r:
|
|
259
|
+
....: pass
|
|
260
|
+
Traceback (most recent call last):
|
|
261
|
+
...
|
|
262
|
+
ValueError: source already redirected
|
|
263
|
+
"""
|
|
264
|
+
cdef readonly source_file, dest_file
|
|
265
|
+
cdef readonly int source_fd, dest_fd, dup_source_fd
|
|
266
|
+
cdef bint close_dest
|
|
267
|
+
|
|
268
|
+
def __cinit__(self):
|
|
269
|
+
self.source_fd = -1
|
|
270
|
+
self.dest_fd = -1
|
|
271
|
+
self.dup_source_fd = -1
|
|
272
|
+
|
|
273
|
+
def __init__(self, source, dest, close=None):
|
|
274
|
+
self.source_file = file_and_fd(source, &self.source_fd)
|
|
275
|
+
self.dest_file = file_and_fd(dest, &self.dest_fd)
|
|
276
|
+
|
|
277
|
+
if self.dest_file is None:
|
|
278
|
+
if close:
|
|
279
|
+
raise ValueError("close=True requires a Python destination file")
|
|
280
|
+
elif close is None:
|
|
281
|
+
close = True
|
|
282
|
+
self.close_dest = close
|
|
283
|
+
|
|
284
|
+
cdef int flush(self) except -1:
|
|
285
|
+
for f in (self.source_file, self.dest_file):
|
|
286
|
+
if f is not None:
|
|
287
|
+
f.flush()
|
|
288
|
+
|
|
289
|
+
def __enter__(self):
|
|
290
|
+
# Basic sanity checks
|
|
291
|
+
if self.source_fd == -1:
|
|
292
|
+
raise ValueError("invalid source file")
|
|
293
|
+
if self.dest_fd == -1:
|
|
294
|
+
raise ValueError("invalid destination file")
|
|
295
|
+
if self.dup_source_fd != -1:
|
|
296
|
+
raise ValueError("source already redirected")
|
|
297
|
+
|
|
298
|
+
self.flush()
|
|
299
|
+
|
|
300
|
+
dupsrc = dup(self.source_fd)
|
|
301
|
+
if dupsrc == -1:
|
|
302
|
+
PyErr_SetFromErrno(OSError)
|
|
303
|
+
fd = dup2(self.dest_fd, self.source_fd)
|
|
304
|
+
if fd == -1:
|
|
305
|
+
try:
|
|
306
|
+
PyErr_SetFromErrno(OSError)
|
|
307
|
+
finally:
|
|
308
|
+
close(dupsrc)
|
|
309
|
+
self.dup_source_fd = dupsrc
|
|
310
|
+
return self
|
|
311
|
+
|
|
312
|
+
def __exit__(self, *args):
|
|
313
|
+
try:
|
|
314
|
+
self.flush()
|
|
315
|
+
finally:
|
|
316
|
+
fd = dup2(self.dup_source_fd, self.source_fd)
|
|
317
|
+
if fd == -1:
|
|
318
|
+
PyErr_SetFromErrno(OSError)
|
|
319
|
+
close(self.dup_source_fd)
|
|
320
|
+
self.dup_source_fd = -1
|
|
321
|
+
if self.close_dest:
|
|
322
|
+
self.dest_file.close()
|
|
323
|
+
self.dest_fd = -1
|
sage/misc/sage_timeit.py
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-objects
|
|
2
|
+
"""
|
|
3
|
+
Accurate timing information for Sage commands
|
|
4
|
+
|
|
5
|
+
This is an implementation of nice timeit functionality, like the
|
|
6
|
+
``%timeit`` magic command in IPython. To use it, use the ``timeit``
|
|
7
|
+
command. This command then calls :func:`sage_timeit`, which you can
|
|
8
|
+
find below.
|
|
9
|
+
|
|
10
|
+
EXAMPLES::
|
|
11
|
+
|
|
12
|
+
sage: timeit('1+1') # random output
|
|
13
|
+
625 loops, best of 3: 314 ns per loop
|
|
14
|
+
|
|
15
|
+
AUTHOR:
|
|
16
|
+
|
|
17
|
+
-- William Stein, based on code by Fernando Perez included in IPython
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import os
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class SageTimeitResult:
|
|
24
|
+
r"""
|
|
25
|
+
Represent the statistics of a timeit() command.
|
|
26
|
+
|
|
27
|
+
Prints as a string so that it can be easily returned to a user.
|
|
28
|
+
|
|
29
|
+
INPUT:
|
|
30
|
+
|
|
31
|
+
- ``stats`` -- tuple of length 5 containing the following information:
|
|
32
|
+
|
|
33
|
+
- integer, number of loops
|
|
34
|
+
- integer, repeat number
|
|
35
|
+
- Python integer, number of digits to print
|
|
36
|
+
- number, best timing result
|
|
37
|
+
- str, time unit
|
|
38
|
+
|
|
39
|
+
EXAMPLES::
|
|
40
|
+
|
|
41
|
+
sage: from sage.misc.sage_timeit import SageTimeitResult
|
|
42
|
+
sage: SageTimeitResult( (3, 5, int(8), pi, 'ms') ) # needs sage.symbolic
|
|
43
|
+
3 loops, best of 5: 3.1415927 ms per loop
|
|
44
|
+
|
|
45
|
+
::
|
|
46
|
+
|
|
47
|
+
sage: units = [u"s", u"ms", u"μs", u"ns"]
|
|
48
|
+
sage: scaling = [1, 1e3, 1e6, 1e9]
|
|
49
|
+
sage: number = 7
|
|
50
|
+
sage: repeat = 13
|
|
51
|
+
sage: precision = int(5)
|
|
52
|
+
sage: best = pi / 10 ^ 9 # needs sage.symbolic
|
|
53
|
+
sage: order = 3
|
|
54
|
+
sage: stats = (number, repeat, precision, best * scaling[order], units[order]) # needs sage.symbolic
|
|
55
|
+
sage: SageTimeitResult(stats) # needs sage.symbolic
|
|
56
|
+
7 loops, best of 13: 3.1416 ns per loop
|
|
57
|
+
|
|
58
|
+
If the third argument is not a Python integer, a :exc:`TypeError` is raised::
|
|
59
|
+
|
|
60
|
+
sage: SageTimeitResult( (1, 2, 3, 4, 's') )
|
|
61
|
+
<repr(<sage.misc.sage_timeit.SageTimeitResult at 0x...>) failed: TypeError: * wants int>
|
|
62
|
+
"""
|
|
63
|
+
def __init__(self, stats, series=None):
|
|
64
|
+
r"""
|
|
65
|
+
Construction of a timing result.
|
|
66
|
+
|
|
67
|
+
See documentation of ``SageTimeitResult`` for more details and
|
|
68
|
+
examples.
|
|
69
|
+
|
|
70
|
+
EXAMPLES::
|
|
71
|
+
|
|
72
|
+
sage: from sage.misc.sage_timeit import SageTimeitResult
|
|
73
|
+
sage: SageTimeitResult( (3, 5, int(8), pi, 'ms') ) # needs sage.symbolic
|
|
74
|
+
3 loops, best of 5: 3.1415927 ms per loop
|
|
75
|
+
sage: s = SageTimeitResult( (3, 5, int(8), pi, 'ms'), [1.0,1.1,0.5]) # needs sage.symbolic
|
|
76
|
+
sage: s.series # needs sage.symbolic
|
|
77
|
+
[1.00000000000000, 1.10000000000000, 0.500000000000000]
|
|
78
|
+
"""
|
|
79
|
+
self.stats = stats
|
|
80
|
+
self.series = series if not None else []
|
|
81
|
+
|
|
82
|
+
def __repr__(self):
|
|
83
|
+
r"""
|
|
84
|
+
String representation.
|
|
85
|
+
|
|
86
|
+
EXAMPLES::
|
|
87
|
+
|
|
88
|
+
sage: from sage.misc.sage_timeit import SageTimeitResult
|
|
89
|
+
sage: stats = (1, 2, int(3), pi, 'ns') # needs sage.symbolic
|
|
90
|
+
sage: SageTimeitResult(stats) #indirect doctest # needs sage.symbolic
|
|
91
|
+
1 loop, best of 2: 3.14 ns per loop
|
|
92
|
+
"""
|
|
93
|
+
if self.stats[0] > 1:
|
|
94
|
+
s = "%d loops, best of %d: %.*g %s per loop" % self.stats
|
|
95
|
+
else:
|
|
96
|
+
s = "%d loop, best of %d: %.*g %s per loop" % self.stats
|
|
97
|
+
|
|
98
|
+
if isinstance(s, str):
|
|
99
|
+
return s
|
|
100
|
+
return s.encode("utf-8")
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def sage_timeit(stmt, globals_dict=None, preparse=None, number=0, repeat=3, precision=3, seconds=False):
|
|
104
|
+
"""nodetex
|
|
105
|
+
Accurately measure the wall time required to execute ``stmt``.
|
|
106
|
+
|
|
107
|
+
INPUT:
|
|
108
|
+
|
|
109
|
+
- ``stmt`` -- a text string
|
|
110
|
+
|
|
111
|
+
- ``globals_dict`` -- dictionary or ``None`` (default). Evaluate
|
|
112
|
+
``stmt`` in the context of the globals dictionary. If not set,
|
|
113
|
+
the current ``globals()`` dictionary is used.
|
|
114
|
+
|
|
115
|
+
- ``preparse`` -- (default: use globals preparser default) if
|
|
116
|
+
``True`` preparse ``stmt`` using the Sage preparser
|
|
117
|
+
|
|
118
|
+
- ``number`` -- integer; (default: 0); number of loops
|
|
119
|
+
|
|
120
|
+
- ``repeat`` -- integer; (default: 3); number of repetition
|
|
121
|
+
|
|
122
|
+
- ``precision`` -- integer; (default: 3); precision of output time
|
|
123
|
+
|
|
124
|
+
- ``seconds`` -- boolean (default: ``False``); whether to just
|
|
125
|
+
return time in seconds
|
|
126
|
+
|
|
127
|
+
OUTPUT:
|
|
128
|
+
|
|
129
|
+
An instance of ``SageTimeitResult`` unless the optional parameter
|
|
130
|
+
``seconds=True`` is passed. In that case, the elapsed time in
|
|
131
|
+
seconds is returned as a floating-point number.
|
|
132
|
+
|
|
133
|
+
EXAMPLES::
|
|
134
|
+
|
|
135
|
+
sage: from sage.misc.sage_timeit import sage_timeit
|
|
136
|
+
sage: sage_timeit('3^100000', globals(), preparse=True, number=50) # random output
|
|
137
|
+
'50 loops, best of 3: 1.97 ms per loop'
|
|
138
|
+
sage: sage_timeit('3^100000', globals(), preparse=False, number=50) # random output
|
|
139
|
+
'50 loops, best of 3: 67.1 ns per loop'
|
|
140
|
+
sage: a = 10
|
|
141
|
+
sage: sage_timeit('a^2', globals(), number=50) # random output
|
|
142
|
+
'50 loops, best of 3: 4.26 us per loop'
|
|
143
|
+
|
|
144
|
+
If you only want to see the timing and not have access to additional
|
|
145
|
+
information, just use the ``timeit`` object::
|
|
146
|
+
|
|
147
|
+
sage: timeit('10^2', number=50)
|
|
148
|
+
50 loops, best of 3: ... per loop
|
|
149
|
+
|
|
150
|
+
Using sage_timeit gives you more information though::
|
|
151
|
+
|
|
152
|
+
sage: s = sage_timeit('10^2', globals(), repeat=1000)
|
|
153
|
+
sage: len(s.series)
|
|
154
|
+
1000
|
|
155
|
+
sage: mean(s.series) # random output # needs sage.modules
|
|
156
|
+
3.1298141479492283e-07
|
|
157
|
+
sage: min(s.series) # random output
|
|
158
|
+
2.9258728027343752e-07
|
|
159
|
+
sage: t = stats.TimeSeries(s.series) # needs numpy sage.modules
|
|
160
|
+
sage: t.scale(10^6).plot_histogram(bins=20,figsize=[12,6], ymax=2) # needs numpy sage.modules sage.plot
|
|
161
|
+
Graphics object consisting of 20 graphics primitives
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
The input expression can contain newlines (but doctests cannot, so
|
|
165
|
+
we use ``os.linesep`` here)::
|
|
166
|
+
|
|
167
|
+
sage: from sage.misc.sage_timeit import sage_timeit
|
|
168
|
+
sage: from os import linesep as CR
|
|
169
|
+
sage: # sage_timeit(r'a = 2\\nb=131\\nfactor(a^b-1)')
|
|
170
|
+
sage: sage_timeit('a = 2' + CR + 'b=131' + CR + 'factor(a^b-1)', # needs sage.libs.pari
|
|
171
|
+
....: globals(), number=10)
|
|
172
|
+
10 loops, best of 3: ... per loop
|
|
173
|
+
|
|
174
|
+
Test to make sure that ``timeit`` behaves well with output::
|
|
175
|
+
|
|
176
|
+
sage: timeit("print('Hi')", number=50)
|
|
177
|
+
50 loops, best of 3: ... per loop
|
|
178
|
+
|
|
179
|
+
If you want a machine-readable output, use the ``seconds=True`` option::
|
|
180
|
+
|
|
181
|
+
sage: timeit("print('Hi')", seconds=True) # random output
|
|
182
|
+
1.42555236816e-06
|
|
183
|
+
sage: t = timeit("print('Hi')", seconds=True)
|
|
184
|
+
sage: t #r random output
|
|
185
|
+
3.6010742187499999e-07
|
|
186
|
+
|
|
187
|
+
TESTS:
|
|
188
|
+
|
|
189
|
+
Make sure that garbage collection is re-enabled after an exception
|
|
190
|
+
occurs in timeit::
|
|
191
|
+
|
|
192
|
+
sage: def f(): raise ValueError
|
|
193
|
+
sage: import gc
|
|
194
|
+
sage: gc.isenabled()
|
|
195
|
+
True
|
|
196
|
+
sage: timeit("f()")
|
|
197
|
+
Traceback (most recent call last):
|
|
198
|
+
...
|
|
199
|
+
ValueError
|
|
200
|
+
sage: gc.isenabled()
|
|
201
|
+
True
|
|
202
|
+
"""
|
|
203
|
+
import math
|
|
204
|
+
import timeit as timeit_
|
|
205
|
+
|
|
206
|
+
import sage.repl.interpreter as interpreter
|
|
207
|
+
import sage.repl.preparse as preparser
|
|
208
|
+
|
|
209
|
+
number = int(number)
|
|
210
|
+
repeat = int(repeat)
|
|
211
|
+
precision = int(precision)
|
|
212
|
+
if preparse is None:
|
|
213
|
+
preparse = interpreter._do_preparse
|
|
214
|
+
if preparse:
|
|
215
|
+
stmt = preparser.preparse(stmt)
|
|
216
|
+
if stmt == "":
|
|
217
|
+
return ''
|
|
218
|
+
|
|
219
|
+
units = ["s", "ms", "μs", "ns"]
|
|
220
|
+
scaling = [1, 1e3, 1e6, 1e9]
|
|
221
|
+
|
|
222
|
+
timer = timeit_.Timer()
|
|
223
|
+
|
|
224
|
+
# this code has tight coupling to the inner workings of timeit.Timer,
|
|
225
|
+
# but is there a better way to achieve that the code stmt has access
|
|
226
|
+
# to the shell namespace?
|
|
227
|
+
|
|
228
|
+
src = timeit_.template.format(stmt=timeit_.reindent(stmt, 8),
|
|
229
|
+
setup='pass', init='')
|
|
230
|
+
code = compile(src, '<magic-timeit>', 'exec')
|
|
231
|
+
ns = {}
|
|
232
|
+
if not globals_dict:
|
|
233
|
+
globals_dict = globals()
|
|
234
|
+
exec(code, globals_dict, ns)
|
|
235
|
+
timer.inner = ns["inner"]
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
import sys
|
|
239
|
+
f = sys.stdout
|
|
240
|
+
|
|
241
|
+
try:
|
|
242
|
+
null = open(os.devnull, 'w')
|
|
243
|
+
except Exception:
|
|
244
|
+
null = None
|
|
245
|
+
|
|
246
|
+
try:
|
|
247
|
+
if null is not None:
|
|
248
|
+
sys.stdout = null
|
|
249
|
+
|
|
250
|
+
if number == 0:
|
|
251
|
+
# determine number so that 0.2 <= total time < 2.0
|
|
252
|
+
number = 1
|
|
253
|
+
for i in range(1, 5):
|
|
254
|
+
number *= 5
|
|
255
|
+
if timer.timeit(number) >= 0.2:
|
|
256
|
+
break
|
|
257
|
+
|
|
258
|
+
series = [s / number for s in timer.repeat(repeat, number)]
|
|
259
|
+
best = min(series)
|
|
260
|
+
|
|
261
|
+
finally:
|
|
262
|
+
if null is not None:
|
|
263
|
+
sys.stdout.close()
|
|
264
|
+
sys.stdout = f
|
|
265
|
+
import gc
|
|
266
|
+
gc.enable()
|
|
267
|
+
|
|
268
|
+
if seconds:
|
|
269
|
+
return best
|
|
270
|
+
|
|
271
|
+
if best > 0.0:
|
|
272
|
+
order = min(-int(math.floor(math.log10(best)) // 3), 3)
|
|
273
|
+
else:
|
|
274
|
+
order = 3
|
|
275
|
+
stats = (number, repeat, precision, best * scaling[order], units[order])
|
|
276
|
+
return SageTimeitResult(stats, series=series)
|
|
Binary file
|