passagemath-objects 10.8.1a3__cp314-cp314-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. passagemath_objects/__init__.py +3 -0
  2. passagemath_objects-10.8.1a3.dist-info/DELVEWHEEL +2 -0
  3. passagemath_objects-10.8.1a3.dist-info/METADATA +114 -0
  4. passagemath_objects-10.8.1a3.dist-info/RECORD +283 -0
  5. passagemath_objects-10.8.1a3.dist-info/WHEEL +5 -0
  6. passagemath_objects-10.8.1a3.dist-info/top_level.txt +3 -0
  7. passagemath_objects.libs/libgmp-10-60021eeab4282b29024e43b2b1412b53.dll +0 -0
  8. sage/all__sagemath_objects.py +46 -0
  9. sage/arith/all__sagemath_objects.py +5 -0
  10. sage/arith/long.pxd +411 -0
  11. sage/arith/numerical_approx.cp314-win_amd64.pyd +0 -0
  12. sage/arith/numerical_approx.pxd +35 -0
  13. sage/arith/numerical_approx.pyx +75 -0
  14. sage/arith/power.cp314-win_amd64.pyd +0 -0
  15. sage/arith/power.pxd +31 -0
  16. sage/arith/power.pyx +127 -0
  17. sage/categories/action.cp314-win_amd64.pyd +0 -0
  18. sage/categories/action.pxd +29 -0
  19. sage/categories/action.pyx +641 -0
  20. sage/categories/algebra_functor.py +745 -0
  21. sage/categories/all__sagemath_objects.py +33 -0
  22. sage/categories/basic.py +71 -0
  23. sage/categories/cartesian_product.py +292 -0
  24. sage/categories/category.py +3379 -0
  25. sage/categories/category_cy_helper.cp314-win_amd64.pyd +0 -0
  26. sage/categories/category_cy_helper.pxd +8 -0
  27. sage/categories/category_cy_helper.pyx +322 -0
  28. sage/categories/category_singleton.cp314-win_amd64.pyd +0 -0
  29. sage/categories/category_singleton.pxd +3 -0
  30. sage/categories/category_singleton.pyx +343 -0
  31. sage/categories/category_types.py +637 -0
  32. sage/categories/category_with_axiom.py +2889 -0
  33. sage/categories/covariant_functorial_construction.py +700 -0
  34. sage/categories/facade_sets.py +228 -0
  35. sage/categories/functor.cp314-win_amd64.pyd +0 -0
  36. sage/categories/functor.pxd +7 -0
  37. sage/categories/functor.pyx +659 -0
  38. sage/categories/homset.py +1289 -0
  39. sage/categories/homsets.py +364 -0
  40. sage/categories/isomorphic_objects.py +73 -0
  41. sage/categories/map.cp314-win_amd64.pyd +0 -0
  42. sage/categories/map.pxd +34 -0
  43. sage/categories/map.pyx +2106 -0
  44. sage/categories/morphism.cp314-win_amd64.pyd +0 -0
  45. sage/categories/morphism.pxd +14 -0
  46. sage/categories/morphism.pyx +895 -0
  47. sage/categories/objects.py +167 -0
  48. sage/categories/primer.py +1695 -0
  49. sage/categories/pushout.py +4847 -0
  50. sage/categories/quotients.py +64 -0
  51. sage/categories/realizations.py +200 -0
  52. sage/categories/sets_cat.py +3305 -0
  53. sage/categories/sets_with_partial_maps.py +52 -0
  54. sage/categories/subobjects.py +64 -0
  55. sage/categories/subquotients.py +21 -0
  56. sage/categories/with_realizations.py +311 -0
  57. sage/cpython/__init__.py +22 -0
  58. sage/cpython/_py2_random.py +619 -0
  59. sage/cpython/all.py +3 -0
  60. sage/cpython/atexit.cp314-win_amd64.pyd +0 -0
  61. sage/cpython/atexit.pyx +269 -0
  62. sage/cpython/builtin_types.cp314-win_amd64.pyd +0 -0
  63. sage/cpython/builtin_types.pyx +7 -0
  64. sage/cpython/cython_metaclass.cp314-win_amd64.pyd +0 -0
  65. sage/cpython/cython_metaclass.h +117 -0
  66. sage/cpython/cython_metaclass.pxd +3 -0
  67. sage/cpython/cython_metaclass.pyx +130 -0
  68. sage/cpython/debug.cp314-win_amd64.pyd +0 -0
  69. sage/cpython/debug.pyx +302 -0
  70. sage/cpython/dict_del_by_value.cp314-win_amd64.pyd +0 -0
  71. sage/cpython/dict_del_by_value.pxd +9 -0
  72. sage/cpython/dict_del_by_value.pyx +191 -0
  73. sage/cpython/dict_internal.h +80 -0
  74. sage/cpython/getattr.cp314-win_amd64.pyd +0 -0
  75. sage/cpython/getattr.pxd +9 -0
  76. sage/cpython/getattr.pyx +439 -0
  77. sage/cpython/pycore_long.h +97 -0
  78. sage/cpython/pycore_long.pxd +10 -0
  79. sage/cpython/python_debug.h +44 -0
  80. sage/cpython/python_debug.pxd +47 -0
  81. sage/cpython/pyx_visit.h +13 -0
  82. sage/cpython/string.cp314-win_amd64.pyd +0 -0
  83. sage/cpython/string.pxd +76 -0
  84. sage/cpython/string.pyx +34 -0
  85. sage/cpython/string_impl.h +60 -0
  86. sage/cpython/type.cp314-win_amd64.pyd +0 -0
  87. sage/cpython/type.pxd +2 -0
  88. sage/cpython/type.pyx +40 -0
  89. sage/cpython/wrapperdescr.pxd +67 -0
  90. sage/ext/all__sagemath_objects.py +3 -0
  91. sage/ext/ccobject.h +64 -0
  92. sage/ext/cplusplus.pxd +17 -0
  93. sage/ext/mod_int.h +30 -0
  94. sage/ext/mod_int.pxd +24 -0
  95. sage/ext/stdsage.pxd +39 -0
  96. sage/groups/all__sagemath_objects.py +1 -0
  97. sage/groups/group.cp314-win_amd64.pyd +0 -0
  98. sage/groups/group.pxd +14 -0
  99. sage/groups/group.pyx +296 -0
  100. sage/groups/old.cp314-win_amd64.pyd +0 -0
  101. sage/groups/old.pxd +14 -0
  102. sage/groups/old.pyx +219 -0
  103. sage/libs/all__sagemath_objects.py +3 -0
  104. sage/libs/gmp/__init__.py +1 -0
  105. sage/libs/gmp/all.pxd +6 -0
  106. sage/libs/gmp/binop.pxd +23 -0
  107. sage/libs/gmp/misc.pxd +8 -0
  108. sage/libs/gmp/mpf.pxd +88 -0
  109. sage/libs/gmp/mpn.pxd +57 -0
  110. sage/libs/gmp/mpq.pxd +57 -0
  111. sage/libs/gmp/mpz.pxd +202 -0
  112. sage/libs/gmp/pylong.cp314-win_amd64.pyd +0 -0
  113. sage/libs/gmp/pylong.pxd +12 -0
  114. sage/libs/gmp/pylong.pyx +150 -0
  115. sage/libs/gmp/random.pxd +25 -0
  116. sage/libs/gmp/randomize.pxd +59 -0
  117. sage/libs/gmp/types.pxd +53 -0
  118. sage/libs/gmpxx.pxd +19 -0
  119. sage/misc/abstract_method.py +276 -0
  120. sage/misc/all__sagemath_objects.py +43 -0
  121. sage/misc/bindable_class.py +253 -0
  122. sage/misc/c3_controlled.cp314-win_amd64.pyd +0 -0
  123. sage/misc/c3_controlled.pxd +2 -0
  124. sage/misc/c3_controlled.pyx +1402 -0
  125. sage/misc/cachefunc.cp314-win_amd64.pyd +0 -0
  126. sage/misc/cachefunc.pxd +43 -0
  127. sage/misc/cachefunc.pyx +3801 -0
  128. sage/misc/call.py +188 -0
  129. sage/misc/classcall_metaclass.cp314-win_amd64.pyd +0 -0
  130. sage/misc/classcall_metaclass.pxd +14 -0
  131. sage/misc/classcall_metaclass.pyx +599 -0
  132. sage/misc/constant_function.cp314-win_amd64.pyd +0 -0
  133. sage/misc/constant_function.pyx +130 -0
  134. sage/misc/decorators.py +739 -0
  135. sage/misc/fast_methods.cp314-win_amd64.pyd +0 -0
  136. sage/misc/fast_methods.pxd +20 -0
  137. sage/misc/fast_methods.pyx +351 -0
  138. sage/misc/flatten.py +90 -0
  139. sage/misc/fpickle.cp314-win_amd64.pyd +0 -0
  140. sage/misc/fpickle.pyx +176 -0
  141. sage/misc/function_mangling.cp314-win_amd64.pyd +0 -0
  142. sage/misc/function_mangling.pxd +11 -0
  143. sage/misc/function_mangling.pyx +308 -0
  144. sage/misc/inherit_comparison.cp314-win_amd64.pyd +0 -0
  145. sage/misc/inherit_comparison.pxd +5 -0
  146. sage/misc/inherit_comparison.pyx +105 -0
  147. sage/misc/instancedoc.cp314-win_amd64.pyd +0 -0
  148. sage/misc/instancedoc.pyx +331 -0
  149. sage/misc/lazy_attribute.cp314-win_amd64.pyd +0 -0
  150. sage/misc/lazy_attribute.pyx +607 -0
  151. sage/misc/lazy_format.py +132 -0
  152. sage/misc/lazy_import.cp314-win_amd64.pyd +0 -0
  153. sage/misc/lazy_import.pxd +13 -0
  154. sage/misc/lazy_import.pyx +1307 -0
  155. sage/misc/lazy_import_cache.py +36 -0
  156. sage/misc/lazy_list.cp314-win_amd64.pyd +0 -0
  157. sage/misc/lazy_list.pxd +19 -0
  158. sage/misc/lazy_list.pyx +1187 -0
  159. sage/misc/lazy_string.cp314-win_amd64.pyd +0 -0
  160. sage/misc/lazy_string.pxd +7 -0
  161. sage/misc/lazy_string.pyx +546 -0
  162. sage/misc/misc.py +980 -0
  163. sage/misc/misc_c.cp314-win_amd64.pyd +0 -0
  164. sage/misc/misc_c.pxd +3 -0
  165. sage/misc/misc_c.pyx +765 -0
  166. sage/misc/namespace_package.py +37 -0
  167. sage/misc/nested_class.cp314-win_amd64.pyd +0 -0
  168. sage/misc/nested_class.pxd +3 -0
  169. sage/misc/nested_class.pyx +394 -0
  170. sage/misc/persist.cp314-win_amd64.pyd +0 -0
  171. sage/misc/persist.pyx +1279 -0
  172. sage/misc/prandom.py +418 -0
  173. sage/misc/randstate.cp314-win_amd64.pyd +0 -0
  174. sage/misc/randstate.pxd +31 -0
  175. sage/misc/randstate.pyx +1096 -0
  176. sage/misc/repr.py +203 -0
  177. sage/misc/reset.cp314-win_amd64.pyd +0 -0
  178. sage/misc/reset.pyx +196 -0
  179. sage/misc/sage_ostools.cp314-win_amd64.pyd +0 -0
  180. sage/misc/sage_ostools.pyx +323 -0
  181. sage/misc/sage_timeit.py +275 -0
  182. sage/misc/sage_timeit_class.cp314-win_amd64.pyd +0 -0
  183. sage/misc/sage_timeit_class.pyx +120 -0
  184. sage/misc/sage_unittest.py +639 -0
  185. sage/misc/sageinspect.py +2792 -0
  186. sage/misc/session.cp314-win_amd64.pyd +0 -0
  187. sage/misc/session.pyx +392 -0
  188. sage/misc/superseded.py +576 -0
  189. sage/misc/test_nested_class.py +228 -0
  190. sage/misc/timing.py +264 -0
  191. sage/misc/unknown.py +222 -0
  192. sage/misc/verbose.py +253 -0
  193. sage/misc/weak_dict.cp314-win_amd64.pyd +0 -0
  194. sage/misc/weak_dict.pxd +15 -0
  195. sage/misc/weak_dict.pyx +1197 -0
  196. sage/modules/all__sagemath_objects.py +1 -0
  197. sage/modules/module.cp314-win_amd64.pyd +0 -0
  198. sage/modules/module.pxd +5 -0
  199. sage/modules/module.pyx +329 -0
  200. sage/rings/all__sagemath_objects.py +3 -0
  201. sage/rings/integer_fake.h +22 -0
  202. sage/rings/integer_fake.pxd +55 -0
  203. sage/rings/integer_fake.pyi +8 -0
  204. sage/sets/all__sagemath_objects.py +3 -0
  205. sage/sets/pythonclass.cp314-win_amd64.pyd +0 -0
  206. sage/sets/pythonclass.pxd +9 -0
  207. sage/sets/pythonclass.pyx +247 -0
  208. sage/structure/__init__.py +13 -0
  209. sage/structure/all.py +30 -0
  210. sage/structure/category_object.cp314-win_amd64.pyd +0 -0
  211. sage/structure/category_object.pxd +28 -0
  212. sage/structure/category_object.pyx +1090 -0
  213. sage/structure/coerce.cp314-win_amd64.pyd +0 -0
  214. sage/structure/coerce.pxd +44 -0
  215. sage/structure/coerce.pyx +2113 -0
  216. sage/structure/coerce_actions.cp314-win_amd64.pyd +0 -0
  217. sage/structure/coerce_actions.pxd +27 -0
  218. sage/structure/coerce_actions.pyx +988 -0
  219. sage/structure/coerce_dict.cp314-win_amd64.pyd +0 -0
  220. sage/structure/coerce_dict.pxd +51 -0
  221. sage/structure/coerce_dict.pyx +1557 -0
  222. sage/structure/coerce_exceptions.py +23 -0
  223. sage/structure/coerce_maps.cp314-win_amd64.pyd +0 -0
  224. sage/structure/coerce_maps.pxd +24 -0
  225. sage/structure/coerce_maps.pyx +656 -0
  226. sage/structure/debug_options.cp314-win_amd64.pyd +0 -0
  227. sage/structure/debug_options.pxd +6 -0
  228. sage/structure/debug_options.pyx +54 -0
  229. sage/structure/dynamic_class.py +541 -0
  230. sage/structure/element.cp314-win_amd64.pyd +0 -0
  231. sage/structure/element.pxd +271 -0
  232. sage/structure/element.pyx +4584 -0
  233. sage/structure/element_wrapper.cp314-win_amd64.pyd +0 -0
  234. sage/structure/element_wrapper.pxd +12 -0
  235. sage/structure/element_wrapper.pyx +582 -0
  236. sage/structure/factorization.py +1457 -0
  237. sage/structure/factorization_integer.py +154 -0
  238. sage/structure/factory.cp314-win_amd64.pyd +0 -0
  239. sage/structure/factory.pyx +863 -0
  240. sage/structure/formal_sum.py +489 -0
  241. sage/structure/gens_py.py +73 -0
  242. sage/structure/global_options.py +1725 -0
  243. sage/structure/indexed_generators.py +863 -0
  244. sage/structure/list_clone.cp314-win_amd64.pyd +0 -0
  245. sage/structure/list_clone.pxd +65 -0
  246. sage/structure/list_clone.pyx +1867 -0
  247. sage/structure/list_clone_demo.cp314-win_amd64.pyd +0 -0
  248. sage/structure/list_clone_demo.pyx +248 -0
  249. sage/structure/list_clone_timings.py +179 -0
  250. sage/structure/list_clone_timings_cy.cp314-win_amd64.pyd +0 -0
  251. sage/structure/list_clone_timings_cy.pyx +86 -0
  252. sage/structure/mutability.cp314-win_amd64.pyd +0 -0
  253. sage/structure/mutability.pxd +21 -0
  254. sage/structure/mutability.pyx +346 -0
  255. sage/structure/nonexact.py +69 -0
  256. sage/structure/parent.cp314-win_amd64.pyd +0 -0
  257. sage/structure/parent.pxd +112 -0
  258. sage/structure/parent.pyx +3087 -0
  259. sage/structure/parent_base.cp314-win_amd64.pyd +0 -0
  260. sage/structure/parent_base.pxd +13 -0
  261. sage/structure/parent_base.pyx +35 -0
  262. sage/structure/parent_gens.cp314-win_amd64.pyd +0 -0
  263. sage/structure/parent_gens.pxd +22 -0
  264. sage/structure/parent_gens.pyx +374 -0
  265. sage/structure/parent_old.cp314-win_amd64.pyd +0 -0
  266. sage/structure/parent_old.pxd +24 -0
  267. sage/structure/parent_old.pyx +278 -0
  268. sage/structure/proof/__init__.py +1 -0
  269. sage/structure/proof/all.py +243 -0
  270. sage/structure/proof/proof.py +300 -0
  271. sage/structure/richcmp.cp314-win_amd64.pyd +0 -0
  272. sage/structure/richcmp.pxd +212 -0
  273. sage/structure/richcmp.pyx +494 -0
  274. sage/structure/sage_object.cp314-win_amd64.pyd +0 -0
  275. sage/structure/sage_object.pxd +3 -0
  276. sage/structure/sage_object.pyx +1088 -0
  277. sage/structure/sage_object_test.py +19 -0
  278. sage/structure/sequence.py +937 -0
  279. sage/structure/set_factories.py +1178 -0
  280. sage/structure/set_factories_example.py +527 -0
  281. sage/structure/support_view.py +164 -0
  282. sage/structure/test_factory.py +56 -0
  283. sage/structure/unique_representation.py +1443 -0
