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
|
Binary file
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-objects
|
|
2
|
+
"""
|
|
3
|
+
Debug options for the :mod:`sage.structure` modules
|
|
4
|
+
|
|
5
|
+
EXAMPLES::
|
|
6
|
+
|
|
7
|
+
sage: from sage.structure.debug_options import debug
|
|
8
|
+
sage: debug.unique_parent_warnings
|
|
9
|
+
False
|
|
10
|
+
sage: debug.refine_category_hash_check
|
|
11
|
+
True
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
#*****************************************************************************
|
|
15
|
+
# Copyright (C) 2013 Robert Bradshaw <robertwb@gmail.com>
|
|
16
|
+
# William Stein <wstein@gmail.com>
|
|
17
|
+
# Volker Braun <vbraun.name@gmail.com>
|
|
18
|
+
#
|
|
19
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
20
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
21
|
+
# the License, or (at your option) any later version.
|
|
22
|
+
# http://www.gnu.org/licenses/
|
|
23
|
+
#*****************************************************************************
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
cdef class DebugOptions_class:
|
|
27
|
+
def __cinit__(self):
|
|
28
|
+
"""
|
|
29
|
+
Initializer for the debug options.
|
|
30
|
+
|
|
31
|
+
TESTS::
|
|
32
|
+
|
|
33
|
+
sage: from sage.structure.debug_options import debug
|
|
34
|
+
sage: type(debug)
|
|
35
|
+
<... 'sage.structure.debug_options.DebugOptions_class'>
|
|
36
|
+
"""
|
|
37
|
+
self.unique_parent_warnings = False
|
|
38
|
+
# This one will be enabled during doctests
|
|
39
|
+
self.refine_category_hash_check = False
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
cdef DebugOptions_class debug = DebugOptions_class()
|
|
43
|
+
|
|
44
|
+
# Since "debug" is declared with cdef, it can only be cimported at
|
|
45
|
+
# the Cython level, not imported in plain Python. So we add it to the
|
|
46
|
+
# globals manually. However this will make the variable out of sync
|
|
47
|
+
# if some user modifies the object, which is inevitable.
|
|
48
|
+
# See https://github.com/cython/cython/issues/3959#issuecomment-753455240
|
|
49
|
+
# and https://github.com/cython/cython/issues/656
|
|
50
|
+
# Note that ``_this_module`` could not be ``globals()``
|
|
51
|
+
# because Sage is compiled with the old_style_globals option.
|
|
52
|
+
import sage.structure.debug_options as _this_module
|
|
53
|
+
_this_module.debug = debug
|
|
54
|
+
del _this_module
|
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-objects
|
|
2
|
+
"""
|
|
3
|
+
Dynamic classes
|
|
4
|
+
|
|
5
|
+
.. RUBRIC:: Why dynamic classes?
|
|
6
|
+
|
|
7
|
+
The short answer:
|
|
8
|
+
|
|
9
|
+
- Multiple inheritance is a powerful tool for constructing new classes
|
|
10
|
+
by combining preexisting building blocks.
|
|
11
|
+
- There is a combinatorial explosion in the number of potentially
|
|
12
|
+
useful classes that can be produced this way.
|
|
13
|
+
- The implementation of standard mathematical constructions calls for
|
|
14
|
+
producing such combinations automatically.
|
|
15
|
+
- Dynamic classes, i.e. classes created on the fly by the Python
|
|
16
|
+
interpreter, are a natural mean to achieve this.
|
|
17
|
+
|
|
18
|
+
The long answer:
|
|
19
|
+
|
|
20
|
+
Say we want to construct a new class ``MyPermutation`` for
|
|
21
|
+
permutations in a given set `S` (in Sage, `S` will be modelled by a
|
|
22
|
+
parent, but we won't discuss this point here). First, we have to
|
|
23
|
+
choose a data structure for the permutations, typically among the
|
|
24
|
+
following:
|
|
25
|
+
|
|
26
|
+
- Stored by cycle type
|
|
27
|
+
- Stored by code
|
|
28
|
+
- Stored in list notation
|
|
29
|
+
- C arrays of short ints (for small permutations)
|
|
30
|
+
- python lists of ints (for huge permutations)
|
|
31
|
+
- ...
|
|
32
|
+
- Stored by reduced word
|
|
33
|
+
- Stored as a function
|
|
34
|
+
- ...
|
|
35
|
+
|
|
36
|
+
Luckily, the Sage library provides (or will provide) classes
|
|
37
|
+
implementing each of those data structures. Those classes all share a
|
|
38
|
+
common interface (or possibly a common abstract base class). So we can
|
|
39
|
+
just derive our class from the chosen one::
|
|
40
|
+
|
|
41
|
+
class MyPermutation(PermutationCycleType):
|
|
42
|
+
...
|
|
43
|
+
|
|
44
|
+
Then we may want to further choose a specific memory behavior (unique
|
|
45
|
+
representation, copy-on-write) which (hopefully) can again be achieved
|
|
46
|
+
by inheritance::
|
|
47
|
+
|
|
48
|
+
class MyPermutation(UniqueRepresentation, PermutationCycleType):
|
|
49
|
+
...
|
|
50
|
+
|
|
51
|
+
Finally, we may want to endow the permutations in `S` with further
|
|
52
|
+
operations coming from the (algebraic) structure of `S`:
|
|
53
|
+
|
|
54
|
+
- group operations
|
|
55
|
+
- or just monoid operations (for a subset of permutations not stable by inverse)
|
|
56
|
+
- poset operations (for left/right/Bruhat order)
|
|
57
|
+
- word operations (searching for substrings, patterns, ...)
|
|
58
|
+
|
|
59
|
+
Or any combination thereof. Now, our class typically looks like::
|
|
60
|
+
|
|
61
|
+
class MyPermutation(UniqueRepresentation, PermutationCycleType, PosetElement, GroupElement):
|
|
62
|
+
...
|
|
63
|
+
|
|
64
|
+
Note the combinatorial explosion in the potential number of classes
|
|
65
|
+
which can be created this way.
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
In practice, such classes will be used in mathematical constructions
|
|
69
|
+
like::
|
|
70
|
+
|
|
71
|
+
SymmetricGroup(5).subset(... TODO: find a good example in the context above ...)
|
|
72
|
+
|
|
73
|
+
In such a construction, the structure of the result, and therefore the
|
|
74
|
+
operations on its elements can only be determined at execution
|
|
75
|
+
time. Let us take another standard construction::
|
|
76
|
+
|
|
77
|
+
A = cartesian_product( B, C )
|
|
78
|
+
|
|
79
|
+
Depending on the structure of `B` and `C`, and possibly on further
|
|
80
|
+
options passed down by the user, `A` may be:
|
|
81
|
+
|
|
82
|
+
- an enumerated set
|
|
83
|
+
- a group
|
|
84
|
+
- an algebra
|
|
85
|
+
- a poset
|
|
86
|
+
- ...
|
|
87
|
+
|
|
88
|
+
Or any combination thereof.
|
|
89
|
+
|
|
90
|
+
Hardcoding classes for all potential combinations would be at best
|
|
91
|
+
tedious. Furthermore, this would require a cumbersome mechanism to
|
|
92
|
+
lookup the appropriate class depending on the desired combination.
|
|
93
|
+
|
|
94
|
+
Instead, one may use the ability of Python to create new classes
|
|
95
|
+
dynamically::
|
|
96
|
+
|
|
97
|
+
type("class name", tuple of base classes, dictionary of methods)
|
|
98
|
+
|
|
99
|
+
This paradigm is powerful, but there are some technicalities to
|
|
100
|
+
address. The purpose of this library is to standardize its use within
|
|
101
|
+
Sage, and in particular to ensure that the constructed classes are
|
|
102
|
+
reused whenever possible (unique representation), and can be pickled.
|
|
103
|
+
|
|
104
|
+
.. RUBRIC:: Combining dynamic classes and Cython classes
|
|
105
|
+
|
|
106
|
+
Cython classes cannot inherit from a dynamic class (there might be
|
|
107
|
+
some partial support for this in the future). On the other hand, such
|
|
108
|
+
an inheritance can be partially emulated using :meth:`__getattr__`. See
|
|
109
|
+
``sage.categories.examples.semigroups_cython`` for an example.
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
# ****************************************************************************
|
|
113
|
+
# Copyright (C) 2008-2009 Nicolas M. Thiery <nthiery at users.sf.net>
|
|
114
|
+
#
|
|
115
|
+
# This program is free software: you can redistribute it and/or modify
|
|
116
|
+
# it under the terms of the GNU General Public License as published by
|
|
117
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
118
|
+
# (at your option) any later version.
|
|
119
|
+
# https://www.gnu.org/licenses/
|
|
120
|
+
# ****************************************************************************
|
|
121
|
+
|
|
122
|
+
import copyreg
|
|
123
|
+
|
|
124
|
+
from sage.misc.cachefunc import weak_cached_function
|
|
125
|
+
from sage.misc.classcall_metaclass import ClasscallMetaclass
|
|
126
|
+
from sage.misc.inherit_comparison import InheritComparisonMetaclass, InheritComparisonClasscallMetaclass
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def dynamic_class(name, bases, cls=None, reduction=None, doccls=None,
|
|
130
|
+
prepend_cls_bases=True, cache=True):
|
|
131
|
+
r"""
|
|
132
|
+
INPUT:
|
|
133
|
+
|
|
134
|
+
- ``name`` -- string
|
|
135
|
+
- ``bases`` -- tuple of classes
|
|
136
|
+
- ``cls`` -- a class or ``None``
|
|
137
|
+
- ``reduction`` -- tuple or ``None``
|
|
138
|
+
- ``doccls`` -- a class or ``None``
|
|
139
|
+
- ``prepend_cls_bases`` -- boolean (default: ``True``)
|
|
140
|
+
- ``cache`` -- boolean or ``'ignore_reduction'`` (default: ``True``)
|
|
141
|
+
|
|
142
|
+
Constructs dynamically a new class ``C`` with name ``name``, and
|
|
143
|
+
bases ``bases``. If ``cls`` is provided, then its methods will be
|
|
144
|
+
inserted into ``C``, and its bases will be prepended to ``bases``
|
|
145
|
+
(unless ``prepend_cls_bases`` is ``False``).
|
|
146
|
+
|
|
147
|
+
The module, documentation and source introspection is taken from
|
|
148
|
+
``doccls``, or ``cls`` if ``doccls`` is ``None``, or ``bases[0]``
|
|
149
|
+
if both are ``None`` (therefore ``bases`` should be non empty if
|
|
150
|
+
``cls`` is ``None``).
|
|
151
|
+
|
|
152
|
+
The constructed class can safely be pickled (assuming the
|
|
153
|
+
arguments themselves can).
|
|
154
|
+
|
|
155
|
+
Unless ``cache`` is ``False``, the result is cached, ensuring unique
|
|
156
|
+
representation of dynamic classes.
|
|
157
|
+
|
|
158
|
+
See :mod:`sage.structure.dynamic_class` for a discussion of the
|
|
159
|
+
dynamic classes paradigm, and its relevance to Sage.
|
|
160
|
+
|
|
161
|
+
EXAMPLES:
|
|
162
|
+
|
|
163
|
+
To setup the stage, we create a class Foo with some methods,
|
|
164
|
+
cached methods, and lazy attributes, and a class Bar::
|
|
165
|
+
|
|
166
|
+
sage: from sage.misc.lazy_attribute import lazy_attribute
|
|
167
|
+
sage: from sage.misc.cachefunc import cached_function
|
|
168
|
+
sage: from sage.structure.dynamic_class import dynamic_class
|
|
169
|
+
sage: class Foo():
|
|
170
|
+
....: "The Foo class"
|
|
171
|
+
....: def __init__(self, x):
|
|
172
|
+
....: self._x = x
|
|
173
|
+
....: @cached_method
|
|
174
|
+
....: def f(self):
|
|
175
|
+
....: return self._x^2
|
|
176
|
+
....: def g(self):
|
|
177
|
+
....: return self._x^2
|
|
178
|
+
....: @lazy_attribute
|
|
179
|
+
....: def x(self):
|
|
180
|
+
....: return self._x
|
|
181
|
+
sage: class Bar:
|
|
182
|
+
....: def bar(self):
|
|
183
|
+
....: return self._x^2
|
|
184
|
+
|
|
185
|
+
We now create a class FooBar which is a copy of Foo, except that it
|
|
186
|
+
also inherits from Bar::
|
|
187
|
+
|
|
188
|
+
sage: FooBar = dynamic_class("FooBar", (Bar,), Foo)
|
|
189
|
+
sage: x = FooBar(3)
|
|
190
|
+
sage: x.f()
|
|
191
|
+
9
|
|
192
|
+
sage: x.f() is x.f()
|
|
193
|
+
True
|
|
194
|
+
sage: x.x
|
|
195
|
+
3
|
|
196
|
+
sage: x.bar()
|
|
197
|
+
9
|
|
198
|
+
sage: FooBar.__name__
|
|
199
|
+
'FooBar'
|
|
200
|
+
sage: FooBar.__module__
|
|
201
|
+
'__main__'
|
|
202
|
+
|
|
203
|
+
sage: Foo.__bases__
|
|
204
|
+
(<class 'object'>,)
|
|
205
|
+
sage: FooBar.__bases__
|
|
206
|
+
(<class '__main__.Bar'>,)
|
|
207
|
+
sage: Foo.mro()
|
|
208
|
+
[<class '__main__.Foo'>, <class 'object'>]
|
|
209
|
+
sage: FooBar.mro()
|
|
210
|
+
[<class '__main__.FooBar'>, <class '__main__.Bar'>, <class 'object'>]
|
|
211
|
+
|
|
212
|
+
If all the base classes have a zero ``__dictoffset__``, the dynamic
|
|
213
|
+
class also has a zero ``__dictoffset__``. This means that the
|
|
214
|
+
instances of the class don't have a ``__dict__``
|
|
215
|
+
(see :issue:`23435`)::
|
|
216
|
+
|
|
217
|
+
sage: dyn = dynamic_class("dyn", (Integer,))
|
|
218
|
+
sage: dyn.__dictoffset__
|
|
219
|
+
0
|
|
220
|
+
|
|
221
|
+
.. RUBRIC:: Pickling
|
|
222
|
+
|
|
223
|
+
Dynamic classes are pickled by construction. Namely, upon
|
|
224
|
+
unpickling, the class will be reconstructed by recalling
|
|
225
|
+
dynamic_class with the same arguments::
|
|
226
|
+
|
|
227
|
+
sage: type(FooBar).__reduce__(FooBar)
|
|
228
|
+
(<function dynamic_class at ...>, ('FooBar', (<class '__main__.Bar'>,), <class '__main__.Foo'>, None, None))
|
|
229
|
+
|
|
230
|
+
Technically, this is achieved by using a metaclass, since the
|
|
231
|
+
Python pickling protocol for classes is to pickle by name::
|
|
232
|
+
|
|
233
|
+
sage: type(FooBar)
|
|
234
|
+
<class 'sage.structure.dynamic_class.DynamicMetaclass'>
|
|
235
|
+
|
|
236
|
+
The following (meaningless) example illustrates how to customize
|
|
237
|
+
the result of the reduction::
|
|
238
|
+
|
|
239
|
+
sage: BarFoo = dynamic_class('BarFoo', (Foo,), Bar, reduction = (str, (3,)))
|
|
240
|
+
sage: type(BarFoo).__reduce__(BarFoo)
|
|
241
|
+
(<class 'str'>, (3,))
|
|
242
|
+
sage: loads(dumps(BarFoo))
|
|
243
|
+
'3'
|
|
244
|
+
|
|
245
|
+
.. RUBRIC:: Caching
|
|
246
|
+
|
|
247
|
+
By default, the built class is cached::
|
|
248
|
+
|
|
249
|
+
sage: dynamic_class("FooBar", (Bar,), Foo) is FooBar
|
|
250
|
+
True
|
|
251
|
+
sage: dynamic_class("FooBar", (Bar,), Foo, cache=True) is FooBar
|
|
252
|
+
True
|
|
253
|
+
|
|
254
|
+
and the result depends on the reduction::
|
|
255
|
+
|
|
256
|
+
sage: dynamic_class('BarFoo', (Foo,), Bar, reduction = (str, (3,))) is BarFoo
|
|
257
|
+
True
|
|
258
|
+
sage: dynamic_class('BarFoo', (Foo,), Bar, reduction = (str, (2,))) is BarFoo
|
|
259
|
+
False
|
|
260
|
+
|
|
261
|
+
With ``cache=False``, a new class is created each time::
|
|
262
|
+
|
|
263
|
+
sage: FooBar1 = dynamic_class("FooBar", (Bar,), Foo, cache=False); FooBar1
|
|
264
|
+
<class '__main__.FooBar'>
|
|
265
|
+
sage: FooBar2 = dynamic_class("FooBar", (Bar,), Foo, cache=False); FooBar2
|
|
266
|
+
<class '__main__.FooBar'>
|
|
267
|
+
sage: FooBar1 is FooBar
|
|
268
|
+
False
|
|
269
|
+
sage: FooBar2 is FooBar1
|
|
270
|
+
False
|
|
271
|
+
|
|
272
|
+
With ``cache="ignore_reduction"``, the class does not depend on
|
|
273
|
+
the reduction::
|
|
274
|
+
|
|
275
|
+
sage: BarFoo = dynamic_class('BarFoo', (Foo,), Bar, reduction = (str, (3,)), cache='ignore_reduction')
|
|
276
|
+
sage: dynamic_class('BarFoo', (Foo,), Bar, reduction = (str, (2,)), cache='ignore_reduction') is BarFoo
|
|
277
|
+
True
|
|
278
|
+
|
|
279
|
+
In particular, the reduction used is that provided upon creating the
|
|
280
|
+
first class::
|
|
281
|
+
|
|
282
|
+
sage: dynamic_class('BarFoo', (Foo,), Bar, reduction = (str, (2,)), cache='ignore_reduction')._reduction
|
|
283
|
+
(<class 'str'>, (3,))
|
|
284
|
+
|
|
285
|
+
.. WARNING::
|
|
286
|
+
|
|
287
|
+
The behaviour upon creating several dynamic classes from the
|
|
288
|
+
same data but with different values for ``cache`` option is
|
|
289
|
+
currently left unspecified. In other words, for a given
|
|
290
|
+
application, it is recommended to consistently use the same
|
|
291
|
+
value for that option.
|
|
292
|
+
|
|
293
|
+
TESTS::
|
|
294
|
+
|
|
295
|
+
sage: import __main__
|
|
296
|
+
sage: __main__.Foo = Foo
|
|
297
|
+
sage: __main__.Bar = Bar
|
|
298
|
+
sage: x = FooBar(3)
|
|
299
|
+
sage: x.__dict__ # Breaks without the __dict__ deletion in dynamic_class_internal
|
|
300
|
+
{'_x': 3}
|
|
301
|
+
|
|
302
|
+
sage: type(FooBar).__reduce__(FooBar)
|
|
303
|
+
(<function dynamic_class at ...>, ('FooBar', (<class '__main__.Bar'>,), <class '__main__.Foo'>, None, None))
|
|
304
|
+
sage: import pickle
|
|
305
|
+
sage: pickle.loads(pickle.dumps(FooBar)) == FooBar
|
|
306
|
+
True
|
|
307
|
+
|
|
308
|
+
We check that introspection works reasonably::
|
|
309
|
+
|
|
310
|
+
sage: sage.misc.sageinspect.sage_getdoc(FooBar)
|
|
311
|
+
'The Foo class\n'
|
|
312
|
+
|
|
313
|
+
Finally, we check that classes derived from UniqueRepresentation
|
|
314
|
+
are handled gracefully (despite them also using a metaclass)::
|
|
315
|
+
|
|
316
|
+
sage: FooUnique = dynamic_class("Foo", (Bar, UniqueRepresentation))
|
|
317
|
+
sage: loads(dumps(FooUnique)) is FooUnique
|
|
318
|
+
True
|
|
319
|
+
"""
|
|
320
|
+
bases = tuple(bases)
|
|
321
|
+
try:
|
|
322
|
+
name = str(name)
|
|
323
|
+
except UnicodeEncodeError:
|
|
324
|
+
pass
|
|
325
|
+
assert isinstance(name, str)
|
|
326
|
+
# assert(cls is None or issubtype(type(cls), type) or type(cls) is classobj)
|
|
327
|
+
if cache is True:
|
|
328
|
+
return dynamic_class_internal(name, bases, cls, reduction, doccls, prepend_cls_bases)
|
|
329
|
+
elif cache is False:
|
|
330
|
+
# bypass the cached method
|
|
331
|
+
return dynamic_class_internal.f(name, bases, cls, reduction, doccls, prepend_cls_bases)
|
|
332
|
+
else: # cache = "ignore_reduction"
|
|
333
|
+
result = dynamic_class_internal(name, bases, cls, False, doccls, prepend_cls_bases)
|
|
334
|
+
if result._reduction is False:
|
|
335
|
+
result._reduction = reduction
|
|
336
|
+
return result
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
@weak_cached_function
|
|
340
|
+
def dynamic_class_internal(name, bases, cls=None, reduction=None, doccls=None, prepend_cls_bases=True):
|
|
341
|
+
r"""
|
|
342
|
+
See sage.structure.dynamic_class.dynamic_class? for indirect doctests.
|
|
343
|
+
|
|
344
|
+
TESTS::
|
|
345
|
+
|
|
346
|
+
sage: Foo1 = sage.structure.dynamic_class.dynamic_class_internal("Foo", (object,))
|
|
347
|
+
sage: Foo2 = sage.structure.dynamic_class.dynamic_class_internal("Foo", (object,), doccls = sage.structure.dynamic_class.TestClass)
|
|
348
|
+
sage: Foo3 = sage.structure.dynamic_class.dynamic_class_internal("Foo", (object,), cls = sage.structure.dynamic_class.TestClass)
|
|
349
|
+
sage: all(Foo.__name__ == 'Foo' for Foo in [Foo1, Foo2, Foo3])
|
|
350
|
+
True
|
|
351
|
+
sage: all(Foo.__bases__ == (object,) for Foo in [Foo1, Foo2, Foo3])
|
|
352
|
+
True
|
|
353
|
+
sage: Foo1.__module__ == object.__module__
|
|
354
|
+
True
|
|
355
|
+
sage: Foo2.__module__ == sage.structure.dynamic_class.TestClass.__module__
|
|
356
|
+
True
|
|
357
|
+
sage: Foo3.__module__ == sage.structure.dynamic_class.TestClass.__module__
|
|
358
|
+
True
|
|
359
|
+
sage: Foo1.__doc__ == object.__doc__
|
|
360
|
+
True
|
|
361
|
+
sage: Foo2.__doc__ == sage.structure.dynamic_class.TestClass.__doc__
|
|
362
|
+
True
|
|
363
|
+
sage: Foo3.__doc__ == sage.structure.dynamic_class.TestClass.__doc__
|
|
364
|
+
True
|
|
365
|
+
|
|
366
|
+
We check that introspection works reasonably::
|
|
367
|
+
|
|
368
|
+
sage: from sage.misc.sageinspect import sage_getfile, sage_getsourcelines
|
|
369
|
+
sage: sage_getfile(Foo2)
|
|
370
|
+
'.../sage/structure/dynamic_class.py'
|
|
371
|
+
sage: sage_getfile(Foo3)
|
|
372
|
+
'.../sage/structure/dynamic_class.py'
|
|
373
|
+
sage: sage_getsourcelines(Foo2)
|
|
374
|
+
(['class TestClass:...'], ...)
|
|
375
|
+
sage: sage_getsourcelines(Foo3)
|
|
376
|
+
(['class TestClass:...'], ...)
|
|
377
|
+
sage: sage_getsourcelines(Foo2())
|
|
378
|
+
(['class TestClass:...'], ...)
|
|
379
|
+
sage: sage_getsourcelines(Foo3())
|
|
380
|
+
(['class TestClass:...'], ...)
|
|
381
|
+
sage: sage_getsourcelines(Foo3().bla)
|
|
382
|
+
([' def bla():...'], ...)
|
|
383
|
+
|
|
384
|
+
We check that :issue:`21895` has been resolved::
|
|
385
|
+
|
|
386
|
+
sage: C1 = sage.structure.dynamic_class.dynamic_class_internal("C1", (Morphism, UniqueRepresentation))
|
|
387
|
+
sage: type(C1)
|
|
388
|
+
<class 'sage.structure.dynamic_class.DynamicInheritComparisonClasscallMetaclass'>
|
|
389
|
+
sage: C2 = sage.structure.dynamic_class.dynamic_class_internal("C2", (UniqueRepresentation, Morphism))
|
|
390
|
+
sage: type(C2)
|
|
391
|
+
<class 'sage.structure.dynamic_class.DynamicInheritComparisonClasscallMetaclass'>
|
|
392
|
+
|
|
393
|
+
We check that :issue:`28392` has been resolved::
|
|
394
|
+
|
|
395
|
+
sage: class A:
|
|
396
|
+
....: pass
|
|
397
|
+
sage: Foo1 = sage.structure.dynamic_class.dynamic_class("Foo", (), A)
|
|
398
|
+
sage: "__weakref__" in Foo1.__dict__
|
|
399
|
+
False
|
|
400
|
+
sage: "__dict__" in Foo1.__dict__
|
|
401
|
+
False
|
|
402
|
+
"""
|
|
403
|
+
if reduction is None:
|
|
404
|
+
reduction = (dynamic_class, (name, bases, cls, reduction, doccls))
|
|
405
|
+
if cls is not None:
|
|
406
|
+
methods = dict(cls.__dict__)
|
|
407
|
+
# Anything else that should not be kept?
|
|
408
|
+
for key in ["__dict__", "__weakref__"]:
|
|
409
|
+
if key in methods:
|
|
410
|
+
del methods[key]
|
|
411
|
+
if prepend_cls_bases:
|
|
412
|
+
cls_bases = cls.__bases__
|
|
413
|
+
all_bases = set()
|
|
414
|
+
for base in bases:
|
|
415
|
+
if isinstance(base, type):
|
|
416
|
+
all_bases.update(base.mro())
|
|
417
|
+
cls_bases = tuple(b for b in cls_bases if b not in all_bases)
|
|
418
|
+
bases = cls_bases + bases
|
|
419
|
+
else:
|
|
420
|
+
methods = {}
|
|
421
|
+
if doccls is None:
|
|
422
|
+
if cls is not None:
|
|
423
|
+
doccls = cls
|
|
424
|
+
else:
|
|
425
|
+
assert bases != ()
|
|
426
|
+
doccls = bases[0]
|
|
427
|
+
methods['_reduction'] = reduction
|
|
428
|
+
# HACK: _doccls is a 1-element tuple to avoid __classget__
|
|
429
|
+
# or trouble with binding behaviour...
|
|
430
|
+
methods['_doccls'] = (doccls,)
|
|
431
|
+
methods['__doc__'] = doccls.__doc__
|
|
432
|
+
methods['__module__'] = doccls.__module__
|
|
433
|
+
|
|
434
|
+
# If none of the bases have a __dict__, the new class shouldn't
|
|
435
|
+
# have one either.
|
|
436
|
+
# NOTE: we need the isinstance(b, type) check to exclude old-style
|
|
437
|
+
# classes.
|
|
438
|
+
if all(isinstance(b, type) and not b.__dictoffset__ for b in bases):
|
|
439
|
+
methods['__slots__'] = ()
|
|
440
|
+
|
|
441
|
+
metaclass = DynamicMetaclass
|
|
442
|
+
# The metaclass of a class must derive from the metaclasses of its
|
|
443
|
+
# bases. The following handles the case where one of the base
|
|
444
|
+
# classes is a known Sage metaclass. This approach won't scale
|
|
445
|
+
# well if we start using metaclasses seriously in Sage.
|
|
446
|
+
for base in bases:
|
|
447
|
+
if isinstance(base, ClasscallMetaclass):
|
|
448
|
+
if not issubclass(metaclass, ClasscallMetaclass):
|
|
449
|
+
if metaclass is DynamicMetaclass:
|
|
450
|
+
metaclass = DynamicClasscallMetaclass
|
|
451
|
+
elif metaclass is DynamicInheritComparisonMetaclass:
|
|
452
|
+
metaclass = DynamicInheritComparisonClasscallMetaclass
|
|
453
|
+
else:
|
|
454
|
+
raise NotImplementedError("No subclass of %r known that inherits from ClasscallMetaclass" % (metaclass,))
|
|
455
|
+
if isinstance(base, InheritComparisonMetaclass):
|
|
456
|
+
if not issubclass(metaclass, InheritComparisonMetaclass):
|
|
457
|
+
if metaclass is DynamicMetaclass:
|
|
458
|
+
metaclass = DynamicInheritComparisonMetaclass
|
|
459
|
+
elif metaclass is DynamicClasscallMetaclass:
|
|
460
|
+
metaclass = DynamicInheritComparisonClasscallMetaclass
|
|
461
|
+
else:
|
|
462
|
+
raise NotImplementedError("No subclass of %r known that inherits from InheritComparisonMetaclass" % (metaclass,))
|
|
463
|
+
return metaclass(name, bases, methods)
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
class DynamicMetaclass(type):
|
|
467
|
+
"""
|
|
468
|
+
A metaclass implementing an appropriate reduce-by-construction method
|
|
469
|
+
"""
|
|
470
|
+
def _sage_src_lines_(self):
|
|
471
|
+
r"""
|
|
472
|
+
Get the source lines of the dynamic class. This defers to the
|
|
473
|
+
source lines of the ``_doccls`` attribute, which is set when
|
|
474
|
+
the dynamic class is constructed.
|
|
475
|
+
|
|
476
|
+
EXAMPLES::
|
|
477
|
+
|
|
478
|
+
sage: from sage.misc.sageinspect import sage_getsourcelines
|
|
479
|
+
sage: from sage.structure.dynamic_class import dynamic_class
|
|
480
|
+
sage: C = dynamic_class("SomeClass", [object], doccls=Integer)
|
|
481
|
+
sage: sage_getsourcelines(C)[0][0]
|
|
482
|
+
'cdef class Integer(sage.structure.element.EuclideanDomainElement):\n'
|
|
483
|
+
"""
|
|
484
|
+
try:
|
|
485
|
+
# HACK: _doccls is a 1-element tuple to avoid __classget__
|
|
486
|
+
# or trouble with binding behaviour...
|
|
487
|
+
doccls = self._doccls[0]
|
|
488
|
+
except AttributeError:
|
|
489
|
+
raise NotImplementedError("no _doccls found")
|
|
490
|
+
from sage.misc.sageinspect import sage_getsourcelines
|
|
491
|
+
return sage_getsourcelines(doccls)
|
|
492
|
+
|
|
493
|
+
def __reduce__(self):
|
|
494
|
+
"""
|
|
495
|
+
See :func:`sage.structure.dynamic_class.dynamic_class` for
|
|
496
|
+
non-trivial tests.
|
|
497
|
+
|
|
498
|
+
TESTS::
|
|
499
|
+
|
|
500
|
+
sage: class Foo: pass
|
|
501
|
+
sage: class DocClass: pass
|
|
502
|
+
sage: C = sage.structure.dynamic_class.dynamic_class_internal("bla", (object,), Foo, doccls = DocClass)
|
|
503
|
+
sage: type(C).__reduce__(C)
|
|
504
|
+
(<function dynamic_class at ...>,
|
|
505
|
+
('bla', (<class 'object'>,), <class '__main__.Foo'>, None, <class '__main__.DocClass'>))
|
|
506
|
+
sage: C = sage.structure.dynamic_class.dynamic_class_internal("bla", (object,), Foo, doccls = DocClass, reduction = "blah")
|
|
507
|
+
sage: type(C).__reduce__(C)
|
|
508
|
+
'blah'
|
|
509
|
+
"""
|
|
510
|
+
return self._reduction
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
class DynamicClasscallMetaclass(DynamicMetaclass, ClasscallMetaclass):
|
|
514
|
+
pass
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
class DynamicInheritComparisonMetaclass(DynamicMetaclass, InheritComparisonMetaclass):
|
|
518
|
+
pass
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
class DynamicInheritComparisonClasscallMetaclass(DynamicMetaclass, InheritComparisonClasscallMetaclass):
|
|
522
|
+
pass
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
# This registers the appropriate reduction methods (see Issue #5985)
|
|
526
|
+
for M in [DynamicMetaclass,
|
|
527
|
+
DynamicClasscallMetaclass,
|
|
528
|
+
DynamicInheritComparisonMetaclass,
|
|
529
|
+
DynamicInheritComparisonClasscallMetaclass]:
|
|
530
|
+
copyreg.pickle(M, M.__reduce__)
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
class TestClass:
|
|
534
|
+
"""
|
|
535
|
+
A class used for checking that introspection works
|
|
536
|
+
"""
|
|
537
|
+
def bla():
|
|
538
|
+
"""
|
|
539
|
+
bla ...
|
|
540
|
+
"""
|
|
541
|
+
pass
|
|
Binary file
|