passagemath-objects 10.6.47__cp311-cp311-macosx_13_0_x86_64.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.
- passagemath_objects/.dylibs/libgmp.10.dylib +0 -0
- passagemath_objects/__init__.py +3 -0
- passagemath_objects-10.6.47.dist-info/METADATA +115 -0
- passagemath_objects-10.6.47.dist-info/RECORD +280 -0
- passagemath_objects-10.6.47.dist-info/WHEEL +6 -0
- passagemath_objects-10.6.47.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-311-darwin.so +0 -0
- sage/arith/numerical_approx.pxd +35 -0
- sage/arith/numerical_approx.pyx +75 -0
- sage/arith/power.cpython-311-darwin.so +0 -0
- sage/arith/power.pxd +31 -0
- sage/arith/power.pyx +127 -0
- sage/categories/action.cpython-311-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-311-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-311-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-311-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-311-darwin.so +0 -0
- sage/categories/map.pxd +34 -0
- sage/categories/map.pyx +2106 -0
- sage/categories/morphism.cpython-311-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 +3290 -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-311-darwin.so +0 -0
- sage/cpython/atexit.pyx +269 -0
- sage/cpython/builtin_types.cpython-311-darwin.so +0 -0
- sage/cpython/builtin_types.pyx +7 -0
- sage/cpython/cython_metaclass.cpython-311-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-311-darwin.so +0 -0
- sage/cpython/debug.pyx +302 -0
- sage/cpython/dict_del_by_value.cpython-311-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-311-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-311-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-311-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-311-darwin.so +0 -0
- sage/groups/group.pxd +14 -0
- sage/groups/group.pyx +322 -0
- sage/groups/old.cpython-311-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-311-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-311-darwin.so +0 -0
- sage/misc/c3_controlled.pxd +2 -0
- sage/misc/c3_controlled.pyx +1402 -0
- sage/misc/cachefunc.cpython-311-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-311-darwin.so +0 -0
- sage/misc/classcall_metaclass.pxd +14 -0
- sage/misc/classcall_metaclass.pyx +599 -0
- sage/misc/constant_function.cpython-311-darwin.so +0 -0
- sage/misc/constant_function.pyx +130 -0
- sage/misc/decorators.py +747 -0
- sage/misc/fast_methods.cpython-311-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-311-darwin.so +0 -0
- sage/misc/fpickle.pyx +177 -0
- sage/misc/function_mangling.cpython-311-darwin.so +0 -0
- sage/misc/function_mangling.pxd +11 -0
- sage/misc/function_mangling.pyx +308 -0
- sage/misc/inherit_comparison.cpython-311-darwin.so +0 -0
- sage/misc/inherit_comparison.pxd +5 -0
- sage/misc/inherit_comparison.pyx +105 -0
- sage/misc/instancedoc.cpython-311-darwin.so +0 -0
- sage/misc/instancedoc.pyx +331 -0
- sage/misc/lazy_attribute.cpython-311-darwin.so +0 -0
- sage/misc/lazy_attribute.pyx +607 -0
- sage/misc/lazy_format.py +135 -0
- sage/misc/lazy_import.cpython-311-darwin.so +0 -0
- sage/misc/lazy_import.pyx +1299 -0
- sage/misc/lazy_import_cache.py +36 -0
- sage/misc/lazy_list.cpython-311-darwin.so +0 -0
- sage/misc/lazy_list.pxd +19 -0
- sage/misc/lazy_list.pyx +1187 -0
- sage/misc/lazy_string.cpython-311-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-311-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-311-darwin.so +0 -0
- sage/misc/nested_class.pxd +3 -0
- sage/misc/nested_class.pyx +394 -0
- sage/misc/persist.cpython-311-darwin.so +0 -0
- sage/misc/persist.pyx +1251 -0
- sage/misc/prandom.py +418 -0
- sage/misc/randstate.cpython-311-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-311-darwin.so +0 -0
- sage/misc/reset.pyx +196 -0
- sage/misc/sage_ostools.cpython-311-darwin.so +0 -0
- sage/misc/sage_ostools.pyx +323 -0
- sage/misc/sage_timeit.py +275 -0
- sage/misc/sage_timeit_class.cpython-311-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-311-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-311-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-311-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-311-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-311-darwin.so +0 -0
- sage/structure/category_object.pxd +28 -0
- sage/structure/category_object.pyx +1087 -0
- sage/structure/coerce.cpython-311-darwin.so +0 -0
- sage/structure/coerce.pxd +44 -0
- sage/structure/coerce.pyx +2107 -0
- sage/structure/coerce_actions.cpython-311-darwin.so +0 -0
- sage/structure/coerce_actions.pxd +27 -0
- sage/structure/coerce_actions.pyx +988 -0
- sage/structure/coerce_dict.cpython-311-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-311-darwin.so +0 -0
- sage/structure/coerce_maps.pxd +28 -0
- sage/structure/coerce_maps.pyx +718 -0
- sage/structure/debug_options.cpython-311-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-311-darwin.so +0 -0
- sage/structure/element.pxd +272 -0
- sage/structure/element.pyx +4772 -0
- sage/structure/element_wrapper.cpython-311-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-311-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-311-darwin.so +0 -0
- sage/structure/list_clone.pxd +65 -0
- sage/structure/list_clone.pyx +1867 -0
- sage/structure/list_clone_demo.cpython-311-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-311-darwin.so +0 -0
- sage/structure/list_clone_timings_cy.pyx +86 -0
- sage/structure/mutability.cpython-311-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-311-darwin.so +0 -0
- sage/structure/parent.pxd +112 -0
- sage/structure/parent.pyx +3093 -0
- sage/structure/parent_base.cpython-311-darwin.so +0 -0
- sage/structure/parent_base.pxd +13 -0
- sage/structure/parent_base.pyx +44 -0
- sage/structure/parent_gens.cpython-311-darwin.so +0 -0
- sage/structure/parent_gens.pxd +22 -0
- sage/structure/parent_gens.pyx +377 -0
- sage/structure/parent_old.cpython-311-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-311-darwin.so +0 -0
- sage/structure/richcmp.pxd +213 -0
- sage/structure/richcmp.pyx +495 -0
- sage/structure/sage_object.cpython-311-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
sage/cpython/atexit.pyx
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-objects
|
|
2
|
+
|
|
3
|
+
"""Utilities for interfacing with the standard library's atexit module."""
|
|
4
|
+
|
|
5
|
+
# ****************************************************************************
|
|
6
|
+
# Copyright (C) 2017 Erik M. Bray <erik.bray@lri.fr>
|
|
7
|
+
#
|
|
8
|
+
# This program is free software: you can redistribute it and/or modify
|
|
9
|
+
# it under the terms of the GNU General Public License as published by
|
|
10
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
11
|
+
# (at your option) any later version.
|
|
12
|
+
# https://www.gnu.org/licenses/
|
|
13
|
+
# ****************************************************************************
|
|
14
|
+
|
|
15
|
+
import atexit
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
__all__ = ['restore_atexit']
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
cdef class restore_atexit:
|
|
22
|
+
r"""
|
|
23
|
+
Context manager that restores the state of the atexit module to its
|
|
24
|
+
previous state when exiting the context.
|
|
25
|
+
|
|
26
|
+
INPUT:
|
|
27
|
+
|
|
28
|
+
- ``run`` -- boolean (default: ``False``); if ``True``, when exiting the
|
|
29
|
+
context (but before restoring the old exit functions), run all
|
|
30
|
+
atexit functions which were added inside the context
|
|
31
|
+
|
|
32
|
+
- ``clear`` -- boolean (default: equal to ``run``); if ``True``, clear
|
|
33
|
+
already registered atexit handlers upon entering the context
|
|
34
|
+
|
|
35
|
+
.. WARNING::
|
|
36
|
+
|
|
37
|
+
The combination ``run=True`` and ``clear=False`` will cause
|
|
38
|
+
already-registered exit functions to be run twice: once when
|
|
39
|
+
exiting the context and again when exiting Python.
|
|
40
|
+
|
|
41
|
+
EXAMPLES:
|
|
42
|
+
|
|
43
|
+
For this example we will wrap the entire example with
|
|
44
|
+
``restore_atexit(clear=True)`` so as to start with a fresh atexit
|
|
45
|
+
module state for the sake of the example.
|
|
46
|
+
|
|
47
|
+
Note that the function ``atexit._run_exitfuncs()`` runs all registered
|
|
48
|
+
handlers, and then clears the list of handlers, so we can use it to test
|
|
49
|
+
manipulation of the ``atexit`` state::
|
|
50
|
+
|
|
51
|
+
sage: import atexit
|
|
52
|
+
sage: from sage.cpython.atexit import restore_atexit
|
|
53
|
+
sage: def handler(*args, **kwargs):
|
|
54
|
+
....: import sys
|
|
55
|
+
....: # see https://github.com/sagemath/sage/issues/25270#comment:56
|
|
56
|
+
....: sys.stdout.write(str((args, kwargs)))
|
|
57
|
+
....: sys.stdout.write('\n')
|
|
58
|
+
sage: atexit.register(handler, 1, 2, c=3)
|
|
59
|
+
<function handler at 0x...>
|
|
60
|
+
sage: atexit.register(handler, 4, 5, d=6)
|
|
61
|
+
<function handler at 0x...>
|
|
62
|
+
sage: with restore_atexit(clear=True):
|
|
63
|
+
....: atexit._run_exitfuncs() # Should be none registered
|
|
64
|
+
....: atexit.register(handler, 1, 2, c=3)
|
|
65
|
+
....: with restore_atexit():
|
|
66
|
+
....: atexit._run_exitfuncs() # Run just registered handler
|
|
67
|
+
....: atexit._run_exitfuncs() # Handler should be run again
|
|
68
|
+
<function handler at 0x...>
|
|
69
|
+
((1, 2), {'c': 3})
|
|
70
|
+
((1, 2), {'c': 3})
|
|
71
|
+
|
|
72
|
+
We test the ``run`` option::
|
|
73
|
+
|
|
74
|
+
sage: with restore_atexit(run=True):
|
|
75
|
+
....: # this handler is run when exiting the context
|
|
76
|
+
....: _ = atexit.register(handler, 7, 8, e=9)
|
|
77
|
+
((7, 8), {'e': 9})
|
|
78
|
+
sage: with restore_atexit(clear=False, run=True):
|
|
79
|
+
....: # original handlers are run when exiting the context
|
|
80
|
+
....: pass
|
|
81
|
+
((4, 5), {'d': 6})
|
|
82
|
+
((1, 2), {'c': 3})
|
|
83
|
+
|
|
84
|
+
The original handlers are still in place::
|
|
85
|
+
|
|
86
|
+
sage: atexit._run_exitfuncs()
|
|
87
|
+
((4, 5), {'d': 6})
|
|
88
|
+
((1, 2), {'c': 3})
|
|
89
|
+
|
|
90
|
+
TESTS::
|
|
91
|
+
|
|
92
|
+
sage: from sage.cpython.atexit import (_get_exithandlers,
|
|
93
|
+
....: _clear_exithandlers)
|
|
94
|
+
sage: atexit.register(handler, 1, 2, c=3)
|
|
95
|
+
<function handler at 0x...>
|
|
96
|
+
sage: atexit.register(handler, 4, 5, d=6)
|
|
97
|
+
<function handler at 0x...>
|
|
98
|
+
sage: print("Initial exit handlers:\n{}".format(_get_exithandlers()))
|
|
99
|
+
Initial exit handlers:
|
|
100
|
+
[(<function handler at 0x...>, (1, 2), {'c': 3}),
|
|
101
|
+
(<function handler at 0x...>, (4, 5), {'d': 6})]
|
|
102
|
+
|
|
103
|
+
sage: with restore_atexit():
|
|
104
|
+
....: pass
|
|
105
|
+
sage: print("After restore_atexit:\n{}".format(_get_exithandlers()))
|
|
106
|
+
After restore_atexit:
|
|
107
|
+
[(<function handler at 0x...>, (1, 2), {'c': 3}),
|
|
108
|
+
(<function handler at 0x...>, (4, 5), {'d': 6})]
|
|
109
|
+
|
|
110
|
+
sage: with restore_atexit(clear=True):
|
|
111
|
+
....: print("Exit handlers in context manager: {}".format(
|
|
112
|
+
....: _get_exithandlers()))
|
|
113
|
+
Exit handlers in context manager: []
|
|
114
|
+
|
|
115
|
+
sage: print("After restore_atexit with clear=True:\n{}".format(
|
|
116
|
+
....: _get_exithandlers()))
|
|
117
|
+
After restore_atexit with clear=True:
|
|
118
|
+
[(<function handler at 0x...>, (1, 2), {'c': 3}),
|
|
119
|
+
(<function handler at 0x...>, (4, 5), {'d': 6})]
|
|
120
|
+
sage: _clear_exithandlers()
|
|
121
|
+
sage: _get_exithandlers()
|
|
122
|
+
[]
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
cdef list _exithandlers
|
|
126
|
+
cdef bint _clear, _run
|
|
127
|
+
|
|
128
|
+
def __init__(self, *, run=False, clear=None):
|
|
129
|
+
self._clear = self._run = run
|
|
130
|
+
if clear is not None:
|
|
131
|
+
self._clear = clear
|
|
132
|
+
self._exithandlers = None
|
|
133
|
+
|
|
134
|
+
def __enter__(self):
|
|
135
|
+
self._exithandlers = _get_exithandlers()
|
|
136
|
+
if self._clear:
|
|
137
|
+
_clear_exithandlers()
|
|
138
|
+
|
|
139
|
+
return self
|
|
140
|
+
|
|
141
|
+
def __exit__(self, *exc):
|
|
142
|
+
if self._run:
|
|
143
|
+
atexit._run_exitfuncs()
|
|
144
|
+
_set_exithandlers(self._exithandlers)
|
|
145
|
+
|
|
146
|
+
from cpython.ref cimport PyObject
|
|
147
|
+
import sys
|
|
148
|
+
|
|
149
|
+
# Implement a uniform interface for getting atexit callbacks
|
|
150
|
+
cdef extern from *:
|
|
151
|
+
"""
|
|
152
|
+
#ifndef Py_BUILD_CORE
|
|
153
|
+
#define Py_BUILD_CORE
|
|
154
|
+
#endif
|
|
155
|
+
#undef _PyGC_FINALIZED
|
|
156
|
+
#include "internal/pycore_interp.h"
|
|
157
|
+
#include "internal/pycore_pystate.h"
|
|
158
|
+
|
|
159
|
+
// Always define this struct for Cython's use
|
|
160
|
+
typedef struct {
|
|
161
|
+
PyObject *func;
|
|
162
|
+
PyObject *args;
|
|
163
|
+
PyObject *kwargs;
|
|
164
|
+
} atexit_callback_struct;
|
|
165
|
+
|
|
166
|
+
#if PY_VERSION_HEX >= 0x030e0000
|
|
167
|
+
// Python 3.14+: atexit uses a PyList stored in state->callbacks
|
|
168
|
+
// Note: In Python 3.14 the atexit_state struct changed - callbacks is now a PyObject* (PyList)
|
|
169
|
+
|
|
170
|
+
static PyObject* get_atexit_callbacks_list(PyObject *self) {
|
|
171
|
+
PyInterpreterState *interp = _PyInterpreterState_GET();
|
|
172
|
+
// Access the callbacks list directly from the interpreter state
|
|
173
|
+
// We return a new reference because Cython expects an owned reference
|
|
174
|
+
PyObject *callbacks = interp->atexit.callbacks;
|
|
175
|
+
Py_XINCREF(callbacks);
|
|
176
|
+
return callbacks;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Dummy function for Python 3.14+ (never called)
|
|
180
|
+
static atexit_callback_struct** get_atexit_callbacks_array(PyObject *self) {
|
|
181
|
+
PyErr_SetString(PyExc_RuntimeError, "Python >= 3.14 has no atexit arrays");
|
|
182
|
+
return NULL;
|
|
183
|
+
}
|
|
184
|
+
#else
|
|
185
|
+
// Python < 3.14: atexit uses C array
|
|
186
|
+
static atexit_callback_struct** get_atexit_callbacks_array(PyObject *self) {
|
|
187
|
+
PyInterpreterState *interp = _PyInterpreterState_GET();
|
|
188
|
+
struct atexit_state state = interp->atexit;
|
|
189
|
+
// Cast from atexit_callback** to our struct type
|
|
190
|
+
return (atexit_callback_struct**)state.callbacks;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Dummy function for Python < 3.14 (never called)
|
|
194
|
+
static PyObject* get_atexit_callbacks_list(PyObject *self) {
|
|
195
|
+
PyErr_SetString(PyExc_RuntimeError, "Python < 3.14 has no atexit lists");
|
|
196
|
+
return NULL;
|
|
197
|
+
}
|
|
198
|
+
#endif
|
|
199
|
+
"""
|
|
200
|
+
# Declare both functions - they exist in all Python versions (one is dummy)
|
|
201
|
+
object get_atexit_callbacks_list(object module)
|
|
202
|
+
|
|
203
|
+
ctypedef struct atexit_callback_struct:
|
|
204
|
+
PyObject* func
|
|
205
|
+
PyObject* args
|
|
206
|
+
PyObject* kwargs
|
|
207
|
+
atexit_callback_struct** get_atexit_callbacks_array(object module) except NULL
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _get_exithandlers():
|
|
211
|
+
"""Return list of exit handlers registered with the atexit module."""
|
|
212
|
+
cdef list exithandlers = []
|
|
213
|
+
cdef atexit_callback_struct ** callbacks
|
|
214
|
+
cdef atexit_callback_struct callback
|
|
215
|
+
cdef int idx
|
|
216
|
+
cdef object kwargs
|
|
217
|
+
|
|
218
|
+
# Python 3.14+ uses a PyList directly
|
|
219
|
+
if sys.version_info >= (3, 14):
|
|
220
|
+
callbacks_list = get_atexit_callbacks_list(atexit)
|
|
221
|
+
if callbacks_list is None:
|
|
222
|
+
return exithandlers
|
|
223
|
+
# callbacks is a list of tuples: [(func, args, kwargs), ...]
|
|
224
|
+
# Normalize kwargs to ensure it's always a dict (not None)
|
|
225
|
+
# Note: In Python 3.14+, atexit stores callbacks in LIFO order
|
|
226
|
+
# (most recently registered first), but we return them in FIFO
|
|
227
|
+
# order (registration order) for consistency with earlier versions
|
|
228
|
+
for item in reversed(callbacks_list):
|
|
229
|
+
func, args, kwargs = item
|
|
230
|
+
if kwargs is None:
|
|
231
|
+
kwargs = {}
|
|
232
|
+
exithandlers.append((func, args, kwargs))
|
|
233
|
+
else:
|
|
234
|
+
# Python < 3.14 uses C array
|
|
235
|
+
callbacks = get_atexit_callbacks_array(atexit)
|
|
236
|
+
for idx in range(atexit._ncallbacks()):
|
|
237
|
+
callback = callbacks[idx][0]
|
|
238
|
+
if callback.kwargs:
|
|
239
|
+
kwargs = <object>callback.kwargs
|
|
240
|
+
else:
|
|
241
|
+
kwargs = {}
|
|
242
|
+
exithandlers.append((<object>callback.func,
|
|
243
|
+
<object>callback.args,
|
|
244
|
+
kwargs))
|
|
245
|
+
return exithandlers
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def _set_exithandlers(exithandlers):
|
|
249
|
+
"""
|
|
250
|
+
Replace the list of exit handlers registered with the atexit module
|
|
251
|
+
with a new list.
|
|
252
|
+
"""
|
|
253
|
+
|
|
254
|
+
# Clear the existing list
|
|
255
|
+
atexit._clear()
|
|
256
|
+
|
|
257
|
+
# We could do this more efficiently by directly rebuilding the array
|
|
258
|
+
# of atexit_callbacks, but this is much simpler
|
|
259
|
+
# Note: exithandlers is in registration order (FIFO).
|
|
260
|
+
# In Python 3.14+, atexit.register prepends to the list (LIFO),
|
|
261
|
+
# so registering in forward order gives us the correct execution order.
|
|
262
|
+
for callback in exithandlers:
|
|
263
|
+
atexit.register(callback[0], *callback[1], **callback[2])
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _clear_exithandlers():
|
|
267
|
+
"""Clear the atexit module of all registered exit handlers."""
|
|
268
|
+
|
|
269
|
+
atexit._clear()
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/* sage_setup: distribution = sagemath-objects
|
|
2
|
+
*/
|
|
3
|
+
/*****************************************************************************
|
|
4
|
+
* Copyright (C) 2015 Jeroen Demeyer <jdemeyer@cage.ugent.be>
|
|
5
|
+
*
|
|
6
|
+
* This program is free software: you can redistribute it and/or modify
|
|
7
|
+
* it under the terms of the GNU General Public License as published by
|
|
8
|
+
* the Free Software Foundation, either version 2 of the License, or
|
|
9
|
+
* (at your option) any later version.
|
|
10
|
+
* https://www.gnu.org/licenses/
|
|
11
|
+
*****************************************************************************/
|
|
12
|
+
|
|
13
|
+
/* Tuple (None, None, None), initialized as needed */
|
|
14
|
+
static PyObject* NoneNoneNone;
|
|
15
|
+
|
|
16
|
+
/* All args flags of a PyMethod */
|
|
17
|
+
#define METH_ALLARGS (METH_VARARGS|METH_KEYWORDS|METH_NOARGS|METH_O)
|
|
18
|
+
|
|
19
|
+
/* Given an unbound method "desc" (this is not checked!) with only a
|
|
20
|
+
* single "self" argument, call "desc(self)" without checking "self".
|
|
21
|
+
* This can in particular be used to call any method as class or
|
|
22
|
+
* static method. */
|
|
23
|
+
static CYTHON_INLINE PyObject* PyMethodDescr_CallSelf(PyMethodDescrObject* desc, PyObject* self)
|
|
24
|
+
{
|
|
25
|
+
PyMethodDef* meth = desc->d_method;
|
|
26
|
+
|
|
27
|
+
/* This must be a METH_NOARGS method */
|
|
28
|
+
if (meth == NULL || (meth->ml_flags & METH_ALLARGS) != METH_NOARGS)
|
|
29
|
+
{
|
|
30
|
+
PyErr_SetString(PyExc_TypeError,
|
|
31
|
+
"PyMethodDescr_CallSelf requires a method without arguments");
|
|
32
|
+
return NULL;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return meth->ml_meth(self, NULL);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/*
|
|
39
|
+
* This function calls PyType_Ready(t) and then calls
|
|
40
|
+
* t.__getmetaclass__(None) (if that method exists) which should
|
|
41
|
+
* return the metaclass for t. Then type(t) is set to this metaclass
|
|
42
|
+
* and metaclass.__init__(t, None, None, None) is called.
|
|
43
|
+
*/
|
|
44
|
+
static CYTHON_INLINE int Sage_PyType_Ready(PyTypeObject* t)
|
|
45
|
+
{
|
|
46
|
+
int r = PyType_Ready(t);
|
|
47
|
+
if (r < 0)
|
|
48
|
+
return r;
|
|
49
|
+
|
|
50
|
+
// Cython 3 sets Py_TPFLAGS_HEAPTYPE before calling PyType_Ready,
|
|
51
|
+
// and resets just after the call. We need to reset it earlier,
|
|
52
|
+
// since otherwise the call to metaclass.__init__ below may have
|
|
53
|
+
// illegal memory accesses.
|
|
54
|
+
// See also:
|
|
55
|
+
// https://github.com/cython/cython/issues/3603
|
|
56
|
+
t->tp_flags &= ~Py_TPFLAGS_HEAPTYPE;
|
|
57
|
+
|
|
58
|
+
/* Set or get metaclass (the type of t) */
|
|
59
|
+
PyTypeObject* metaclass;
|
|
60
|
+
|
|
61
|
+
PyObject* getmetaclass;
|
|
62
|
+
getmetaclass = PyObject_GetAttrString((PyObject*)t, "__getmetaclass__");
|
|
63
|
+
if (getmetaclass)
|
|
64
|
+
{
|
|
65
|
+
/* Call getmetaclass with self=None */
|
|
66
|
+
metaclass = (PyTypeObject*)(PyMethodDescr_CallSelf((PyMethodDescrObject*)getmetaclass, Py_None));
|
|
67
|
+
Py_DECREF(getmetaclass);
|
|
68
|
+
if (!metaclass)
|
|
69
|
+
return -1;
|
|
70
|
+
|
|
71
|
+
if (!PyType_Check(metaclass))
|
|
72
|
+
{
|
|
73
|
+
PyErr_SetString(PyExc_TypeError,
|
|
74
|
+
"__getmetaclass__ did not return a type");
|
|
75
|
+
return -1;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* Now, set t.__class__ to metaclass */
|
|
79
|
+
Py_SET_TYPE(t, metaclass);
|
|
80
|
+
PyType_Modified(t);
|
|
81
|
+
}
|
|
82
|
+
else
|
|
83
|
+
{
|
|
84
|
+
/* No __getmetaclass__ method: read metaclass... */
|
|
85
|
+
PyErr_Clear();
|
|
86
|
+
metaclass = Py_TYPE(t);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* Now call metaclass.__init__(t, None, None, None) unless
|
|
90
|
+
* we would be calling type.__init__ */
|
|
91
|
+
initproc init = metaclass->tp_init;
|
|
92
|
+
if (init == NULL || init == PyType_Type.tp_init)
|
|
93
|
+
return 0;
|
|
94
|
+
|
|
95
|
+
/* Safety check: since we didn't call tp_new of metaclass,
|
|
96
|
+
* we cannot safely call tp_init if the size of the structure
|
|
97
|
+
* differs. */
|
|
98
|
+
if (metaclass->tp_basicsize != PyType_Type.tp_basicsize)
|
|
99
|
+
{
|
|
100
|
+
PyErr_SetString(PyExc_TypeError,
|
|
101
|
+
"metaclass is not compatible with 'type' (you cannot use cdef attributes in Cython metaclasses)");
|
|
102
|
+
return -1;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* Initialize a tuple (None, None, None) */
|
|
106
|
+
if (!NoneNoneNone)
|
|
107
|
+
{
|
|
108
|
+
NoneNoneNone = PyTuple_Pack(3, Py_None, Py_None, Py_None);
|
|
109
|
+
if (!NoneNoneNone) return -1;
|
|
110
|
+
}
|
|
111
|
+
return init((PyObject*)t, NoneNoneNone, NULL);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
/* Use the above function in Cython code instead of the default
|
|
116
|
+
* PyType_Ready() function */
|
|
117
|
+
#define PyType_Ready(t) Sage_PyType_Ready(t)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-objects
|
|
2
|
+
"""
|
|
3
|
+
Metaclasses for Cython extension types
|
|
4
|
+
|
|
5
|
+
Cython does not support metaclasses, but this module can be used to
|
|
6
|
+
implement metaclasses for extension types.
|
|
7
|
+
|
|
8
|
+
.. WARNING::
|
|
9
|
+
|
|
10
|
+
This module has many caveats and you can easily get segfaults if you
|
|
11
|
+
make a mistake. It relies on undocumented Python and Cython
|
|
12
|
+
behaviour, so things might break in future versions.
|
|
13
|
+
|
|
14
|
+
How to use
|
|
15
|
+
==========
|
|
16
|
+
|
|
17
|
+
To enable this metaclass mechanism, you need to put
|
|
18
|
+
``cimport sage.cpython.cython_metaclass`` in your module (in the ``.pxd``
|
|
19
|
+
file if you are using one).
|
|
20
|
+
|
|
21
|
+
In the extension type (a.k.a. ``cdef class``) for which you want to
|
|
22
|
+
define a metaclass, define a method ``__getmetaclass__`` with a single
|
|
23
|
+
unused argument, and turn off the Cython directive
|
|
24
|
+
``always_allow_keywords``. This method should return a type to be used as
|
|
25
|
+
metaclass:
|
|
26
|
+
|
|
27
|
+
.. code-block:: cython
|
|
28
|
+
|
|
29
|
+
cimport cython
|
|
30
|
+
cimport sage.cpython.cython_metaclass
|
|
31
|
+
cdef class MyCustomType():
|
|
32
|
+
@cython.always_allow_keywords(False)
|
|
33
|
+
def __getmetaclass__(_):
|
|
34
|
+
from foo import MyMetaclass
|
|
35
|
+
return MyMetaclass
|
|
36
|
+
|
|
37
|
+
.. WARNING::
|
|
38
|
+
|
|
39
|
+
``__getmetaclass__`` must be defined as an ordinary method taking a
|
|
40
|
+
single argument, but this argument should not be used in the
|
|
41
|
+
method (it will be ``None``).
|
|
42
|
+
|
|
43
|
+
When a type ``cls`` is being constructed with metaclass ``meta``,
|
|
44
|
+
then ``meta.__init__(cls, None, None, None)`` is called from Cython.
|
|
45
|
+
In Python, this would be ``meta.__init__(cls, name, bases, dict)``.
|
|
46
|
+
|
|
47
|
+
.. WARNING::
|
|
48
|
+
|
|
49
|
+
The ``__getmetaclass__`` method is called while the type is being
|
|
50
|
+
created during the import of the module. Therefore,
|
|
51
|
+
``__getmetaclass__`` should not refer to any global objects,
|
|
52
|
+
including the type being created or other types defined or imported
|
|
53
|
+
in the module (unless you are very careful). Note that non-imported
|
|
54
|
+
``cdef`` functions are not Python objects, so those are safe to call.
|
|
55
|
+
|
|
56
|
+
The same warning applies to the ``__init__`` method of the
|
|
57
|
+
metaclass.
|
|
58
|
+
|
|
59
|
+
.. WARNING::
|
|
60
|
+
|
|
61
|
+
The ``__new__`` method of the metaclass (including the ``__cinit__``
|
|
62
|
+
method for Cython extension types) is never called if you're using
|
|
63
|
+
this from Cython. In particular, the metaclass cannot have any
|
|
64
|
+
attributes or virtual methods.
|
|
65
|
+
|
|
66
|
+
EXAMPLES::
|
|
67
|
+
|
|
68
|
+
sage: cython( # needs sage.misc.cython
|
|
69
|
+
....: '''
|
|
70
|
+
....: cimport cython
|
|
71
|
+
....: cimport sage.cpython.cython_metaclass
|
|
72
|
+
....: cdef class MyCustomType():
|
|
73
|
+
....: @cython.always_allow_keywords(False)
|
|
74
|
+
....: def __getmetaclass__(_):
|
|
75
|
+
....: class MyMetaclass(type):
|
|
76
|
+
....: def __init__(*args):
|
|
77
|
+
....: print("Calling MyMetaclass.__init__{}".format(args))
|
|
78
|
+
....: return MyMetaclass
|
|
79
|
+
....:
|
|
80
|
+
....: cdef class MyDerivedType(MyCustomType):
|
|
81
|
+
....: pass
|
|
82
|
+
....: ''')
|
|
83
|
+
Calling MyMetaclass.__init__(<class '...MyCustomType'>, None, None, None)
|
|
84
|
+
Calling MyMetaclass.__init__(<class '...MyDerivedType'>, None, None, None)
|
|
85
|
+
sage: MyCustomType.__class__ # needs sage.misc.cython
|
|
86
|
+
<class '...MyMetaclass'>
|
|
87
|
+
sage: class MyPythonType(MyDerivedType): # needs sage.misc.cython
|
|
88
|
+
....: pass
|
|
89
|
+
Calling MyMetaclass.__init__(<class '...MyPythonType'>, 'MyPythonType', (<class '...MyDerivedType'>,), {...})
|
|
90
|
+
|
|
91
|
+
Implementation
|
|
92
|
+
==============
|
|
93
|
+
|
|
94
|
+
All this is implemented by defining
|
|
95
|
+
|
|
96
|
+
.. code-block:: c
|
|
97
|
+
|
|
98
|
+
#define PyTypeReady(t) Sage_PyType_Ready(t)
|
|
99
|
+
|
|
100
|
+
and then implementing the function ``Sage_PyType_Ready(t)`` which first
|
|
101
|
+
calls ``PyType_Ready(t)`` and then handles the metaclass stuff.
|
|
102
|
+
|
|
103
|
+
TESTS:
|
|
104
|
+
|
|
105
|
+
Check that a proper exception is raised if ``__getmetaclass__``
|
|
106
|
+
returns a non-type::
|
|
107
|
+
|
|
108
|
+
sage: cython( # needs sage.misc.cython
|
|
109
|
+
....: '''
|
|
110
|
+
....: cimport cython
|
|
111
|
+
....: cimport sage.cpython.cython_metaclass
|
|
112
|
+
....: cdef class MyCustomType():
|
|
113
|
+
....: @cython.always_allow_keywords(False)
|
|
114
|
+
....: def __getmetaclass__(_):
|
|
115
|
+
....: return 2
|
|
116
|
+
....: ''')
|
|
117
|
+
Traceback (most recent call last):
|
|
118
|
+
...
|
|
119
|
+
TypeError: __getmetaclass__ did not return a type
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
# ****************************************************************************
|
|
123
|
+
# Copyright (C) 2015 Jeroen Demeyer <jdemeyer@cage.ugent.be>
|
|
124
|
+
#
|
|
125
|
+
# This program is free software: you can redistribute it and/or modify
|
|
126
|
+
# it under the terms of the GNU General Public License as published by
|
|
127
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
128
|
+
# (at your option) any later version.
|
|
129
|
+
# https://www.gnu.org/licenses/
|
|
130
|
+
# ****************************************************************************
|
|
Binary file
|