@@ -0,0 +1,863 @@
1
+ # sage_setup: distribution = sagemath-objects
2
+ r"""
3
+ Factory for cached representations
4
+
5
+ Using a :class:`UniqueFactory` is one way of implementing a *cached
6
+ representation behaviour*. In spite of its name, using a
7
+ :class:`UniqueFactory` is not enough to ensure the *unique representation
8
+ behaviour*. See :mod:`~sage.structure.unique_representation` for a
9
+ detailed explanation.
10
+
11
+ With a :class:`UniqueFactory`, one can preprocess the given arguments. There
12
+ is special support for specifying a subset of the arguments that serve as the
13
+ unique key, so that still *all* given arguments are used to create a new
14
+ instance, but only the specified subset is used to look up in the
15
+ cache. Typically, this is used to construct objects that accept an optional
16
+ ``check=[True|False]`` argument, but whose result should be unique
17
+ regardless of said optional argument. (This use case should be handled with
18
+ care, though: Any checking which isn't done in the ``create_key`` or
19
+ ``create_key_and_extra_args`` method will be done only when a new object is
20
+ generated, but not when a cached object is retrieved from cache.
21
+ Consequently, if the factory is once called with ``check=False``, a
22
+ subsequent call with ``check=True`` cannot be expected to perform all checks
23
+ unless these checks are all in the ``create_key`` or
24
+ ``create_key_and_extra_args`` method.)
25
+
26
+ For a class derived from
27
+ :class:`~sage.structure.unique_representation.CachedRepresentation`, argument
28
+ preprocessing can be obtained by providing a custom static ``__classcall__``
29
+ or ``__classcall_private__`` method, but this seems less transparent. When
30
+ argument preprocessing is not needed or the preprocess is not very
31
+ sophisticated, then generally
32
+ :class:`~sage.structure.unique_representation.CachedRepresentation` is much
33
+ easier to use than a factory.
34
+
35
+ .. SEEALSO::
36
+
37
+ :mod:`sage.structure.unique_representation`
38
+
39
+ AUTHORS:
40
+
41
+ - Robert Bradshaw (2008): initial version
42
+ - Simon King (2013): extended documentation
43
+ - Julian Rueth (2014-05-09): use ``_cache_key`` if parameters are unhashable
44
+ - Kwankyu Lee (2025-10): added support for ``do_pickle=True`` for cached methods
45
+ """
46
+ #*****************************************************************************
47
+ # Copyright (C) 2008 Robert Bradshaw <robertwb@math.washington.edu>
48
+ # 2014 Julian Rueth <julian.rueth@fsfe.org>
49
+ #
50
+ # This program is free software: you can redistribute it and/or modify
51
+ # it under the terms of the GNU General Public License as published by
52
+ # the Free Software Foundation, either version 2 of the License, or
53
+ # (at your option) any later version.
54
+ # http://www.gnu.org/licenses/
55
+ #*****************************************************************************
56
+
57
+ import types
58
+
59
+ from sage.structure.sage_object cimport SageObject
60
+
61
+ cdef sage_version = None
62
+ from sage.cpython.string cimport bytes_to_str
63
+
64
+ cimport sage.misc.weak_dict
65
+ from sage.misc.cachefunc cimport cache_key as _cache_key
66
+
67
+
68
+ cdef class UniqueFactory(SageObject):
69
+ """
70
+ This class is intended to make it easy to cache objects.
71
+
72
+ It is based on the idea that the object is uniquely defined by a set of
73
+ defining data (the key). There is also the possibility of some
74
+ non-defining data (extra args) which will be used in initial creation,
75
+ but not affect the caching.
76
+
77
+ .. WARNING::
78
+
79
+ This class only provides *cached representation behaviour*. Hence,
80
+ using :class:`UniqueFactory`, it is still possible to create distinct
81
+ objects that evaluate equal. Unique representation behaviour can be
82
+ added, for example, by additionally inheriting from
83
+ :class:`sage.misc.fast_methods.WithEqualityById`.
84
+
85
+ The objects created are cached (using weakrefs) based on their key and
86
+ returned directly rather than re-created if requested again. Pickling is
87
+ taken care of by the factory, and will return the same object for the same
88
+ version of Sage, and distinct (but hopefully equal) objects for different
89
+ versions of Sage.
90
+
91
+ .. WARNING::
92
+
93
+ The objects returned by a :class:`UniqueFactory` must be instances of
94
+ new style classes (hence, they must be instances of :class:`object`)
95
+ that must not only allow a weak reference, but must accept general
96
+ attribute assignment. Otherwise, pickling won't work.
97
+
98
+ USAGE:
99
+
100
+ A *unique factory* provides a way to create objects from parameters
101
+ (the type of these objects can depend on the parameters, and is often
102
+ determined only at runtime) and to cache them by a certain key
103
+ derived from these parameters, so that when the factory is being
104
+ called again with the same parameters (or just with parameters which
105
+ yield the same key), the object is being returned from cache rather
106
+ than constructed anew.
107
+
108
+ An implementation of a unique factory consists of a factory class and
109
+ an instance of this factory class.
110
+
111
+ The factory class has to be a class inheriting from ``UniqueFactory``.
112
+ Typically it only needs to implement :meth:`create_key` (a method that
113
+ creates a key from the given parameters, under which key the object
114
+ will be stored in the cache) and :meth:`create_object` (a method that
115
+ returns the actual object from the key). Sometimes, one would also
116
+ implement :meth:`create_key_and_extra_args` (this differs from
117
+ :meth:`create_key` in allowing to also create some additional
118
+ arguments from the given parameters, which arguments then get passed
119
+ to :meth:`create_object` and thus can have an effect on the initial
120
+ creation of the object, but do *not* affect the key) or
121
+ :meth:`other_keys`. Other methods are not supposed to be overloaded.
122
+
123
+ The factory class itself cannot be called to create objects. Instead,
124
+ an instance of the factory class has to be created first. For
125
+ technical reasons, this instance has to be provided with a name that
126
+ allows Sage to find its definition. Specifically, the name of the
127
+ factory instance (or the full path to it, if it is not in the global
128
+ namespace) has to be passed to the factory class as a string variable.
129
+ So, if our factory class has been called ``A`` and is located in
130
+ ``sage/spam/battletoads.py``, then we need to define an instance (say,
131
+ ``B``) of ``A`` by writing ``B = A("sage.spam.battletoads.B")``
132
+ (or ``B = A("B")`` if this ``B`` will be imported into global
133
+ namespace). This instance can then be used to create objects (by
134
+ calling ``B(*parameters)``).
135
+
136
+ Notice that the objects created by the factory don't inherit from the
137
+ factory class. They *do* know about the factory that created them (this
138
+ information, along with the keys under which this factory caches them,
139
+ is stored in the ``_factory_data`` attributes of the objects), but not
140
+ via inheritance.
141
+
142
+ EXAMPLES:
143
+
144
+ The below examples are rather artificial and illustrate particular
145
+ aspects. For a "real-life" usage case of ``UniqueFactory``, see
146
+ the finite field factory in :mod:`sage.rings.finite_rings.finite_field_constructor`.
147
+
148
+ In many cases, a factory class is implemented by providing the two
149
+ methods :meth:`create_key` and :meth:`create_object`. In our example,
150
+ we want to demonstrate how to use "extra arguments" to choose a specific
151
+ implementation, with preference given to an instance found in the cache,
152
+ even if its implementation is different. Hence, we implement
153
+ :meth:`create_key_and_extra_args` rather than :meth:`create_key`, putting
154
+ the chosen implementation into the extra arguments. Then, in the
155
+ :meth:`create_object` method, we create and return instances of the
156
+ specified implementation.
157
+ ::
158
+
159
+ sage: from sage.structure.factory import UniqueFactory
160
+ sage: class MyFactory(UniqueFactory):
161
+ ....: def create_key_and_extra_args(self, *args, **kwds):
162
+ ....: return args, {'impl':kwds.get('impl', None)}
163
+ ....: def create_object(self, version, key, **extra_args):
164
+ ....: impl = extra_args['impl']
165
+ ....: if impl == 'C':
166
+ ....: return C(*key)
167
+ ....: return D(*key)
168
+ ....:
169
+
170
+ Now we can create a factory instance. It is supposed to be found under the
171
+ name ``'F'`` in the ``__main__`` module. Note that in an interactive
172
+ session, ``F`` would automatically be in the ``__main__`` module. Hence,
173
+ the second and third of the following four lines are only needed in
174
+ doctests. ::
175
+
176
+ sage: F = MyFactory("__main__.F")
177
+ sage: import __main__
178
+ sage: __main__.F = F
179
+ sage: loads(dumps(F)) is F
180
+ True
181
+
182
+ Now we create two classes ``C`` and ``D``. The first is a Cython
183
+ extension-type class that does not allow weak references nor attribute
184
+ assignment. The second is a Python class, that is derived from
185
+ :class:`object`. ::
186
+
187
+ sage: cython("cdef class C: pass") # needs sage.misc.cython
188
+ sage: class D:
189
+ ....: def __init__(self, *args):
190
+ ....: self.t = args
191
+ ....: def __repr__(self):
192
+ ....: return "D%s"%repr(self.t)
193
+ ....:
194
+
195
+ Again, being in a doctest, we need to put the class ``D`` into the
196
+ ``__main__`` module, so that Python can find it::
197
+
198
+ sage: import __main__
199
+ sage: __main__.D = D
200
+
201
+ It is impossible to create an instance of ``C`` with our factory, since it
202
+ does not allow weak references::
203
+
204
+ sage: F(1, impl='C') # needs sage.misc.cython
205
+ Traceback (most recent call last):
206
+ ...
207
+ TypeError: cannot create weak reference to '....C' object
208
+
209
+ Let us try again, with a Cython class that does allow weak
210
+ references. Now, creation of an instance using the factory works::
211
+
212
+ sage: cython( # needs sage.misc.cython
213
+ ....: '''
214
+ ....: cdef class C:
215
+ ....: cdef __weakref__
216
+ ....: ''')
217
+ ....:
218
+ sage: c = F(1, impl='C') # needs sage.misc.cython
219
+ sage: isinstance(c, C) # needs sage.misc.cython
220
+ True
221
+
222
+ The cache is used when calling the factory again---even if it is suggested
223
+ to use a different implementation. This is because the implementation is
224
+ only considered an "extra argument" that does not count for the key.
225
+ ::
226
+
227
+ sage: c is F(1, impl='C') is F(1, impl='D') is F(1) # needs sage.misc.cython
228
+ True
229
+
230
+ However, pickling and unpickling does not use the cache. This is because
231
+ the factory has tried to assign an attribute to the instance that provides
232
+ information on the key used to create the instance, but failed::
233
+
234
+ sage: loads(dumps(c)) is c # needs sage.misc.cython
235
+ False
236
+ sage: hasattr(c, '_factory_data') # needs sage.misc.cython
237
+ False
238
+
239
+ We have already seen that our factory will only take the requested
240
+ implementation into account if the arguments used as key have not been used
241
+ yet. So, we use other arguments to create an instance of class ``D``. As
242
+ the class can be weak-referenced and allows for attribute assignment,
243
+ everything works::
244
+
245
+ sage: d = F(2, impl='D')
246
+ sage: isinstance(d, D)
247
+ True
248
+ sage: loads(dumps(d)) is d
249
+ True
250
+ sage: d._factory_data
251
+ (<__main__.MyFactory object at ...>,
252
+ (...),
253
+ (2,),
254
+ {'impl': 'D'})
255
+
256
+ When an object constructed by a factory is pickled, the content of
257
+ ``__dict__`` is not put into the pickle since unpickling either restores
258
+ the object from the cache or reconstructs the object afresh. This defeats
259
+ methods decorated with ``@cached_method(do_pickle=True)``. Hence
260
+ ``UniqueFactory`` makes exceptions to the placeholders for such methods::
261
+
262
+ sage: # needs sage.rings.function_field
263
+ sage: K.<x> = FunctionField(QQ); R.<y> = K[]
264
+ sage: F = K.extension(y^5 - x^3 - 3*x + x*y)
265
+ sage: F.genus()
266
+ 4
267
+ sage: type(F.genus)
268
+ <class 'sage.misc.cachefunc.CachedMethodCallerNoArgs'>
269
+ sage: F.genus.is_pickled_with_cache()
270
+ True
271
+ sage: s = dumps(F)
272
+ sage: F.genus.clear_cache()
273
+ sage: Fp = loads(s)
274
+ sage: Fp is F
275
+ True
276
+ sage: Fp.genus.cache
277
+ 4
278
+ """
279
+ cdef readonly _name
280
+ cdef readonly _cache
281
+
282
+ def __init__(self, name):
283
+ """
284
+ INPUT:
285
+
286
+ - ``name`` -- string; a name in the global namespace referring to
287
+ ``self`` or a fully qualified path name to ``self``, which is used to
288
+ locate the factory on unpickling
289
+
290
+ EXAMPLES::
291
+
292
+ sage: from sage.structure.factory import UniqueFactory
293
+ sage: fake_factory = UniqueFactory('ZZ')
294
+ sage: loads(dumps(fake_factory))
295
+ Integer Ring
296
+ sage: fake_factory = UniqueFactory('sage.rings.rational_field.QQ')
297
+ sage: loads(dumps(fake_factory))
298
+ Rational Field
299
+ """
300
+ self._name = name
301
+ self._cache = sage.misc.weak_dict.WeakValueDictionary()
302
+
303
+ def __reduce__(self):
304
+ """
305
+ EXAMPLES::
306
+
307
+ sage: A = FiniteField(127)
308
+ sage: A is loads(dumps(A)) # indirect doctest
309
+ True
310
+
311
+ sage: # needs sage.rings.finite_rings
312
+ sage: B = FiniteField(3^3,'b')
313
+ sage: B is loads(dumps(B))
314
+ True
315
+ sage: C = FiniteField(2^16,'c')
316
+ sage: C is loads(dumps(C))
317
+ True
318
+ sage: D = FiniteField(3^20,'d')
319
+ sage: D is loads(dumps(D))
320
+ True
321
+
322
+ TESTS::
323
+
324
+ sage: loads(dumps(FiniteField)) is FiniteField
325
+ True
326
+ sage: from sage.structure.test_factory import test_factory
327
+ sage: loads(dumps(test_factory)) is test_factory
328
+ True
329
+ """
330
+ return lookup_global, (self._name,)
331
+
332
+ def __call__(self, *args, **kwds):
333
+ """
334
+ This is the method invoked to create objects. It first creates a key
335
+ from the given parameters, then if an object with that key already
336
+ exists returns it, and otherwise creates one and stores a weak reference
337
+ to it in its dictionary.
338
+
339
+ Do not override this method. Instead, override ``create_key`` and
340
+ ``create_object`` and put the docstring in the body of the class.
341
+
342
+ EXAMPLES::
343
+
344
+ sage: from sage.structure.test_factory import test_factory
345
+ sage: _ = test_factory(1,2,3); _
346
+ Making object (1, 2, 3)
347
+ <sage.structure.test_factory.A object at ...>
348
+
349
+ It already created one, so don't re-create::
350
+
351
+ sage: test_factory(1,2,3)
352
+ <sage.structure.test_factory.A object at ...>
353
+ sage: test_factory(1,2,3) is test_factory(1,2,3)
354
+ True
355
+
356
+ Of course, with a different key, a new object will be created::
357
+
358
+ sage: test_factory(1,2,3) is test_factory(1,2,4)
359
+ Making object (1, 2, 4)
360
+ False
361
+ """
362
+ key, kwds = self.create_key_and_extra_args(*args, **kwds)
363
+ version = self.get_version(sage_version)
364
+ return self.get_object(version, key, kwds)
365
+
366
+ cpdef get_object(self, version, key, extra_args):
367
+ """
368
+ Return the object corresponding to ``key``, creating it with
369
+ ``extra_args`` if necessary (for example, it isn't in the cache
370
+ or it is unpickling from an older version of Sage).
371
+
372
+ EXAMPLES::
373
+
374
+ sage: from sage.structure.test_factory import test_factory
375
+ sage: a = test_factory.get_object(3.0, 'a', {}); a
376
+ Making object a
377
+ <sage.structure.test_factory.A object at ...>
378
+ sage: test_factory.get_object(3.0, 'a', {}) is test_factory.get_object(3.0, 'a', {})
379
+ True
380
+ sage: test_factory.get_object(3.0, 'a', {}) is test_factory.get_object(3.1, 'a', {})
381
+ Making object a
382
+ False
383
+ sage: test_factory.get_object(3.0, 'a', {}) is test_factory.get_object(3.0, 'b', {})
384
+ Making object b
385
+ False
386
+
387
+ TESTS:
388
+
389
+ Check that :issue:`16317` has been fixed, i.e., caching works for
390
+ unhashable objects::
391
+
392
+ sage: K.<u> = Qq(4) # needs sage.rings.padics
393
+ sage: d = test_factory.get_object(3.0, (K(1), 'c'), {}) # needs sage.rings.padics
394
+ Making object (1 + O(2^20), 'c')
395
+ sage: d is test_factory.get_object(3.0, (K(1), 'c'), {}) # needs sage.rings.padics
396
+ True
397
+ """
398
+ cache_key = key
399
+ try:
400
+ try:
401
+ return self._cache[version, cache_key]
402
+ except TypeError: # key is unhashable
403
+ cache_key = _cache_key(cache_key)
404
+ return self._cache[version, cache_key]
405
+ except KeyError:
406
+ pass
407
+ obj = self.create_object(version, key, **extra_args)
408
+ self._cache[version, cache_key] = obj
409
+ try:
410
+ for key in self.other_keys(key, obj):
411
+ try:
412
+ self._cache[version, key] = obj
413
+ except TypeError: # key is unhashable
414
+ self._cache[version, _cache_key(key)] = obj
415
+ obj._factory_data = self, version, key, extra_args
416
+
417
+ # Install a custom __reduce__ method on the instance "obj"
418
+ # that we just created. We only do this if the class of
419
+ # "obj" has a generic __reduce__ method, which is either
420
+ # object.__reduce__ or __reduce_cython__, the
421
+ # auto-generated pickling function for Cython.
422
+ f = obj.__class__.__reduce__
423
+ if f.__objclass__ is object or f.__name__ == "__reduce_cython__":
424
+ obj.__reduce_ex__ = types.MethodType(generic_factory_reduce, obj)
425
+ # Install a custom __setstate__ method to reinstate unpickled state data
426
+ obj.__setstate__ = types.MethodType(generic_factory_setstate, obj)
427
+ except AttributeError:
428
+ pass
429
+ return obj
430
+
431
+ cpdef get_version(self, sage_version):
432
+ """
433
+ This is provided to allow more or less granular control over
434
+ pickle versioning. Objects pickled in the same version of Sage
435
+ will unpickle to the same rather than simply equal objects. This
436
+ can provide significant gains as arithmetic must be performed on
437
+ objects with identical parents. However, if there has been an
438
+ incompatible change (e.g. in element representation) we want the
439
+ version number to change so coercion is forced between the two
440
+ parents.
441
+
442
+ Defaults to the Sage version that is passed in, but coarser
443
+ granularity can be provided.
444
+
445
+ EXAMPLES::
446
+
447
+ sage: from sage.structure.test_factory import test_factory
448
+ sage: test_factory.get_version((3,1,0))
449
+ (3, 1, 0)
450
+ """
451
+ global sage_version
452
+ if sage_version is None:
453
+ from sage.version import version as sage_version
454
+ sage_version = sage_version.split('.')
455
+ for i in range(len(sage_version)):
456
+ try:
457
+ sage_version[i] = int(sage_version[i])
458
+ except ValueError:
459
+ pass
460
+ sage_version = tuple(sage_version)
461
+ return sage_version
462
+
463
+ def create_key_and_extra_args(self, *args, **kwds):
464
+ r"""
465
+ Return a tuple containing the key (uniquely defining data)
466
+ and any extra arguments (empty by default).
467
+
468
+ Defaults to :meth:`create_key`.
469
+
470
+ EXAMPLES::
471
+
472
+ sage: from sage.structure.test_factory import test_factory
473
+ sage: test_factory.create_key_and_extra_args(1, 2, key=5)
474
+ ((1, 2), {})
475
+ sage: GF.create_key_and_extra_args(3)
476
+ ((3, ('x',), None, 'modn', 3, 1, True, None, None, None, True, False), {})
477
+ """
478
+ return self.create_key(*args, **kwds), {}
479
+
480
+ def create_key(self, *args, **kwds):
481
+ """
482
+ Given the parameters (arguments and keywords), create a key
483
+ that uniquely determines this object.
484
+
485
+ EXAMPLES::
486
+
487
+ sage: from sage.structure.test_factory import test_factory
488
+ sage: test_factory.create_key(1, 2, key=5)
489
+ (1, 2)
490
+ """
491
+ raise NotImplementedError
492
+
493
+ def create_object(self, version, key, **extra_args):
494
+ """
495
+ Create the object from the key and extra arguments. This is only
496
+ called if the object was not found in the cache.
497
+
498
+ EXAMPLES::
499
+
500
+ sage: from sage.structure.test_factory import test_factory
501
+ sage: test_factory.create_object(0, (1,2,3))
502
+ Making object (1, 2, 3)
503
+ <sage.structure.test_factory.A object at ...>
504
+ sage: test_factory('a')
505
+ Making object ('a',)
506
+ <sage.structure.test_factory.A object at ...>
507
+ sage: test_factory('a') # NOT called again
508
+ <sage.structure.test_factory.A object at ...>
509
+ """
510
+ raise NotImplementedError
511
+
512
+ cpdef other_keys(self, key, obj):
513
+ """
514
+ Sometimes during object creation, certain defaults are chosen which
515
+ may result in a new (more specific) key. This allows the more specific
516
+ key to be regarded as equivalent to the original key returned by
517
+ :meth:`create_key` for the purpose of lookup in the cache, and is used
518
+ for pickling.
519
+
520
+ EXAMPLES:
521
+
522
+ The ``GF`` factory used to have a custom :meth:`other_keys`
523
+ method, but this was removed in :issue:`16934`::
524
+
525
+ sage: # needs sage.libs.linbox sage.rings.finite_rings
526
+ sage: key, _ = GF.create_key_and_extra_args(27, 'k'); key
527
+ (27, ('k',), x^3 + 2*x + 1, 'givaro', 3, 3, True, None, 'poly', True, True, True)
528
+ sage: K = GF.create_object(0, key); K
529
+ Finite Field in k of size 3^3
530
+ sage: GF.other_keys(key, K)
531
+ []
532
+
533
+ sage: K = GF(7^40, 'a') # needs sage.rings.finite_rings
534
+ sage: loads(dumps(K)) is K # needs sage.rings.finite_rings
535
+ True
536
+ """
537
+ return []
538
+
539
+ cpdef reduce_data(self, obj):
540
+ """
541
+ The results of this function can be returned from
542
+ :meth:`__reduce__`. This is here so the factory internals can
543
+ change without having to re-write :meth:`__reduce__` methods
544
+ that use it.
545
+
546
+ EXAMPLES::
547
+
548
+ sage: # needs sage.modules
549
+ sage: from sage.modules.free_module import FreeModuleFactory_with_standard_basis as F
550
+ sage: V = F(ZZ, 5)
551
+ sage: factory, data = F.reduce_data(V)
552
+ sage: factory(*data)
553
+ Ambient free module of rank 5 over the principal ideal domain Integer Ring
554
+ sage: factory(*data) is V
555
+ True
556
+
557
+ sage: from sage.structure.test_factory import test_factory
558
+ sage: a = test_factory(1, 2)
559
+ Making object (1, 2)
560
+ sage: test_factory.reduce_data(a)
561
+ (<cyfunction generic_factory_unpickle at ...>,
562
+ (<sage.structure.test_factory.UniqueFactoryTester object at ...>,
563
+ (...),
564
+ (1, 2),
565
+ {}))
566
+
567
+ Note that the ellipsis ``(...)`` here stands for the Sage
568
+ version.
569
+ """
570
+ d = generic_factory_getstate(obj)
571
+ if d:
572
+ return generic_factory_unpickle, obj._factory_data, d
573
+ else:
574
+ return generic_factory_unpickle, obj._factory_data
575
+
576
+
577
+ # This is used to handle old UniqueFactory pickles
578
+ factory_unpickles = {}
579
+
580
+
581
+ def register_factory_unpickle(name, callable):
582
+ """
583
+ Register a callable to handle the unpickling from an old
584
+ :class:`UniqueFactory` object.
585
+
586
+ :class:`UniqueFactory` pickles use a global name through
587
+ :func:`generic_factory_unpickle()`, so the usual
588
+ :func:`~sage.misc.persist.register_unpickle_override()`
589
+ cannot be used here.
590
+
591
+ .. SEEALSO::
592
+
593
+ :func:`generic_factory_unpickle()`
594
+
595
+ TESTS:
596
+
597
+ This is similar to the example given in
598
+ :func:`generic_factory_unpickle()`, but here we will use a function to
599
+ explicitly return a polynomial ring.
600
+
601
+ First, we create the factory. In a doctest, it is needed to explicitly put
602
+ it into ``__main__``, so that it can be located when pickling. Also, it is
603
+ needed that we work with a new-style class::
604
+
605
+ sage: from sage.structure.factory import UniqueFactory, register_factory_unpickle
606
+ sage: import __main__
607
+ sage: class OldStuff():
608
+ ....: def __init__(self, n, **extras):
609
+ ....: self.n = n
610
+ ....: def __repr__(self):
611
+ ....: return "Rotten old thing of level {}".format(self.n)
612
+ sage: __main__.OldStuff = OldStuff
613
+ sage: class MyFactory(UniqueFactory):
614
+ ....: def create_object(self, version, key, **extras):
615
+ ....: return OldStuff(key[0])
616
+ ....: def create_key(self, *args):
617
+ ....: return args
618
+ sage: G = MyFactory('__main__.G')
619
+ sage: __main__.G = G
620
+ sage: a = G(3); a
621
+ Rotten old thing of level 3
622
+ sage: loads(dumps(a)) is a
623
+ True
624
+
625
+ Now, we create a pickle (the string returned by ``dumps(a)``)::
626
+
627
+ sage: s = dumps(a)
628
+
629
+ We create the function which will handle the unpickling::
630
+
631
+ sage: def foo(n, **kwds):
632
+ ....: return PolynomialRing(QQ, n, 'x')
633
+ sage: register_factory_unpickle('__main__.G', foo)
634
+
635
+ The old pickle correctly unpickles as an explicit polynomial ring::
636
+
637
+ sage: loads(s)
638
+ Multivariate Polynomial Ring in x0, x1, x2 over Rational Field
639
+ """
640
+ global factory_unpickles
641
+ factory_unpickles[name] = callable
642
+
643
+
644
+ def generic_factory_unpickle(factory, *args):
645
+ """
646
+ Method used for unpickling the object.
647
+
648
+ The unpickling mechanism needs a plain Python function to call.
649
+ It takes a factory as the first argument, passes the rest of the
650
+ arguments onto the factory's :meth:`UniqueFactory.get_object` method.
651
+
652
+ EXAMPLES::
653
+
654
+ sage: # needs sage.modules
655
+ sage: from sage.modules.free_module import FreeModuleFactory_with_standard_basis as F
656
+ sage: V = F(ZZ, 5)
657
+ sage: func, data = F.reduce_data(V)
658
+ sage: func is sage.structure.factory.generic_factory_unpickle
659
+ True
660
+ sage: sage.structure.factory.generic_factory_unpickle(*data) is V
661
+ True
662
+
663
+ TESTS:
664
+
665
+ The following was enabled in :issue:`16349`. Suppose we have defined
666
+ (somewhere in the library of an old Sage version) a unique factory; in our
667
+ example below, it returns polynomial rings. Now suppose that we want to
668
+ replace the factory by something else, say, a class that provides the
669
+ unique parent behaviour using
670
+ :class:`~sage.structure.unique_representation.UniqueRepresentation`. We
671
+ show here how to make it possible to unpickle a pickle created with the
672
+ factory, automatically turning it into an instance of the new class.
673
+
674
+ First, we create the factory. In a doctest, it is needed to explicitly put
675
+ it into ``__main__``, so that it can be located when pickling. Also, it is
676
+ needed that we work with a new-style class::
677
+
678
+ sage: from sage.structure.factory import UniqueFactory
679
+ sage: import __main__
680
+ sage: class OldStuff():
681
+ ....: def __init__(self, n, **extras):
682
+ ....: self.n = n
683
+ ....: def __repr__(self):
684
+ ....: return "Rotten old thing of level {}".format(self.n)
685
+ sage: __main__.OldStuff = OldStuff
686
+ sage: class MyFactory(UniqueFactory):
687
+ ....: def create_object(self, version, key, **extras):
688
+ ....: return OldStuff(key[0])
689
+ ....: def create_key(self, *args):
690
+ ....: return args
691
+ sage: F = MyFactory('__main__.F')
692
+ sage: __main__.F = F
693
+ sage: a = F(3); a
694
+ Rotten old thing of level 3
695
+ sage: loads(dumps(a)) is a
696
+ True
697
+
698
+ Now, we create a pickle (the string returned by ``dumps(a)``)::
699
+
700
+ sage: s = dumps(a)
701
+
702
+ We create a new class, derived from
703
+ :class:`~sage.structure.unique_representation.UniqueRepresentation`, that
704
+ shall replace the old factory. In particular, the class has to have the
705
+ same name as the old factory, and has to be put into the same module
706
+ (here: ``__main__``). We turn it into a sub-class of the old class, but
707
+ this is just to save the effort of writing a new init method::
708
+
709
+ sage: from sage.structure.unique_representation import UniqueRepresentation
710
+ sage: class F(UniqueRepresentation, OldStuff):
711
+ ....: def __repr__(self):
712
+ ....: return "Shiny new thing of level {}".format(self.n)
713
+ sage: __main__.F = F
714
+
715
+ The old pickle correctly unpickles as an instance of the new class, which
716
+ is of course different from the instance of the old class, but exhibits
717
+ unique object behaviour as well::
718
+
719
+ sage: b = loads(s); b
720
+ Shiny new thing of level 3
721
+ sage: a is b
722
+ False
723
+ sage: loads(dumps(b)) is b
724
+ True
725
+ """
726
+ cdef UniqueFactory F
727
+ if factory is not None:
728
+ try:
729
+ F = factory
730
+ return F.get_object(*args)
731
+ except TypeError:
732
+ pass
733
+ # See Issue #16349: When replacing a UniqueFactory by something else (e.g.,
734
+ # a UniqueRepresentation), then we get the object by calling.
735
+ #
736
+ # The first argument of a UniqueFactory pickle is a version number. We
737
+ # strip this.
738
+ return factory(*args[1], **args[2])
739
+
740
+
741
+ def generic_factory_reduce(self, proto):
742
+ """
743
+ Used to provide a ``__reduce__`` method if one does not already exist.
744
+
745
+ INPUT:
746
+
747
+ - ``proto`` -- positive integer; protocol number
748
+
749
+ EXAMPLES::
750
+
751
+ sage: V = QQ^6 # needs sage.modules
752
+ sage: sage.structure.factory.generic_factory_reduce(V, 1) == V.__reduce_ex__(1) # needs sage.modules
753
+ True
754
+ """
755
+ if self._factory_data is None:
756
+ raise NotImplementedError("__reduce__ not implemented for %s" % type(self))
757
+ else:
758
+ return self._factory_data[0].reduce_data(self)
759
+
760
+
761
+ def generic_factory_getstate(obj):
762
+ """
763
+ Used for pickling :class:`UniqueFactory` objects.
764
+
765
+ The cached value of the method with ``do_pickle=True`` is pickled
766
+ along with the object.
767
+
768
+ TESTS::
769
+
770
+ sage: # needs sage.rings.function_field
771
+ sage: K.<x> = FunctionField(QQ); R.<y> = K[]
772
+ sage: F = K.extension(y^5 - x^3 - 3*x + x*y)
773
+ sage: F.genus()
774
+ 4
775
+ sage: F.genus.cache
776
+ 4
777
+ sage: s = dumps(F)
778
+ sage: F.genus.clear_cache()
779
+ sage: F.genus.cache
780
+ sage: Fp = loads(s)
781
+ sage: Fp is F
782
+ True
783
+ sage: Fp.genus.cache
784
+ 4
785
+ """
786
+ # We filter out cached-method placeholders (CachedFunction) with
787
+ # do_pickle=True in __dict__ to keep them as the state of the pickled object.
788
+ #
789
+ # Note that the same code is used to get the state of UniqueRepresentation objects.
790
+ from sage.misc.cachefunc import CachedFunction
791
+ d = {}
792
+ try:
793
+ for key, value in obj.__dict__.items():
794
+ if isinstance(value, CachedFunction) and value.is_pickled_with_cache():
795
+ d[key] = value
796
+ except AttributeError:
797
+ pass
798
+ return d
799
+
800
+
801
+ def generic_factory_setstate(self, d):
802
+ """
803
+ Used for unpickling :class:`UniqueFactory` objects.
804
+
805
+ TESTS:
806
+
807
+ Unpickled value overrides cached value::
808
+
809
+ sage: # needs sage.rings.function_field
810
+ sage: K.<x> = FunctionField(QQ); R.<y> = K[]
811
+ sage: F = K.extension(y^5 - x^3 - 3*x + x*y)
812
+ sage: F.genus()
813
+ 4
814
+ sage: s = dumps(F)
815
+ sage: F.genus.set_cache(10)
816
+ sage: F.genus()
817
+ 10
818
+ sage: Fp = loads(s)
819
+ sage: Fp is F
820
+ True
821
+ sage: Fp.genus()
822
+ 4
823
+ """
824
+ self.__dict__.update(d)
825
+
826
+
827
+ def lookup_global(name):
828
+ """
829
+ Used in unpickling the factory itself.
830
+
831
+ EXAMPLES::
832
+
833
+ sage: from sage.structure.factory import lookup_global
834
+ sage: lookup_global('ZZ')
835
+ Integer Ring
836
+ sage: lookup_global('sage.rings.integer_ring.ZZ')
837
+ Integer Ring
838
+ """
839
+ name = bytes_to_str(name, encoding='ASCII')
840
+ try:
841
+ return factory_unpickles[name]
842
+ except KeyError:
843
+ pass
844
+
845
+ if '.' in name:
846
+ module, name = name.rsplit('.', 1)
847
+ all = __import__(module, fromlist=[name])
848
+ else:
849
+ try:
850
+ import sage.all as all
851
+ except ImportError:
852
+ try:
853
+ import sage.all__sagemath_modules as all
854
+ except ImportError:
855
+ try:
856
+ import sage.all__sagemath_pari as all
857
+ except ImportError:
858
+ import sage.all__sagemath_categories as all
859
+ return getattr(all, name)
860
+
861
+
862
+ # Old imports required for unpickling old pickles
863
+ from sage.structure.test_factory import test_factory