passagemath-objects 10.6.45__cp313-cp313-musllinux_1_2_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.
Potentially problematic release.
This version of passagemath-objects might be problematic. Click here for more details.
- passagemath_objects/__init__.py +3 -0
- passagemath_objects-10.6.45.dist-info/METADATA +115 -0
- passagemath_objects-10.6.45.dist-info/RECORD +280 -0
- passagemath_objects-10.6.45.dist-info/WHEEL +5 -0
- passagemath_objects-10.6.45.dist-info/top_level.txt +3 -0
- passagemath_objects.libs/libgmp-0e7fc84e.so.10.5.0 +0 -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-313-x86_64-linux-musl.so +0 -0
- sage/arith/numerical_approx.pxd +35 -0
- sage/arith/numerical_approx.pyx +75 -0
- sage/arith/power.cpython-313-x86_64-linux-musl.so +0 -0
- sage/arith/power.pxd +31 -0
- sage/arith/power.pyx +127 -0
- sage/categories/action.cpython-313-x86_64-linux-musl.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-313-x86_64-linux-musl.so +0 -0
- sage/categories/category_cy_helper.pxd +8 -0
- sage/categories/category_cy_helper.pyx +322 -0
- sage/categories/category_singleton.cpython-313-x86_64-linux-musl.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-313-x86_64-linux-musl.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-313-x86_64-linux-musl.so +0 -0
- sage/categories/map.pxd +34 -0
- sage/categories/map.pyx +2106 -0
- sage/categories/morphism.cpython-313-x86_64-linux-musl.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-313-x86_64-linux-musl.so +0 -0
- sage/cpython/atexit.pyx +269 -0
- sage/cpython/builtin_types.cpython-313-x86_64-linux-musl.so +0 -0
- sage/cpython/builtin_types.pyx +7 -0
- sage/cpython/cython_metaclass.cpython-313-x86_64-linux-musl.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-313-x86_64-linux-musl.so +0 -0
- sage/cpython/debug.pyx +302 -0
- sage/cpython/dict_del_by_value.cpython-313-x86_64-linux-musl.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-313-x86_64-linux-musl.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-313-x86_64-linux-musl.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-313-x86_64-linux-musl.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-313-x86_64-linux-musl.so +0 -0
- sage/groups/group.pxd +14 -0
- sage/groups/group.pyx +322 -0
- sage/groups/old.cpython-313-x86_64-linux-musl.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-313-x86_64-linux-musl.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-313-x86_64-linux-musl.so +0 -0
- sage/misc/c3_controlled.pxd +2 -0
- sage/misc/c3_controlled.pyx +1402 -0
- sage/misc/cachefunc.cpython-313-x86_64-linux-musl.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-313-x86_64-linux-musl.so +0 -0
- sage/misc/classcall_metaclass.pxd +14 -0
- sage/misc/classcall_metaclass.pyx +599 -0
- sage/misc/constant_function.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/constant_function.pyx +130 -0
- sage/misc/decorators.py +747 -0
- sage/misc/fast_methods.cpython-313-x86_64-linux-musl.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-313-x86_64-linux-musl.so +0 -0
- sage/misc/fpickle.pyx +177 -0
- sage/misc/function_mangling.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/function_mangling.pxd +11 -0
- sage/misc/function_mangling.pyx +308 -0
- sage/misc/inherit_comparison.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/inherit_comparison.pxd +5 -0
- sage/misc/inherit_comparison.pyx +105 -0
- sage/misc/instancedoc.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/instancedoc.pyx +331 -0
- sage/misc/lazy_attribute.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/lazy_attribute.pyx +607 -0
- sage/misc/lazy_format.py +135 -0
- sage/misc/lazy_import.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/lazy_import.pyx +1299 -0
- sage/misc/lazy_import_cache.py +36 -0
- sage/misc/lazy_list.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/lazy_list.pxd +19 -0
- sage/misc/lazy_list.pyx +1187 -0
- sage/misc/lazy_string.cpython-313-x86_64-linux-musl.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-313-x86_64-linux-musl.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-313-x86_64-linux-musl.so +0 -0
- sage/misc/nested_class.pxd +3 -0
- sage/misc/nested_class.pyx +394 -0
- sage/misc/persist.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/persist.pyx +1251 -0
- sage/misc/prandom.py +418 -0
- sage/misc/randstate.cpython-313-x86_64-linux-musl.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-313-x86_64-linux-musl.so +0 -0
- sage/misc/reset.pyx +196 -0
- sage/misc/sage_ostools.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/sage_ostools.pyx +323 -0
- sage/misc/sage_timeit.py +275 -0
- sage/misc/sage_timeit_class.cpython-313-x86_64-linux-musl.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-313-x86_64-linux-musl.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-313-x86_64-linux-musl.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-313-x86_64-linux-musl.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-313-x86_64-linux-musl.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-313-x86_64-linux-musl.so +0 -0
- sage/structure/category_object.pxd +28 -0
- sage/structure/category_object.pyx +1087 -0
- sage/structure/coerce.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/coerce.pxd +44 -0
- sage/structure/coerce.pyx +2107 -0
- sage/structure/coerce_actions.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/coerce_actions.pxd +27 -0
- sage/structure/coerce_actions.pyx +988 -0
- sage/structure/coerce_dict.cpython-313-x86_64-linux-musl.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-313-x86_64-linux-musl.so +0 -0
- sage/structure/coerce_maps.pxd +28 -0
- sage/structure/coerce_maps.pyx +718 -0
- sage/structure/debug_options.cpython-313-x86_64-linux-musl.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-313-x86_64-linux-musl.so +0 -0
- sage/structure/element.pxd +272 -0
- sage/structure/element.pyx +4772 -0
- sage/structure/element_wrapper.cpython-313-x86_64-linux-musl.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-313-x86_64-linux-musl.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-313-x86_64-linux-musl.so +0 -0
- sage/structure/list_clone.pxd +65 -0
- sage/structure/list_clone.pyx +1867 -0
- sage/structure/list_clone_demo.cpython-313-x86_64-linux-musl.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-313-x86_64-linux-musl.so +0 -0
- sage/structure/list_clone_timings_cy.pyx +86 -0
- sage/structure/mutability.cpython-313-x86_64-linux-musl.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-313-x86_64-linux-musl.so +0 -0
- sage/structure/parent.pxd +112 -0
- sage/structure/parent.pyx +3093 -0
- sage/structure/parent_base.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/parent_base.pxd +13 -0
- sage/structure/parent_base.pyx +44 -0
- sage/structure/parent_gens.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/parent_gens.pxd +22 -0
- sage/structure/parent_gens.pyx +377 -0
- sage/structure/parent_old.cpython-313-x86_64-linux-musl.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-313-x86_64-linux-musl.so +0 -0
- sage/structure/richcmp.pxd +213 -0
- sage/structure/richcmp.pyx +495 -0
- sage/structure/sage_object.cpython-313-x86_64-linux-musl.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,245 @@
|
|
|
1
|
+
/* sage_setup: distribution = sagemath-objects
|
|
2
|
+
*/
|
|
3
|
+
/* This contains internal definitions for python dictionaries,
|
|
4
|
+
* mostly copied from cpython sourcecode.
|
|
5
|
+
*
|
|
6
|
+
* Moved here to make it easier to maintain in the face of python
|
|
7
|
+
* changes.
|
|
8
|
+
* */
|
|
9
|
+
|
|
10
|
+
#if PY_VERSION_HEX < 0x30b0000
|
|
11
|
+
|
|
12
|
+
/************************************************************/
|
|
13
|
+
/* Copied verbatim from cpython 3.8 (Objects/dict-common.h) */
|
|
14
|
+
/************************************************************/
|
|
15
|
+
|
|
16
|
+
#ifndef Py_DICT_COMMON_H
|
|
17
|
+
#define Py_DICT_COMMON_H
|
|
18
|
+
|
|
19
|
+
typedef struct {
|
|
20
|
+
/* Cached hash code of me_key. */
|
|
21
|
+
Py_hash_t me_hash;
|
|
22
|
+
PyObject *me_key;
|
|
23
|
+
PyObject *me_value; /* This field is only meaningful for combined tables */
|
|
24
|
+
} PyDictKeyEntry;
|
|
25
|
+
|
|
26
|
+
/* dict_lookup_func() returns index of entry which can be used like DK_ENTRIES(dk)[index].
|
|
27
|
+
* -1 when no entry found, -3 when compare raises error.
|
|
28
|
+
*/
|
|
29
|
+
typedef Py_ssize_t (*dict_lookup_func)
|
|
30
|
+
(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr);
|
|
31
|
+
|
|
32
|
+
#define DKIX_EMPTY (-1)
|
|
33
|
+
#define DKIX_DUMMY (-2) /* Used internally */
|
|
34
|
+
#define DKIX_ERROR (-3)
|
|
35
|
+
|
|
36
|
+
/* See dictobject.c for actual layout of DictKeysObject */
|
|
37
|
+
struct _dictkeysobject {
|
|
38
|
+
Py_ssize_t dk_refcnt;
|
|
39
|
+
|
|
40
|
+
/* Size of the hash table (dk_indices). It must be a power of 2. */
|
|
41
|
+
Py_ssize_t dk_size;
|
|
42
|
+
|
|
43
|
+
/* Function to lookup in the hash table (dk_indices):
|
|
44
|
+
|
|
45
|
+
- lookdict(): general-purpose, and may return DKIX_ERROR if (and
|
|
46
|
+
only if) a comparison raises an exception.
|
|
47
|
+
|
|
48
|
+
- lookdict_unicode(): specialized to Unicode string keys, comparison of
|
|
49
|
+
which can never raise an exception; that function can never return
|
|
50
|
+
DKIX_ERROR.
|
|
51
|
+
|
|
52
|
+
- lookdict_unicode_nodummy(): similar to lookdict_unicode() but further
|
|
53
|
+
specialized for Unicode string keys that cannot be the <dummy> value.
|
|
54
|
+
|
|
55
|
+
- lookdict_split(): Version of lookdict() for split tables. */
|
|
56
|
+
dict_lookup_func dk_lookup;
|
|
57
|
+
|
|
58
|
+
/* Number of usable entries in dk_entries. */
|
|
59
|
+
Py_ssize_t dk_usable;
|
|
60
|
+
|
|
61
|
+
/* Number of used entries in dk_entries. */
|
|
62
|
+
Py_ssize_t dk_nentries;
|
|
63
|
+
|
|
64
|
+
/* Actual hash table of dk_size entries. It holds indices in dk_entries,
|
|
65
|
+
or DKIX_EMPTY(-1) or DKIX_DUMMY(-2).
|
|
66
|
+
|
|
67
|
+
Indices must be: 0 <= indice < USABLE_FRACTION(dk_size).
|
|
68
|
+
|
|
69
|
+
The size in bytes of an indice depends on dk_size:
|
|
70
|
+
|
|
71
|
+
- 1 byte if dk_size <= 0xff (char*)
|
|
72
|
+
- 2 bytes if dk_size <= 0xffff (int16_t*)
|
|
73
|
+
- 4 bytes if dk_size <= 0xffffffff (int32_t*)
|
|
74
|
+
- 8 bytes otherwise (int64_t*)
|
|
75
|
+
|
|
76
|
+
Dynamically sized, SIZEOF_VOID_P is minimum. */
|
|
77
|
+
char dk_indices[]; /* char is required to avoid strict aliasing. */
|
|
78
|
+
|
|
79
|
+
/* "PyDictKeyEntry dk_entries[dk_usable];" array follows:
|
|
80
|
+
see the DK_ENTRIES() macro */
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
#endif
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
/***********************************************************/
|
|
87
|
+
/* Copied verbatim from cpython 3.8 (Objects/dictobject.c) */
|
|
88
|
+
/***********************************************************/
|
|
89
|
+
|
|
90
|
+
#define PERTURB_SHIFT 5
|
|
91
|
+
#define DK_SIZE(dk) ((dk)->dk_size)
|
|
92
|
+
#if SIZEOF_VOID_P > 4
|
|
93
|
+
#define DK_IXSIZE(dk) \
|
|
94
|
+
(DK_SIZE(dk) <= 0xff ? \
|
|
95
|
+
1 : DK_SIZE(dk) <= 0xffff ? \
|
|
96
|
+
2 : DK_SIZE(dk) <= 0xffffffff ? \
|
|
97
|
+
4 : sizeof(int64_t))
|
|
98
|
+
#else
|
|
99
|
+
#define DK_IXSIZE(dk) \
|
|
100
|
+
(DK_SIZE(dk) <= 0xff ? \
|
|
101
|
+
1 : DK_SIZE(dk) <= 0xffff ? \
|
|
102
|
+
2 : sizeof(int32_t))
|
|
103
|
+
#endif
|
|
104
|
+
#define DK_ENTRIES(dk) \
|
|
105
|
+
((PyDictKeyEntry*)(&((int8_t*)((dk)->dk_indices))[DK_SIZE(dk) * DK_IXSIZE(dk)]))
|
|
106
|
+
|
|
107
|
+
#define DK_MASK(dk) (((dk)->dk_size)-1)
|
|
108
|
+
|
|
109
|
+
/* lookup indices. returns DKIX_EMPTY, DKIX_DUMMY, or ix >=0 */
|
|
110
|
+
static inline Py_ssize_t
|
|
111
|
+
dictkeys_get_index(PyDictKeysObject *keys, Py_ssize_t i)
|
|
112
|
+
{
|
|
113
|
+
Py_ssize_t s = DK_SIZE(keys);
|
|
114
|
+
Py_ssize_t ix;
|
|
115
|
+
|
|
116
|
+
if (s <= 0xff) {
|
|
117
|
+
int8_t *indices = (int8_t*)(keys->dk_indices);
|
|
118
|
+
ix = indices[i];
|
|
119
|
+
}
|
|
120
|
+
else if (s <= 0xffff) {
|
|
121
|
+
int16_t *indices = (int16_t*)(keys->dk_indices);
|
|
122
|
+
ix = indices[i];
|
|
123
|
+
}
|
|
124
|
+
#if SIZEOF_VOID_P > 4
|
|
125
|
+
else if (s > 0xffffffff) {
|
|
126
|
+
int64_t *indices = (int64_t*)(keys->dk_indices);
|
|
127
|
+
ix = indices[i];
|
|
128
|
+
}
|
|
129
|
+
#endif
|
|
130
|
+
else {
|
|
131
|
+
int32_t *indices = (int32_t*)(keys->dk_indices);
|
|
132
|
+
ix = indices[i];
|
|
133
|
+
}
|
|
134
|
+
assert(ix >= DKIX_DUMMY);
|
|
135
|
+
return ix;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/* write to indices. */
|
|
139
|
+
static inline void
|
|
140
|
+
dictkeys_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix)
|
|
141
|
+
{
|
|
142
|
+
Py_ssize_t s = DK_SIZE(keys);
|
|
143
|
+
|
|
144
|
+
assert(ix >= DKIX_DUMMY);
|
|
145
|
+
|
|
146
|
+
if (s <= 0xff) {
|
|
147
|
+
int8_t *indices = (int8_t*)(keys->dk_indices);
|
|
148
|
+
assert(ix <= 0x7f);
|
|
149
|
+
indices[i] = (char)ix;
|
|
150
|
+
}
|
|
151
|
+
else if (s <= 0xffff) {
|
|
152
|
+
int16_t *indices = (int16_t*)(keys->dk_indices);
|
|
153
|
+
assert(ix <= 0x7fff);
|
|
154
|
+
indices[i] = (int16_t)ix;
|
|
155
|
+
}
|
|
156
|
+
#if SIZEOF_VOID_P > 4
|
|
157
|
+
else if (s > 0xffffffff) {
|
|
158
|
+
int64_t *indices = (int64_t*)(keys->dk_indices);
|
|
159
|
+
indices[i] = ix;
|
|
160
|
+
}
|
|
161
|
+
#endif
|
|
162
|
+
else {
|
|
163
|
+
int32_t *indices = (int32_t*)(keys->dk_indices);
|
|
164
|
+
assert(ix <= 0x7fffffff);
|
|
165
|
+
indices[i] = (int32_t)ix;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/************************************************************/
|
|
170
|
+
|
|
171
|
+
#else /* Python >= 3.11 */
|
|
172
|
+
|
|
173
|
+
#define Py_BUILD_CORE
|
|
174
|
+
#undef _PyGC_FINALIZED
|
|
175
|
+
#include <internal/pycore_dict.h>
|
|
176
|
+
|
|
177
|
+
/************************************************************/
|
|
178
|
+
/* Copied verbatim from cpython 3.11 (Objects/dictobject.c) */
|
|
179
|
+
/************************************************************/
|
|
180
|
+
|
|
181
|
+
#define PERTURB_SHIFT 5
|
|
182
|
+
#define DK_MASK(dk) (DK_SIZE(dk)-1)
|
|
183
|
+
|
|
184
|
+
/* lookup indices. returns DKIX_EMPTY, DKIX_DUMMY, or ix >=0 */
|
|
185
|
+
static inline Py_ssize_t
|
|
186
|
+
dictkeys_get_index(const PyDictKeysObject *keys, Py_ssize_t i)
|
|
187
|
+
{
|
|
188
|
+
int log2size = DK_LOG_SIZE(keys);
|
|
189
|
+
Py_ssize_t ix;
|
|
190
|
+
|
|
191
|
+
if (log2size < 8) {
|
|
192
|
+
const int8_t *indices = (const int8_t*)(keys->dk_indices);
|
|
193
|
+
ix = indices[i];
|
|
194
|
+
}
|
|
195
|
+
else if (log2size < 16) {
|
|
196
|
+
const int16_t *indices = (const int16_t*)(keys->dk_indices);
|
|
197
|
+
ix = indices[i];
|
|
198
|
+
}
|
|
199
|
+
#if SIZEOF_VOID_P > 4
|
|
200
|
+
else if (log2size >= 32) {
|
|
201
|
+
const int64_t *indices = (const int64_t*)(keys->dk_indices);
|
|
202
|
+
ix = indices[i];
|
|
203
|
+
}
|
|
204
|
+
#endif
|
|
205
|
+
else {
|
|
206
|
+
const int32_t *indices = (const int32_t*)(keys->dk_indices);
|
|
207
|
+
ix = indices[i];
|
|
208
|
+
}
|
|
209
|
+
assert(ix >= DKIX_DUMMY);
|
|
210
|
+
return ix;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/* write to indices. */
|
|
214
|
+
static inline void
|
|
215
|
+
dictkeys_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix)
|
|
216
|
+
{
|
|
217
|
+
int log2size = DK_LOG_SIZE(keys);
|
|
218
|
+
|
|
219
|
+
assert(ix >= DKIX_DUMMY);
|
|
220
|
+
assert(keys->dk_version == 0);
|
|
221
|
+
|
|
222
|
+
if (log2size < 8) {
|
|
223
|
+
int8_t *indices = (int8_t*)(keys->dk_indices);
|
|
224
|
+
assert(ix <= 0x7f);
|
|
225
|
+
indices[i] = (char)ix;
|
|
226
|
+
}
|
|
227
|
+
else if (log2size < 16) {
|
|
228
|
+
int16_t *indices = (int16_t*)(keys->dk_indices);
|
|
229
|
+
assert(ix <= 0x7fff);
|
|
230
|
+
indices[i] = (int16_t)ix;
|
|
231
|
+
}
|
|
232
|
+
#if SIZEOF_VOID_P > 4
|
|
233
|
+
else if (log2size >= 32) {
|
|
234
|
+
int64_t *indices = (int64_t*)(keys->dk_indices);
|
|
235
|
+
indices[i] = ix;
|
|
236
|
+
}
|
|
237
|
+
#endif
|
|
238
|
+
else {
|
|
239
|
+
int32_t *indices = (int32_t*)(keys->dk_indices);
|
|
240
|
+
assert(ix <= 0x7fffffff);
|
|
241
|
+
indices[i] = (int32_t)ix;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
#endif
|
|
Binary file
|
sage/cpython/getattr.pxd
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-objects
|
|
2
|
+
# A class that allows for a more efficient creation
|
|
3
|
+
# of attribute errors, so that raising them requires
|
|
4
|
+
# less time.
|
|
5
|
+
cdef class AttributeErrorMessage:
|
|
6
|
+
cdef public cls
|
|
7
|
+
cdef public name
|
|
8
|
+
|
|
9
|
+
cpdef getattr_from_other_class(self, cls, name)
|
sage/cpython/getattr.pyx
ADDED
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-objects
|
|
2
|
+
"""
|
|
3
|
+
Variants of getattr()
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from cpython.object cimport PyObject, PyTypeObject, Py_TYPE, descrgetfunc
|
|
7
|
+
|
|
8
|
+
from sage.cpython.string cimport bytes_to_str
|
|
9
|
+
|
|
10
|
+
cdef extern from "Python.h":
|
|
11
|
+
r"""
|
|
12
|
+
/* Coded in C because class internals need to be accessed. */
|
|
13
|
+
static PyObject*
|
|
14
|
+
instance_getattr(PyObject* obj, PyObject* name)
|
|
15
|
+
{
|
|
16
|
+
if (PyType_Check(obj)) {
|
|
17
|
+
return _PyType_Lookup((PyTypeObject*)obj, name);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
PyObject** dptr = _PyObject_GetDictPtr(obj);
|
|
21
|
+
if (dptr == NULL) return NULL;
|
|
22
|
+
PyObject* dict = *dptr;
|
|
23
|
+
if (dict == NULL) return NULL;
|
|
24
|
+
return PyDict_GetItem(dict, name);
|
|
25
|
+
}
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
# Return the attribute "name" from "obj". This only looks up the
|
|
29
|
+
# attribute in the instance "obj" and not in obj.__class__.
|
|
30
|
+
# If "obj" is a class, this searches for the attribute in the base
|
|
31
|
+
# classes.
|
|
32
|
+
#
|
|
33
|
+
# Return a borrowed reference or NULL if the attribute was not found.
|
|
34
|
+
PyObject* instance_getattr(obj, name)
|
|
35
|
+
|
|
36
|
+
int PyDescr_IsData(PyObject*)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
cdef class AttributeErrorMessage:
|
|
40
|
+
"""
|
|
41
|
+
Try to emulate the standard Python :exc:`AttributeError` message.
|
|
42
|
+
|
|
43
|
+
.. NOTE::
|
|
44
|
+
|
|
45
|
+
The typical fate of an attribute error is being caught. Hence,
|
|
46
|
+
under normal circumstances, nobody will ever see the error
|
|
47
|
+
message. The idea for this class is to provide an object that
|
|
48
|
+
is fast to create and whose string representation is an attribute
|
|
49
|
+
error's message. That string representation is only created if
|
|
50
|
+
someone wants to see it.
|
|
51
|
+
|
|
52
|
+
EXAMPLES::
|
|
53
|
+
|
|
54
|
+
sage: 1.bla #indirect doctest
|
|
55
|
+
Traceback (most recent call last):
|
|
56
|
+
...
|
|
57
|
+
AttributeError: 'sage.rings.integer.Integer' object has no attribute 'bla'...
|
|
58
|
+
sage: x = polygen(ZZ, 'x')
|
|
59
|
+
sage: QQ[x].gen().bla # needs sage.libs.flint
|
|
60
|
+
Traceback (most recent call last):
|
|
61
|
+
...
|
|
62
|
+
AttributeError: 'sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint' object has no attribute 'bla'...
|
|
63
|
+
|
|
64
|
+
::
|
|
65
|
+
|
|
66
|
+
sage: from sage.cpython.getattr import AttributeErrorMessage
|
|
67
|
+
sage: AttributeErrorMessage(int(1), 'bla')
|
|
68
|
+
'int' object has no attribute 'bla'
|
|
69
|
+
|
|
70
|
+
TESTS:
|
|
71
|
+
|
|
72
|
+
The error message used for the :exc:`AttributeError` is a unique object
|
|
73
|
+
and is changed inplace. This is for reasons of efficiency.
|
|
74
|
+
Hence, if one really needs the error message as a string, then one should
|
|
75
|
+
make a copy of its string representation before it changes. ::
|
|
76
|
+
|
|
77
|
+
sage: try:
|
|
78
|
+
....: 1.__bla
|
|
79
|
+
....: except AttributeError as exc:
|
|
80
|
+
....: ElementError = exc
|
|
81
|
+
sage: ElementError
|
|
82
|
+
AttributeError('sage.rings.integer.Integer' object has no attribute '__bla'...)
|
|
83
|
+
sage: try:
|
|
84
|
+
....: x.__bla
|
|
85
|
+
....: except AttributeError as exc:
|
|
86
|
+
....: ElementError2 = exc
|
|
87
|
+
sage: ElementError
|
|
88
|
+
AttributeError('sage.rings.polynomial...' object has no attribute '__bla'...)
|
|
89
|
+
sage: ElementError2.args[0] is ElementError.args[0]
|
|
90
|
+
True
|
|
91
|
+
sage: isinstance(ElementError.args[0], sage.cpython.getattr.AttributeErrorMessage)
|
|
92
|
+
True
|
|
93
|
+
|
|
94
|
+
AUTHOR:
|
|
95
|
+
|
|
96
|
+
- Simon King (2011-05-21)
|
|
97
|
+
"""
|
|
98
|
+
def __init__(self, obj=None, name=""):
|
|
99
|
+
self.cls = type(obj)
|
|
100
|
+
self.name = name
|
|
101
|
+
|
|
102
|
+
def __repr__(self):
|
|
103
|
+
cls = bytes_to_str((<PyTypeObject*>self.cls).tp_name, 'utf-8',
|
|
104
|
+
'replace')
|
|
105
|
+
# Go directly through tp_name since __name__ can be overridden--this is
|
|
106
|
+
# almost verbatim how CPython formats this message except we don't cut
|
|
107
|
+
# off the class name after 50 characters, and non-strings are displayed
|
|
108
|
+
# with their repr :)
|
|
109
|
+
return f"'{cls}' object has no attribute {self.name!r}"
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
cdef AttributeErrorMessage dummy_error_message = AttributeErrorMessage()
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
cpdef raw_getattr(obj, name):
|
|
116
|
+
"""
|
|
117
|
+
Like ``getattr(obj, name)`` but without invoking the binding
|
|
118
|
+
behavior of descriptors under normal attribute access.
|
|
119
|
+
This can be used to easily get unbound methods or other
|
|
120
|
+
descriptors.
|
|
121
|
+
|
|
122
|
+
This ignores ``__getattribute__`` hooks but it does support
|
|
123
|
+
``__getattr__``.
|
|
124
|
+
|
|
125
|
+
.. NOTE::
|
|
126
|
+
|
|
127
|
+
For Cython classes, ``__getattr__`` is actually implemented as
|
|
128
|
+
``__getattribute__``, which means that it is not supported by
|
|
129
|
+
``raw_getattr``.
|
|
130
|
+
|
|
131
|
+
EXAMPLES::
|
|
132
|
+
|
|
133
|
+
sage: class X:
|
|
134
|
+
....: @property
|
|
135
|
+
....: def prop(self):
|
|
136
|
+
....: return 42
|
|
137
|
+
....: def method(self):
|
|
138
|
+
....: pass
|
|
139
|
+
....: def __getattr__(self, name):
|
|
140
|
+
....: return "magic " + name
|
|
141
|
+
sage: raw_getattr(X, "prop")
|
|
142
|
+
<property object at ...>
|
|
143
|
+
sage: raw_getattr(X, "method")
|
|
144
|
+
<function ...method at ...>
|
|
145
|
+
sage: raw_getattr(X, "attr")
|
|
146
|
+
Traceback (most recent call last):
|
|
147
|
+
...
|
|
148
|
+
AttributeError: '...' object has no attribute 'attr'...
|
|
149
|
+
sage: x = X()
|
|
150
|
+
sage: raw_getattr(x, "prop")
|
|
151
|
+
<property object at ...>
|
|
152
|
+
sage: raw_getattr(x, "method")
|
|
153
|
+
<function ...method at ...>
|
|
154
|
+
sage: raw_getattr(x, "attr")
|
|
155
|
+
'magic attr'
|
|
156
|
+
sage: x.__dict__["prop"] = 'no'
|
|
157
|
+
sage: x.__dict__["method"] = 'yes'
|
|
158
|
+
sage: x.__dict__["attr"] = 'ok'
|
|
159
|
+
sage: raw_getattr(x, "prop")
|
|
160
|
+
<property object at ...>
|
|
161
|
+
sage: raw_getattr(x, "method")
|
|
162
|
+
'yes'
|
|
163
|
+
sage: raw_getattr(x, "attr")
|
|
164
|
+
'ok'
|
|
165
|
+
|
|
166
|
+
The same tests with an inherited new-style class::
|
|
167
|
+
|
|
168
|
+
sage: class Y(X, object):
|
|
169
|
+
....: pass
|
|
170
|
+
sage: raw_getattr(Y, "prop")
|
|
171
|
+
<property object at ...>
|
|
172
|
+
sage: raw_getattr(Y, "method")
|
|
173
|
+
<function ...method at ...>
|
|
174
|
+
sage: raw_getattr(Y, "attr")
|
|
175
|
+
Traceback (most recent call last):
|
|
176
|
+
...
|
|
177
|
+
AttributeError: '...' object has no attribute 'attr'...
|
|
178
|
+
sage: y = Y()
|
|
179
|
+
sage: raw_getattr(y, "prop")
|
|
180
|
+
<property object at ...>
|
|
181
|
+
sage: raw_getattr(y, "method")
|
|
182
|
+
<function ...method at ...>
|
|
183
|
+
sage: raw_getattr(y, "attr")
|
|
184
|
+
'magic attr'
|
|
185
|
+
sage: y.__dict__["prop"] = 'no'
|
|
186
|
+
sage: y.__dict__["method"] = 'yes'
|
|
187
|
+
sage: y.__dict__["attr"] = 'ok'
|
|
188
|
+
sage: raw_getattr(y, "prop")
|
|
189
|
+
<property object at ...>
|
|
190
|
+
sage: raw_getattr(y, "method")
|
|
191
|
+
'yes'
|
|
192
|
+
sage: raw_getattr(y, "attr")
|
|
193
|
+
'ok'
|
|
194
|
+
"""
|
|
195
|
+
cdef PyObject* class_attr = NULL
|
|
196
|
+
|
|
197
|
+
try:
|
|
198
|
+
cls = obj.__class__
|
|
199
|
+
except AttributeError:
|
|
200
|
+
# Old-style classes don't have a __class__ (because these do
|
|
201
|
+
# not support metaclasses).
|
|
202
|
+
cls = None
|
|
203
|
+
else:
|
|
204
|
+
class_attr = instance_getattr(cls, name)
|
|
205
|
+
|
|
206
|
+
# We honor the order prescribed by the descriptor protocol:
|
|
207
|
+
# a data descriptor overrides instance attributes. In other
|
|
208
|
+
# cases, the instance attribute takes priority.
|
|
209
|
+
if class_attr is not NULL and PyDescr_IsData(class_attr):
|
|
210
|
+
return <object>class_attr
|
|
211
|
+
|
|
212
|
+
instance_attr = instance_getattr(obj, name)
|
|
213
|
+
if instance_attr is not NULL:
|
|
214
|
+
return <object>instance_attr
|
|
215
|
+
if class_attr is not NULL:
|
|
216
|
+
return <object>class_attr
|
|
217
|
+
|
|
218
|
+
if cls is not None:
|
|
219
|
+
try:
|
|
220
|
+
cls_getattr = cls.__getattr__
|
|
221
|
+
except AttributeError:
|
|
222
|
+
pass
|
|
223
|
+
else:
|
|
224
|
+
return cls_getattr(obj, name)
|
|
225
|
+
|
|
226
|
+
dummy_error_message.cls = type(obj)
|
|
227
|
+
dummy_error_message.name = name
|
|
228
|
+
raise AttributeError(dummy_error_message)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
cpdef getattr_from_other_class(self, cls, name):
|
|
232
|
+
"""
|
|
233
|
+
Emulate ``getattr(self, name)``, as if ``self`` was an instance of
|
|
234
|
+
``cls``.
|
|
235
|
+
|
|
236
|
+
INPUT:
|
|
237
|
+
|
|
238
|
+
- ``self`` -- some object
|
|
239
|
+
|
|
240
|
+
- ``cls`` -- a new-style class
|
|
241
|
+
|
|
242
|
+
- ``name`` -- string
|
|
243
|
+
|
|
244
|
+
If ``self`` is an instance of cls, raises an :exc:`AttributeError`, to
|
|
245
|
+
avoid a double lookup. This function is intended to be called from
|
|
246
|
+
__getattr__, and so should not be called if name is an attribute
|
|
247
|
+
of ``self``.
|
|
248
|
+
|
|
249
|
+
EXAMPLES::
|
|
250
|
+
|
|
251
|
+
sage: from sage.cpython.getattr import getattr_from_other_class
|
|
252
|
+
sage: class A():
|
|
253
|
+
....: def inc(self):
|
|
254
|
+
....: return self + 1
|
|
255
|
+
....:
|
|
256
|
+
....: @staticmethod
|
|
257
|
+
....: def greeting():
|
|
258
|
+
....: print("Hello World!")
|
|
259
|
+
....:
|
|
260
|
+
....: @lazy_attribute
|
|
261
|
+
....: def lazy_attribute(self):
|
|
262
|
+
....: return repr(self)
|
|
263
|
+
sage: getattr_from_other_class(1, A, "inc")
|
|
264
|
+
<bound method A.inc of 1>
|
|
265
|
+
sage: getattr_from_other_class(1, A, "inc")()
|
|
266
|
+
2
|
|
267
|
+
|
|
268
|
+
Static methods work::
|
|
269
|
+
|
|
270
|
+
sage: getattr_from_other_class(1, A, "greeting")()
|
|
271
|
+
Hello World!
|
|
272
|
+
|
|
273
|
+
Caveat: lazy attributes work with extension types only
|
|
274
|
+
if they allow attribute assignment or have a public attribute
|
|
275
|
+
``_cached_methods`` of type ``<dict>``. This condition
|
|
276
|
+
is satisfied, e.g., by any class that is derived from
|
|
277
|
+
:class:`Parent`::
|
|
278
|
+
|
|
279
|
+
sage: getattr_from_other_class(1, A, "lazy_attribute")
|
|
280
|
+
Traceback (most recent call last):
|
|
281
|
+
...
|
|
282
|
+
AttributeError: 'sage.rings.integer.Integer' object has no attribute 'lazy_attribute'...
|
|
283
|
+
|
|
284
|
+
The integer ring is a parent, so, lazy attributes work::
|
|
285
|
+
|
|
286
|
+
sage: getattr_from_other_class(ZZ, A, "lazy_attribute")
|
|
287
|
+
'Integer Ring'
|
|
288
|
+
sage: getattr_from_other_class(PolynomialRing(QQ, name='x', sparse=True).one(), A, "lazy_attribute")
|
|
289
|
+
'1'
|
|
290
|
+
sage: getattr_from_other_class(17, A, "lazy_attribute")
|
|
291
|
+
Traceback (most recent call last):
|
|
292
|
+
...
|
|
293
|
+
AttributeError: 'sage.rings.integer.Integer' object has no attribute 'lazy_attribute'...
|
|
294
|
+
|
|
295
|
+
In general, descriptors are not yet well supported, because they
|
|
296
|
+
often do not accept to be cheated with the type of their instance::
|
|
297
|
+
|
|
298
|
+
sage: A.__weakref__.__get__(1)
|
|
299
|
+
Traceback (most recent call last):
|
|
300
|
+
...
|
|
301
|
+
TypeError: descriptor '__weakref__' for 'A' objects doesn't apply
|
|
302
|
+
to ...'sage.rings.integer.Integer' object
|
|
303
|
+
|
|
304
|
+
When this occurs, an :exc:`AttributeError` is raised::
|
|
305
|
+
|
|
306
|
+
sage: getattr_from_other_class(1, A, "__weakref__")
|
|
307
|
+
Traceback (most recent call last):
|
|
308
|
+
...
|
|
309
|
+
AttributeError: 'sage.rings.integer.Integer' object has no attribute '__weakref__'...
|
|
310
|
+
|
|
311
|
+
This was caught by :issue:`8296` for which we do a couple more tests::
|
|
312
|
+
|
|
313
|
+
sage: "__weakref__" in dir(A)
|
|
314
|
+
True
|
|
315
|
+
sage: 1.__weakref__
|
|
316
|
+
Traceback (most recent call last):
|
|
317
|
+
...
|
|
318
|
+
AttributeError: 'sage.rings.integer.Integer' object has no attribute '__weakref__'...
|
|
319
|
+
|
|
320
|
+
sage: n = 1
|
|
321
|
+
sage: ip = get_ipython() # not tested: only works in interactive shell
|
|
322
|
+
sage: ip.magic_psearch('n.N') # not tested: only works in interactive shell
|
|
323
|
+
n.N
|
|
324
|
+
sage: ip.magic_psearch('n.__weakref__') # not tested: only works in interactive shell
|
|
325
|
+
|
|
326
|
+
Caveat: When __call__ is not defined for instances, using
|
|
327
|
+
``A.__call__`` yields the method ``__call__`` of the class. We use
|
|
328
|
+
a workaround but there is no guarantee for robustness.
|
|
329
|
+
|
|
330
|
+
sage: getattr_from_other_class(1, A, "__call__")
|
|
331
|
+
Traceback (most recent call last):
|
|
332
|
+
...
|
|
333
|
+
AttributeError: 'sage.rings.integer.Integer' object has no attribute '__call__'...
|
|
334
|
+
|
|
335
|
+
TESTS:
|
|
336
|
+
|
|
337
|
+
Check that we do not pick up special attributes from the ``type``
|
|
338
|
+
class, see :issue:`20686`::
|
|
339
|
+
|
|
340
|
+
sage: getattr_from_other_class(1, type, "__name__")
|
|
341
|
+
Traceback (most recent call last):
|
|
342
|
+
...
|
|
343
|
+
AttributeError: 'sage.rings.integer.Integer' object has no attribute '__name__'...
|
|
344
|
+
|
|
345
|
+
Non-strings as "name" are handled gracefully::
|
|
346
|
+
|
|
347
|
+
sage: getattr_from_other_class(1, type, None)
|
|
348
|
+
Traceback (most recent call last):
|
|
349
|
+
...
|
|
350
|
+
AttributeError: 'sage.rings.integer.Integer' object has no attribute None...
|
|
351
|
+
"""
|
|
352
|
+
if not isinstance(cls, type):
|
|
353
|
+
raise TypeError(f"{cls!r} is not a type")
|
|
354
|
+
|
|
355
|
+
if isinstance(self, cls):
|
|
356
|
+
dummy_error_message.cls = type(self)
|
|
357
|
+
dummy_error_message.name = name
|
|
358
|
+
raise AttributeError(dummy_error_message)
|
|
359
|
+
cdef PyObject* attr = instance_getattr(cls, name)
|
|
360
|
+
if attr is NULL:
|
|
361
|
+
dummy_error_message.cls = type(self)
|
|
362
|
+
dummy_error_message.name = name
|
|
363
|
+
raise AttributeError(dummy_error_message)
|
|
364
|
+
attribute = <object>attr
|
|
365
|
+
# Check for a descriptor (__get__ in Python)
|
|
366
|
+
cdef descrgetfunc getter = Py_TYPE(attribute).tp_descr_get
|
|
367
|
+
if getter is NULL:
|
|
368
|
+
# Not a descriptor
|
|
369
|
+
return attribute
|
|
370
|
+
# Conditionally defined lazy_attributes don't work well with fake subclasses
|
|
371
|
+
# (a :exc:`TypeError` is raised if the lazy attribute is not defined).
|
|
372
|
+
# For the moment, we ignore that when this occurs.
|
|
373
|
+
# Other descriptors (including __weakref__) also break.
|
|
374
|
+
try:
|
|
375
|
+
return getter(attribute, self, cls)
|
|
376
|
+
except TypeError:
|
|
377
|
+
pass
|
|
378
|
+
dummy_error_message.cls = type(self)
|
|
379
|
+
dummy_error_message.name = name
|
|
380
|
+
raise AttributeError(dummy_error_message)
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def dir_with_other_class(self, *cls):
|
|
384
|
+
r"""
|
|
385
|
+
Emulates ``dir(self)``, as if ``self`` was also an instance ``cls``,
|
|
386
|
+
right after ``caller_class`` in the method resolution order
|
|
387
|
+
(``self.__class__.mro()``)
|
|
388
|
+
|
|
389
|
+
EXAMPLES::
|
|
390
|
+
|
|
391
|
+
sage: class A():
|
|
392
|
+
....: a = 1
|
|
393
|
+
....: b = 2
|
|
394
|
+
....: c = 3
|
|
395
|
+
sage: class B():
|
|
396
|
+
....: b = 2
|
|
397
|
+
....: c = 3
|
|
398
|
+
....: d = 4
|
|
399
|
+
sage: x = A()
|
|
400
|
+
sage: x.c = 1; x.e = 1
|
|
401
|
+
sage: from sage.cpython.getattr import dir_with_other_class
|
|
402
|
+
sage: dir_with_other_class(x, B)
|
|
403
|
+
[..., 'a', 'b', 'c', 'd', 'e']
|
|
404
|
+
sage: class C():
|
|
405
|
+
....: f = 6
|
|
406
|
+
sage: dir_with_other_class(x, B, C)
|
|
407
|
+
[..., 'a', 'b', 'c', 'd', 'e', 'f']
|
|
408
|
+
|
|
409
|
+
Check that objects without dicts are well handled::
|
|
410
|
+
|
|
411
|
+
sage: # needs sage.misc.cython
|
|
412
|
+
sage: cython("cdef class A:\n cdef public int a")
|
|
413
|
+
sage: cython("cdef class B:\n cdef public int b")
|
|
414
|
+
sage: x = A()
|
|
415
|
+
sage: x.a = 1
|
|
416
|
+
sage: hasattr(x,'__dict__')
|
|
417
|
+
False
|
|
418
|
+
sage: dir_with_other_class(x, B)
|
|
419
|
+
[..., 'a', 'b']
|
|
420
|
+
|
|
421
|
+
TESTS:
|
|
422
|
+
|
|
423
|
+
Check that :issue:`13043` is fixed::
|
|
424
|
+
|
|
425
|
+
sage: len(dir(RIF))==len(set(dir(RIF))) # needs sage.rings.real_interval_field
|
|
426
|
+
True
|
|
427
|
+
"""
|
|
428
|
+
ret = set()
|
|
429
|
+
# This tries to emulate the standard dir function
|
|
430
|
+
# Is there a better way to call dir on self, while ignoring this
|
|
431
|
+
# __dir__? Using dir(super(A, self)) does not work since the
|
|
432
|
+
# attributes coming from subclasses of A will be ignored
|
|
433
|
+
ret.update(dir(self.__class__))
|
|
434
|
+
if hasattr(self, "__dict__"):
|
|
435
|
+
ret.update(list(self.__dict__))
|
|
436
|
+
for c in cls:
|
|
437
|
+
if not isinstance(self, c):
|
|
438
|
+
ret.update(dir(c))
|
|
439
|
+
return sorted(ret)
|