passagemath-objects 10.6.44__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.
Files changed (280) hide show
  1. passagemath_objects/.dylibs/libgmp.10.dylib +0 -0
  2. passagemath_objects/__init__.py +3 -0
  3. passagemath_objects-10.6.44.dist-info/METADATA +115 -0
  4. passagemath_objects-10.6.44.dist-info/RECORD +280 -0
  5. passagemath_objects-10.6.44.dist-info/WHEEL +6 -0
  6. passagemath_objects-10.6.44.dist-info/top_level.txt +3 -0
  7. sage/all__sagemath_objects.py +37 -0
  8. sage/arith/all__sagemath_objects.py +5 -0
  9. sage/arith/long.pxd +411 -0
  10. sage/arith/numerical_approx.cpython-314t-darwin.so +0 -0
  11. sage/arith/numerical_approx.pxd +35 -0
  12. sage/arith/numerical_approx.pyx +75 -0
  13. sage/arith/power.cpython-314t-darwin.so +0 -0
  14. sage/arith/power.pxd +31 -0
  15. sage/arith/power.pyx +127 -0
  16. sage/categories/action.cpython-314t-darwin.so +0 -0
  17. sage/categories/action.pxd +29 -0
  18. sage/categories/action.pyx +641 -0
  19. sage/categories/algebra_functor.py +745 -0
  20. sage/categories/all__sagemath_objects.py +33 -0
  21. sage/categories/basic.py +62 -0
  22. sage/categories/cartesian_product.py +295 -0
  23. sage/categories/category.py +3401 -0
  24. sage/categories/category_cy_helper.cpython-314t-darwin.so +0 -0
  25. sage/categories/category_cy_helper.pxd +8 -0
  26. sage/categories/category_cy_helper.pyx +322 -0
  27. sage/categories/category_singleton.cpython-314t-darwin.so +0 -0
  28. sage/categories/category_singleton.pxd +3 -0
  29. sage/categories/category_singleton.pyx +342 -0
  30. sage/categories/category_types.py +637 -0
  31. sage/categories/category_with_axiom.py +2876 -0
  32. sage/categories/covariant_functorial_construction.py +703 -0
  33. sage/categories/facade_sets.py +228 -0
  34. sage/categories/functor.cpython-314t-darwin.so +0 -0
  35. sage/categories/functor.pxd +7 -0
  36. sage/categories/functor.pyx +691 -0
  37. sage/categories/homset.py +1338 -0
  38. sage/categories/homsets.py +364 -0
  39. sage/categories/isomorphic_objects.py +73 -0
  40. sage/categories/map.cpython-314t-darwin.so +0 -0
  41. sage/categories/map.pxd +34 -0
  42. sage/categories/map.pyx +2106 -0
  43. sage/categories/morphism.cpython-314t-darwin.so +0 -0
  44. sage/categories/morphism.pxd +14 -0
  45. sage/categories/morphism.pyx +895 -0
  46. sage/categories/objects.py +167 -0
  47. sage/categories/primer.py +1696 -0
  48. sage/categories/pushout.py +4834 -0
  49. sage/categories/quotients.py +64 -0
  50. sage/categories/realizations.py +200 -0
  51. sage/categories/sets_cat.py +3290 -0
  52. sage/categories/sets_with_partial_maps.py +52 -0
  53. sage/categories/subobjects.py +64 -0
  54. sage/categories/subquotients.py +21 -0
  55. sage/categories/with_realizations.py +311 -0
  56. sage/cpython/__init__.py +19 -0
  57. sage/cpython/_py2_random.py +619 -0
  58. sage/cpython/all.py +3 -0
  59. sage/cpython/atexit.cpython-314t-darwin.so +0 -0
  60. sage/cpython/atexit.pyx +269 -0
  61. sage/cpython/builtin_types.cpython-314t-darwin.so +0 -0
  62. sage/cpython/builtin_types.pyx +7 -0
  63. sage/cpython/cython_metaclass.cpython-314t-darwin.so +0 -0
  64. sage/cpython/cython_metaclass.h +117 -0
  65. sage/cpython/cython_metaclass.pxd +3 -0
  66. sage/cpython/cython_metaclass.pyx +130 -0
  67. sage/cpython/debug.cpython-314t-darwin.so +0 -0
  68. sage/cpython/debug.pyx +302 -0
  69. sage/cpython/dict_del_by_value.cpython-314t-darwin.so +0 -0
  70. sage/cpython/dict_del_by_value.pxd +9 -0
  71. sage/cpython/dict_del_by_value.pyx +191 -0
  72. sage/cpython/dict_internal.h +245 -0
  73. sage/cpython/getattr.cpython-314t-darwin.so +0 -0
  74. sage/cpython/getattr.pxd +9 -0
  75. sage/cpython/getattr.pyx +439 -0
  76. sage/cpython/pycore_long.h +97 -0
  77. sage/cpython/pycore_long.pxd +10 -0
  78. sage/cpython/python_debug.h +44 -0
  79. sage/cpython/python_debug.pxd +47 -0
  80. sage/cpython/pyx_visit.h +13 -0
  81. sage/cpython/string.cpython-314t-darwin.so +0 -0
  82. sage/cpython/string.pxd +76 -0
  83. sage/cpython/string.pyx +34 -0
  84. sage/cpython/string_impl.h +60 -0
  85. sage/cpython/type.cpython-314t-darwin.so +0 -0
  86. sage/cpython/type.pxd +2 -0
  87. sage/cpython/type.pyx +40 -0
  88. sage/cpython/wrapperdescr.pxd +67 -0
  89. sage/ext/all__sagemath_objects.py +3 -0
  90. sage/ext/ccobject.h +64 -0
  91. sage/ext/cplusplus.pxd +17 -0
  92. sage/ext/mod_int.h +30 -0
  93. sage/ext/mod_int.pxd +24 -0
  94. sage/ext/stdsage.pxd +39 -0
  95. sage/groups/all__sagemath_objects.py +1 -0
  96. sage/groups/group.cpython-314t-darwin.so +0 -0
  97. sage/groups/group.pxd +14 -0
  98. sage/groups/group.pyx +322 -0
  99. sage/groups/old.cpython-314t-darwin.so +0 -0
  100. sage/groups/old.pxd +14 -0
  101. sage/groups/old.pyx +219 -0
  102. sage/libs/all__sagemath_objects.py +3 -0
  103. sage/libs/gmp/__init__.py +1 -0
  104. sage/libs/gmp/all.pxd +6 -0
  105. sage/libs/gmp/binop.pxd +23 -0
  106. sage/libs/gmp/misc.pxd +8 -0
  107. sage/libs/gmp/mpf.pxd +88 -0
  108. sage/libs/gmp/mpn.pxd +57 -0
  109. sage/libs/gmp/mpq.pxd +57 -0
  110. sage/libs/gmp/mpz.pxd +202 -0
  111. sage/libs/gmp/pylong.cpython-314t-darwin.so +0 -0
  112. sage/libs/gmp/pylong.pxd +12 -0
  113. sage/libs/gmp/pylong.pyx +150 -0
  114. sage/libs/gmp/random.pxd +25 -0
  115. sage/libs/gmp/randomize.pxd +59 -0
  116. sage/libs/gmp/types.pxd +53 -0
  117. sage/libs/gmpxx.pxd +19 -0
  118. sage/misc/abstract_method.py +276 -0
  119. sage/misc/all__sagemath_objects.py +43 -0
  120. sage/misc/bindable_class.py +253 -0
  121. sage/misc/c3_controlled.cpython-314t-darwin.so +0 -0
  122. sage/misc/c3_controlled.pxd +2 -0
  123. sage/misc/c3_controlled.pyx +1402 -0
  124. sage/misc/cachefunc.cpython-314t-darwin.so +0 -0
  125. sage/misc/cachefunc.pxd +43 -0
  126. sage/misc/cachefunc.pyx +3781 -0
  127. sage/misc/call.py +188 -0
  128. sage/misc/classcall_metaclass.cpython-314t-darwin.so +0 -0
  129. sage/misc/classcall_metaclass.pxd +14 -0
  130. sage/misc/classcall_metaclass.pyx +599 -0
  131. sage/misc/constant_function.cpython-314t-darwin.so +0 -0
  132. sage/misc/constant_function.pyx +130 -0
  133. sage/misc/decorators.py +747 -0
  134. sage/misc/fast_methods.cpython-314t-darwin.so +0 -0
  135. sage/misc/fast_methods.pxd +20 -0
  136. sage/misc/fast_methods.pyx +351 -0
  137. sage/misc/flatten.py +90 -0
  138. sage/misc/fpickle.cpython-314t-darwin.so +0 -0
  139. sage/misc/fpickle.pyx +177 -0
  140. sage/misc/function_mangling.cpython-314t-darwin.so +0 -0
  141. sage/misc/function_mangling.pxd +11 -0
  142. sage/misc/function_mangling.pyx +308 -0
  143. sage/misc/inherit_comparison.cpython-314t-darwin.so +0 -0
  144. sage/misc/inherit_comparison.pxd +5 -0
  145. sage/misc/inherit_comparison.pyx +105 -0
  146. sage/misc/instancedoc.cpython-314t-darwin.so +0 -0
  147. sage/misc/instancedoc.pyx +331 -0
  148. sage/misc/lazy_attribute.cpython-314t-darwin.so +0 -0
  149. sage/misc/lazy_attribute.pyx +607 -0
  150. sage/misc/lazy_format.py +135 -0
  151. sage/misc/lazy_import.cpython-314t-darwin.so +0 -0
  152. sage/misc/lazy_import.pyx +1299 -0
  153. sage/misc/lazy_import_cache.py +36 -0
  154. sage/misc/lazy_list.cpython-314t-darwin.so +0 -0
  155. sage/misc/lazy_list.pxd +19 -0
  156. sage/misc/lazy_list.pyx +1187 -0
  157. sage/misc/lazy_string.cpython-314t-darwin.so +0 -0
  158. sage/misc/lazy_string.pxd +7 -0
  159. sage/misc/lazy_string.pyx +546 -0
  160. sage/misc/misc.py +1066 -0
  161. sage/misc/misc_c.cpython-314t-darwin.so +0 -0
  162. sage/misc/misc_c.pxd +3 -0
  163. sage/misc/misc_c.pyx +766 -0
  164. sage/misc/namespace_package.py +37 -0
  165. sage/misc/nested_class.cpython-314t-darwin.so +0 -0
  166. sage/misc/nested_class.pxd +3 -0
  167. sage/misc/nested_class.pyx +394 -0
  168. sage/misc/persist.cpython-314t-darwin.so +0 -0
  169. sage/misc/persist.pyx +1251 -0
  170. sage/misc/prandom.py +418 -0
  171. sage/misc/randstate.cpython-314t-darwin.so +0 -0
  172. sage/misc/randstate.pxd +30 -0
  173. sage/misc/randstate.pyx +1059 -0
  174. sage/misc/repr.py +203 -0
  175. sage/misc/reset.cpython-314t-darwin.so +0 -0
  176. sage/misc/reset.pyx +196 -0
  177. sage/misc/sage_ostools.cpython-314t-darwin.so +0 -0
  178. sage/misc/sage_ostools.pyx +323 -0
  179. sage/misc/sage_timeit.py +275 -0
  180. sage/misc/sage_timeit_class.cpython-314t-darwin.so +0 -0
  181. sage/misc/sage_timeit_class.pyx +120 -0
  182. sage/misc/sage_unittest.py +637 -0
  183. sage/misc/sageinspect.py +2768 -0
  184. sage/misc/session.cpython-314t-darwin.so +0 -0
  185. sage/misc/session.pyx +392 -0
  186. sage/misc/superseded.py +557 -0
  187. sage/misc/test_nested_class.py +228 -0
  188. sage/misc/timing.py +264 -0
  189. sage/misc/unknown.py +222 -0
  190. sage/misc/verbose.py +253 -0
  191. sage/misc/weak_dict.cpython-314t-darwin.so +0 -0
  192. sage/misc/weak_dict.pxd +15 -0
  193. sage/misc/weak_dict.pyx +1231 -0
  194. sage/modules/all__sagemath_objects.py +1 -0
  195. sage/modules/module.cpython-314t-darwin.so +0 -0
  196. sage/modules/module.pxd +5 -0
  197. sage/modules/module.pyx +329 -0
  198. sage/rings/all__sagemath_objects.py +3 -0
  199. sage/rings/integer_fake.h +22 -0
  200. sage/rings/integer_fake.pxd +55 -0
  201. sage/sets/all__sagemath_objects.py +3 -0
  202. sage/sets/pythonclass.cpython-314t-darwin.so +0 -0
  203. sage/sets/pythonclass.pxd +9 -0
  204. sage/sets/pythonclass.pyx +247 -0
  205. sage/structure/__init__.py +4 -0
  206. sage/structure/all.py +30 -0
  207. sage/structure/category_object.cpython-314t-darwin.so +0 -0
  208. sage/structure/category_object.pxd +28 -0
  209. sage/structure/category_object.pyx +1087 -0
  210. sage/structure/coerce.cpython-314t-darwin.so +0 -0
  211. sage/structure/coerce.pxd +44 -0
  212. sage/structure/coerce.pyx +2107 -0
  213. sage/structure/coerce_actions.cpython-314t-darwin.so +0 -0
  214. sage/structure/coerce_actions.pxd +27 -0
  215. sage/structure/coerce_actions.pyx +988 -0
  216. sage/structure/coerce_dict.cpython-314t-darwin.so +0 -0
  217. sage/structure/coerce_dict.pxd +51 -0
  218. sage/structure/coerce_dict.pyx +1557 -0
  219. sage/structure/coerce_exceptions.py +23 -0
  220. sage/structure/coerce_maps.cpython-314t-darwin.so +0 -0
  221. sage/structure/coerce_maps.pxd +28 -0
  222. sage/structure/coerce_maps.pyx +718 -0
  223. sage/structure/debug_options.cpython-314t-darwin.so +0 -0
  224. sage/structure/debug_options.pxd +6 -0
  225. sage/structure/debug_options.pyx +54 -0
  226. sage/structure/dynamic_class.py +541 -0
  227. sage/structure/element.cpython-314t-darwin.so +0 -0
  228. sage/structure/element.pxd +272 -0
  229. sage/structure/element.pyx +4772 -0
  230. sage/structure/element_wrapper.cpython-314t-darwin.so +0 -0
  231. sage/structure/element_wrapper.pxd +12 -0
  232. sage/structure/element_wrapper.pyx +582 -0
  233. sage/structure/factorization.py +1422 -0
  234. sage/structure/factorization_integer.py +105 -0
  235. sage/structure/factory.cpython-314t-darwin.so +0 -0
  236. sage/structure/factory.pyx +786 -0
  237. sage/structure/formal_sum.py +489 -0
  238. sage/structure/gens_py.py +73 -0
  239. sage/structure/global_options.py +1743 -0
  240. sage/structure/indexed_generators.py +863 -0
  241. sage/structure/list_clone.cpython-314t-darwin.so +0 -0
  242. sage/structure/list_clone.pxd +65 -0
  243. sage/structure/list_clone.pyx +1867 -0
  244. sage/structure/list_clone_demo.cpython-314t-darwin.so +0 -0
  245. sage/structure/list_clone_demo.pyx +248 -0
  246. sage/structure/list_clone_timings.py +179 -0
  247. sage/structure/list_clone_timings_cy.cpython-314t-darwin.so +0 -0
  248. sage/structure/list_clone_timings_cy.pyx +86 -0
  249. sage/structure/mutability.cpython-314t-darwin.so +0 -0
  250. sage/structure/mutability.pxd +21 -0
  251. sage/structure/mutability.pyx +348 -0
  252. sage/structure/nonexact.py +69 -0
  253. sage/structure/parent.cpython-314t-darwin.so +0 -0
  254. sage/structure/parent.pxd +112 -0
  255. sage/structure/parent.pyx +3093 -0
  256. sage/structure/parent_base.cpython-314t-darwin.so +0 -0
  257. sage/structure/parent_base.pxd +13 -0
  258. sage/structure/parent_base.pyx +44 -0
  259. sage/structure/parent_gens.cpython-314t-darwin.so +0 -0
  260. sage/structure/parent_gens.pxd +22 -0
  261. sage/structure/parent_gens.pyx +377 -0
  262. sage/structure/parent_old.cpython-314t-darwin.so +0 -0
  263. sage/structure/parent_old.pxd +25 -0
  264. sage/structure/parent_old.pyx +294 -0
  265. sage/structure/proof/__init__.py +1 -0
  266. sage/structure/proof/all.py +243 -0
  267. sage/structure/proof/proof.py +300 -0
  268. sage/structure/richcmp.cpython-314t-darwin.so +0 -0
  269. sage/structure/richcmp.pxd +213 -0
  270. sage/structure/richcmp.pyx +495 -0
  271. sage/structure/sage_object.cpython-314t-darwin.so +0 -0
  272. sage/structure/sage_object.pxd +3 -0
  273. sage/structure/sage_object.pyx +988 -0
  274. sage/structure/sage_object_test.py +19 -0
  275. sage/structure/sequence.py +937 -0
  276. sage/structure/set_factories.py +1178 -0
  277. sage/structure/set_factories_example.py +527 -0
  278. sage/structure/support_view.py +179 -0
  279. sage/structure/test_factory.py +56 -0
  280. sage/structure/unique_representation.py +1359 -0
@@ -0,0 +1,1743 @@
1
+ # sage_setup: distribution = sagemath-objects
2
+ r"""
3
+ Global options
4
+
5
+ The :class:`GlobalOptions` class provides a generic mechanism for
6
+ setting and accessing **global** options for parents in one or several
7
+ related classes, typically for customizing the representation of their
8
+ elements. This class will eventually also support setting options on a
9
+ parent by parent basis.
10
+
11
+ These options should be "attached" to one or more classes as an options method.
12
+
13
+ .. SEEALSO::
14
+
15
+ For good examples of :class:`GlobalOptions` in action see
16
+ :obj:`sage.combinat.partition.Partitions.options` and
17
+ :obj:`sage.combinat.tableau.Tableaux.options`.
18
+
19
+ .. _construction_section:
20
+
21
+ Construction of options classes
22
+ -------------------------------
23
+
24
+ The general setup for creating a set of global options is::
25
+
26
+ sage: from sage.structure.global_options import GlobalOptions
27
+ sage: class MyOptions(GlobalOptions):
28
+ ....: '''
29
+ ....: Nice options
30
+ ....:
31
+ ....: @OPTIONS@
32
+ ....: '''
33
+ ....: NAME = 'option name'
34
+ ....: module = 'sage.some_module.some_file'
35
+ ....: option_class = 'name_of_class_controlled_by_options'
36
+ ....: first_option = dict(default='with_bells',
37
+ ....: description='Changes the functionality of _repr_',
38
+ ....: values=dict(with_bells='causes _repr_ to print with bells',
39
+ ....: with_whistles='causes _repr_ to print with whistles'),
40
+ ....: alias=dict(bells='option1', whistles='option2'))
41
+ ....: # second_option = dict(...)
42
+ ....: # third_option = dict(...)
43
+
44
+ Note the syntax using the ``class`` keyword. However, because of some
45
+ metaclass magic, the resulting ``MyOptions`` object becomes an instance
46
+ of ``GlobalOptions`` instead of a subclass. So, despite the ``class``
47
+ syntax, ``MyOptions`` is not a class.
48
+
49
+ The options constructed by :class:`GlobalOptions` have to be explicitly
50
+ associated to the class that they control using the following arguments:
51
+
52
+ - ``NAME`` -- a descriptive name for the options class; this is
53
+ optional. The default is the name of the constructed class.
54
+
55
+ - ``module`` -- the sage module containing the options class (optional)
56
+
57
+ - ``option_class`` -- the name of the options class; this is optional and
58
+ defaults to ``NAME`` if not explicitly set
59
+
60
+ It is only possible to pickle a :class:`GlobalOptions` class if the
61
+ corresponding module is specified *and* if the options are explicitly
62
+ attached to the corresponding class as a *options* method.
63
+
64
+ Each option is specified as a dictionary which describes the possible
65
+ values for the option and its documentation. The possible entries in this
66
+ dictionary are:
67
+
68
+ - ``alias`` -- allows for several option values to do the same thing
69
+
70
+ - ``alt_name`` -- an alternative name for this option
71
+
72
+ - ``checker`` -- a validation function which returns whether a user
73
+ supplied value is valid or not. This is typically useful for large
74
+ lists of legal values such as :class:`~sage.rings.semirings.non_negative_integer_semiring.NN`.
75
+
76
+ - ``default`` -- gives the default value for the option
77
+
78
+ - ``description`` -- a one line description of the option
79
+
80
+ - ``link_to`` -- links this option to another one in another set of
81
+ global options. This is used for example to allow
82
+ :class:`Partitions` and :class:`Tableaux` to share the same
83
+ ``convention`` option.
84
+
85
+ - ``setter`` -- a function which is called **after** the value of the
86
+ option is changed
87
+
88
+ - ``values`` -- dictionary assigning each valid value for the option
89
+ to a short description of what it does
90
+
91
+ - ``case_sensitive`` -- boolean (default: ``True``); depending on
92
+ whether the values of the option are case sensitive
93
+
94
+ For each option, either a complete list of possible values, via ``values``, or a
95
+ validation function, via ``checker``, must be given. The values can be quite
96
+ arbitrary, including user-defined functions which customize the default
97
+ behaviour of the classes such as the output of ``_repr_`` or :func:`latex`. See
98
+ :ref:`dispatcher` below, and :meth:`~GlobalOptions._dispatcher`, for more
99
+ information.
100
+
101
+ The documentation for the options is automatically constructed from
102
+ the docstring of the class by replacing the magic word ``@OPTIONS@``
103
+ with a description of each option.
104
+
105
+ The basic structure for defining a :class:`GlobalOptions` class is best
106
+ illustrated by an example::
107
+
108
+ sage: from sage.structure.global_options import GlobalOptions
109
+ sage: class Menu():
110
+ ....: class options(GlobalOptions):
111
+ ....: '''
112
+ ....: Fancy documentation
113
+ ....: -------------------
114
+ ....:
115
+ ....: @OPTIONS@
116
+ ....:
117
+ ....: The END!
118
+ ....: '''
119
+ ....: NAME = 'menu'
120
+ ....: entree = dict(default='soup',
121
+ ....: description='The first course of a meal',
122
+ ....: values=dict(soup='soup of the day', bread='oven baked'),
123
+ ....: alias=dict(rye='bread'))
124
+ ....: appetizer = dict(alt_name='entree')
125
+ ....: main = dict(default='pizza', description='Main meal',
126
+ ....: values=dict(pizza='thick crust', pasta='penne arrabiata'),
127
+ ....: case_sensitive=False)
128
+ ....: dessert = dict(default='espresso', description='Dessert',
129
+ ....: values=dict(espresso='life begins again',
130
+ ....: cake='waist begins again',
131
+ ....: cream='fluffy, white stuff'))
132
+ ....: tip = dict(default=10, description='Reward for good service',
133
+ ....: checker = lambda tip: tip in range(20))
134
+ sage: Menu.options
135
+ Current options for menu
136
+ - dessert: espresso
137
+ - entree: soup
138
+ - main: pizza
139
+ - tip: 10
140
+
141
+ In the examples above, the options are constructed when the ``options``
142
+ object is created. However, it is also possible to construct the options
143
+ dynamically using the :meth:`GlobalOptions._add_to_options` methods.
144
+
145
+ For more details see :class:`GlobalOptions`.
146
+
147
+ Accessing and setting option values
148
+ -----------------------------------
149
+
150
+ All options and their values, when they are strings, are forced to be lower
151
+ case. The values of an options class can be set and accessed by calling the
152
+ class or by treating the class as an array.
153
+
154
+ Continuing the example from :ref:`construction_section`::
155
+
156
+ sage: Menu.options
157
+ Current options for menu
158
+ - dessert: espresso
159
+ - entree: soup
160
+ - main: pizza
161
+ - tip: 10
162
+ sage: Menu.options.dessert
163
+ espresso
164
+ sage: Menu.options.dessert = 'cake'
165
+ sage: Menu.options.dessert
166
+ cake
167
+
168
+ Note that, provided there is no ambiguity, options and their values can be
169
+ abbreviated::
170
+
171
+ sage: Menu.options('d')
172
+ 'cake'
173
+ sage: Menu.options('m','t',des='esp', ent='sou') # get and set several values at once
174
+ ['pizza', 10]
175
+ sage: Menu.options(t=15)
176
+ sage: Menu.options('tip')
177
+ 15
178
+ sage: Menu.options.tip
179
+ 15
180
+ sage: Menu.options(e='s', m='Pi'); Menu.options()
181
+ Current options for menu
182
+ - dessert: cake
183
+ - entree: soup
184
+ - main: pizza
185
+ - tip: 15
186
+ sage: Menu.options(m='P')
187
+ Traceback (most recent call last):
188
+ ...
189
+ ValueError: P is not a valid value for main in the options for menu
190
+
191
+
192
+ Setter functions
193
+ ----------------
194
+
195
+ Each option of a :class:`GlobalOptions` can be equipped with an optional setter
196
+ function which is called **after** the value of the option is changed. In the
197
+ following example, setting the option 'add' changes the state of the class by
198
+ setting an attribute in this class using a :func:`classmethod`. Note that the
199
+ options object is inserted after the creation of the class in order to access
200
+ the :func:`classmethod` as ``A.setter``::
201
+
202
+ sage: from sage.structure.global_options import GlobalOptions
203
+ sage: class A(SageObject):
204
+ ....: state = 0
205
+ ....: @classmethod
206
+ ....: def setter(cls, option, val):
207
+ ....: cls.state += int(val)
208
+ sage: class options(GlobalOptions):
209
+ ....: NAME = "A"
210
+ ....: add = dict(default=1,
211
+ ....: checker=lambda v: int(v)>0,
212
+ ....: description='An option with a setter',
213
+ ....: setter=A.setter)
214
+ sage: A.options = options
215
+ sage: A.options
216
+ Current options for A
217
+ - add: 1
218
+ sage: a = A(); a.state
219
+ 1
220
+ sage: a.options()
221
+ Current options for A
222
+ - add: 1
223
+ sage: a.options(add=4)
224
+ sage: a.state
225
+ 5
226
+ sage: a.options()
227
+ Current options for A
228
+ - add: 4
229
+
230
+ Documentation for options
231
+ -------------------------
232
+
233
+ The documentation for a :class:`GlobalOptions` is automatically generated from
234
+ the supplied options. For example, the generated documentation for the options
235
+ ``menu`` defined in :ref:`construction_section` is the following:
236
+
237
+ .. CODE-BLOCK:: text
238
+
239
+ Fancy documentation
240
+ -------------------
241
+
242
+ OPTIONS:
243
+
244
+ - ``appetizer`` -- alternative name for ``entree``
245
+ - ``dessert`` -- (default: ``espresso``)
246
+ Dessert
247
+
248
+ - ``cake`` -- waist begins again
249
+ - ``cream`` -- fluffy, white stuff
250
+ - ``espresso`` -- life begins again
251
+
252
+ - ``entree`` -- (default: ``soup``)
253
+ The first course of a meal
254
+
255
+ - ``bread`` -- oven baked
256
+ - ``rye`` -- alias for ``bread``
257
+ - ``soup`` -- soup of the day
258
+
259
+ - ``main`` -- (default: ``pizza``)
260
+ Main meal
261
+
262
+ - ``pasta`` -- penne arrabiata
263
+ - ``pizza`` -- thick crust
264
+
265
+ - ``tip`` -- (default: ``10``)
266
+ Reward for good service
267
+
268
+
269
+ The END!
270
+
271
+ See :class:`~sage.structure.global_options.GlobalOptions` for more features of these options.
272
+
273
+ In addition, help on each option, and its list of possible values, can be
274
+ obtained by (trying to) set the option equal to '?'::
275
+
276
+ sage: Menu.options.dessert? # not tested
277
+ - ``dessert`` -- (default: ``espresso``)
278
+ Dessert
279
+
280
+ - ``cake`` -- waist begins again
281
+ - ``cream`` -- fluffy, white stuff
282
+ - ``espresso`` -- life begins again
283
+
284
+ .. _dispatcher:
285
+
286
+ Dispatchers
287
+ -----------
288
+
289
+ The whole idea of a :class:`GlobalOptions` class is that the options change the
290
+ default behaviour of the associated classes. This can be done either by simply
291
+ checking what the current value of the relevant option is. Another possibility
292
+ is to use the options class as a dispatcher to associated methods. To use the
293
+ dispatcher feature of a :class:`GlobalOptions` class it is necessary to implement
294
+ separate methods for each value of the option where the naming convention for
295
+ these methods is that they start with a common prefix and finish with the value
296
+ of the option.
297
+
298
+ If the value of a dispatchable option is set equal to a (user defined) function
299
+ then this function is called instead of a class method.
300
+
301
+ For example, the options ``MyOptions`` can be used to dispatch the ``_repr_``
302
+ method of the associated class ``MyClass`` as follows:
303
+
304
+ .. CODE-BLOCK:: python
305
+
306
+ class MyClass(...):
307
+ def _repr_(self):
308
+ return self.options._dispatch(self,'_repr_','first_option')
309
+ def _repr_with_bells(self):
310
+ print('Bell!')
311
+ def _repr_with_whistles(self):
312
+ print('Whistles!')
313
+ class MyOptions(GlobalOptions):
314
+ ...
315
+
316
+ In this example, ``first_option`` is an option of ``MyOptions`` which takes
317
+ values ``bells``, ``whistles``, and so on. Note that it is necessary to make
318
+ ``self``, which is an instance of ``MyClass``, an argument of the dispatcher
319
+ because :meth:`~GlobalOptions._dispatch()` is a method of :class:`GlobalOptions`
320
+ and not a method of ``MyClass``. Apart from ``MyOptions``, as it is a method of
321
+ this class, the arguments are the attached class (here ``MyClass``), the prefix
322
+ of the method of ``MyClass`` being dispatched, the option of ``MyOptions``
323
+ which controls the dispatching. All other arguments are passed through to the
324
+ corresponding methods of ``MyClass``. In general, a dispatcher is invoked as:
325
+
326
+ .. CODE-BLOCK:: python
327
+
328
+ self.options._dispatch(self, dispatch_to, option, *args, **kargs)
329
+
330
+ Usually this will result in the method
331
+ ``dispatch_to + '_' + MyOptions(options)`` of ``self`` being called with
332
+ arguments ``*args`` and ``**kargs`` (if ``dispatch_to[-1] == '_'`` then the
333
+ method ``dispatch_to + MyOptions(options)`` is called).
334
+
335
+ If ``MyOptions(options)`` is itself a function then the dispatcher will call
336
+ this function instead. In this way, it is possible to allow the user to
337
+ customise the default behaviour of this method. See
338
+ :meth:`~GlobalOptions._dispatch` for an example of how this can be achieved.
339
+
340
+ The dispatching capabilities of :class:`GlobalOptions` allows options to be
341
+ applied automatically without needing to parse different values of the option
342
+ (the cost is that there must be a method for each value). The dispatching
343
+ capabilities can also be used to make one option control several methods:
344
+
345
+ .. CODE-BLOCK:: python
346
+
347
+ def __le__(self, other):
348
+ return self.options._dispatch(self, '_le_','cmp', other)
349
+ def __ge__(self, other):
350
+ return self.options._dispatch(self, '_ge_','cmp', other)
351
+ def _le_option_a(self, other):
352
+ return ...
353
+ def _ge_option_a(self, other):
354
+ return ...
355
+ def _le_option_b(self, other):
356
+ return ...
357
+ def _ge_option_b(self, other):
358
+ return ...
359
+
360
+ See :meth:`~GlobalOptions._dispatch` for more details.
361
+
362
+ Doc testing
363
+ -----------
364
+
365
+ All of the options and their effects should be doc-tested. However, in order
366
+ not to break other tests, all options should be returned to their default state
367
+ at the end of each test. To make this easier, every :class:`GlobalOptions` class has
368
+ a :meth:`~GlobalOptions._reset()` method for doing exactly this.
369
+
370
+
371
+ Pickling
372
+ --------
373
+
374
+ Options classes can only be pickled if they are the options for some standard
375
+ sage class. In this case the class is specified using the arguments to
376
+ :class:`GlobalOptions`. For example
377
+ :meth:`~sage.combinat.partition.Partitions.options` is defined as:
378
+
379
+ .. CODE-BLOCK:: python
380
+
381
+ class Partitions(UniqueRepresentation, Parent):
382
+ ...
383
+ class options(GlobalOptions):
384
+ NAME = 'Partitions'
385
+ module = 'sage.combinat.partition'
386
+ ...
387
+
388
+ Here is an example to test the pickling of a :class:`GlobalOptions` instance::
389
+
390
+ sage: TestSuite(Partitions.options).run()
391
+
392
+ TESTS:
393
+
394
+ Check that the old call syntax still works::
395
+
396
+ sage: class Menu():
397
+ ....: options = GlobalOptions('menu',
398
+ ....: doc='Fancy documentation\n'+'-'*19, end_doc='The END!',
399
+ ....: entree=dict(default='soup',
400
+ ....: description='The first course of a meal',
401
+ ....: values=dict(soup='soup of the day', bread='oven baked'),
402
+ ....: alias=dict(rye='bread')),
403
+ ....: appetizer=dict(alt_name='entree'),
404
+ ....: main=dict(default='pizza', description='Main meal',
405
+ ....: values=dict(pizza='thick crust', pasta='penne arrabiata'),
406
+ ....: case_sensitive=False),
407
+ ....: dessert=dict(default='espresso', description='Dessert',
408
+ ....: values=dict(espresso='life begins again',
409
+ ....: cake='waist begins again',
410
+ ....: cream='fluffy, white stuff')),
411
+ ....: tip=dict(default=10, description='Reward for good service',
412
+ ....: checker=lambda tip: tip in range(20))
413
+ ....: )
414
+ sage: Menu.options
415
+ Current options for menu
416
+ - dessert: espresso
417
+ - entree: soup
418
+ - main: pizza
419
+ - tip: 10
420
+
421
+ We can have a ``name`` option::
422
+
423
+ sage: class MyOptions(GlobalOptions):
424
+ ....: name = dict(default='alice', values={'alice': "A", 'bob': "B"})
425
+ sage: MyOptions
426
+ Current options for MyOptions
427
+ - name: alice
428
+
429
+ Check that the ``name`` and ``NAME`` keywords are both supported with
430
+ this syntax::
431
+
432
+ sage: GlobalOptions(name='menu')
433
+ Current options for menu
434
+ sage: GlobalOptions(NAME='menu')
435
+ Current options for menu
436
+ sage: GlobalOptions()
437
+ Traceback (most recent call last):
438
+ ...
439
+ TypeError: GlobalOptions() is missing keyword argument 'name'
440
+
441
+ Test the documentation examples above::
442
+
443
+ sage: print(Menu.options.__doc__)
444
+ Fancy documentation
445
+ -------------------
446
+ <BLANKLINE>
447
+ OPTIONS:
448
+ <BLANKLINE>
449
+ - ``appetizer`` -- alternative name for ``entree``
450
+ - ``dessert`` -- (default: ``espresso``)
451
+ Dessert
452
+ <BLANKLINE>
453
+ - ``cake`` -- waist begins again
454
+ - ``cream`` -- fluffy, white stuff
455
+ - ``espresso`` -- life begins again
456
+ <BLANKLINE>
457
+ - ``entree`` -- (default: ``soup``)
458
+ The first course of a meal
459
+ <BLANKLINE>
460
+ - ``bread`` -- oven baked
461
+ - ``rye`` -- alias for ``bread``
462
+ - ``soup`` -- soup of the day
463
+ <BLANKLINE>
464
+ - ``main`` -- (default: ``pizza``)
465
+ Main meal
466
+ <BLANKLINE>
467
+ - ``pasta`` -- penne arrabiata
468
+ - ``pizza`` -- thick crust
469
+ <BLANKLINE>
470
+ - ``tip`` -- (default: ``10``)
471
+ Reward for good service
472
+ <BLANKLINE>
473
+ <BLANKLINE>
474
+ <BLANKLINE>
475
+ <BLANKLINE>
476
+ The END!
477
+ See :class:`~sage.structure.global_options.GlobalOptions` for more features of these options.
478
+
479
+ ::
480
+
481
+ sage: print(Menu.options.dessert.__doc__)
482
+ - ``dessert`` -- (default: ``espresso``)
483
+ Dessert
484
+ <BLANKLINE>
485
+ - ``cake`` -- waist begins again
486
+ - ``cream`` -- fluffy, white stuff
487
+ - ``espresso`` -- life begins again
488
+ <BLANKLINE>
489
+
490
+ AUTHORS:
491
+
492
+ - Andrew Mathas (2013): initial version
493
+ - Andrew Mathas (2016): overhaul making the options attributes, enabling
494
+ pickling and attaching the options to a class.
495
+ - Jeroen Demeyer (2017): use subclassing to create instances
496
+ """
497
+
498
+ # ****************************************************************************
499
+ # Copyright (C) 2013,2016 Andrew Mathas <andrew dot mathas at sydney dot edu dot au>
500
+ # Copyright (C) 2017 Jeroen Demeyer <J.Demeyer@UGent.be>
501
+ #
502
+ # This program is free software: you can redistribute it and/or modify
503
+ # it under the terms of the GNU General Public License as published by
504
+ # the Free Software Foundation, either version 2 of the License, or
505
+ # (at your option) any later version.
506
+ # https://www.gnu.org/licenses/
507
+ # ****************************************************************************
508
+
509
+
510
+ from importlib import import_module
511
+ from pickle import PicklingError
512
+ from textwrap import dedent
513
+
514
+ from sage.misc.instancedoc import instancedoc
515
+
516
+
517
+ class Option:
518
+ r"""
519
+ An option.
520
+
521
+ Each option for an options class is an instance of this class which
522
+ implements the magic that allows the options to the attributes of the
523
+ options class that can be looked up, set and called.
524
+
525
+ By way of example, this class implements the following functionality.
526
+
527
+ EXAMPLES::
528
+
529
+ sage: # needs sage.combinat
530
+ sage: Partitions.options.display
531
+ list
532
+ sage: Partitions.options.display = 'compact'
533
+ sage: Partitions.options.display('list')
534
+ sage: Partitions.options._reset()
535
+
536
+ TESTS::
537
+
538
+ sage: TestSuite(Partitions.options.display).run()
539
+ """
540
+ __name__ = 'Option class'
541
+
542
+ def __init__(self, options, name):
543
+ r"""
544
+ Initialise an option by settings its ``name``, "parent" option class
545
+ ``options`` and doc-string.
546
+
547
+ EXAMPLES::
548
+
549
+ sage: type(Partitions.options.display) # indirect doctest
550
+ <class 'sage.structure.global_options.Option'>
551
+ """
552
+ self._name = name
553
+ self._options = options
554
+ self.__doc__ = options._doc[name]
555
+ super().__init__()
556
+
557
+ def __repr__(self):
558
+ r"""
559
+ Return a string representation for this collection of options.
560
+
561
+ EXAMPLES::
562
+
563
+ sage: Partitions.options.display # indirect doctest
564
+ list
565
+ """
566
+ # NOTE: we intentionally use str() instead of repr()
567
+ return str(self._options[self._name])
568
+
569
+ def __add__(self, other):
570
+ r"""
571
+ Return the object obtained by adding ``self`` and ``other``, where
572
+ ``self`` behaves like its value.
573
+
574
+ EXAMPLES::
575
+
576
+ sage: Tableaux.options.convention + ' is good' # needs sage.combinat
577
+ 'English is good'
578
+ """
579
+ return self._options[self._name] + other
580
+
581
+ def __radd__(self, other):
582
+ r"""
583
+ Return the object obtained by adding ``other`` and ``self``, where
584
+ ``self`` behaves like its value.
585
+
586
+ EXAMPLES::
587
+
588
+ sage: 'Good ' + Tableaux.options.convention # needs sage.combinat
589
+ 'Good English'
590
+ """
591
+ return other + self._options[self._name]
592
+
593
+ def __mul__(self, other):
594
+ r"""
595
+ Return the object obtained by adding ``self`` and ``other``, where
596
+ ``self`` behaves like its value.
597
+
598
+ EXAMPLES::
599
+
600
+ sage: Tableaux.options.convention + ' is good' # needs sage.combinat
601
+ 'English is good'
602
+ """
603
+ return self._options[self._name] * other
604
+
605
+ def __rmul__(self, other):
606
+ r"""
607
+ Return the object obtained by r-adding ``other`` and ``self``, where
608
+ ``self`` behaves like its value.
609
+
610
+ EXAMPLES::
611
+
612
+ sage: 'Good ' + Tableaux.options.convention # needs sage.combinat
613
+ 'Good English'
614
+ """
615
+ return other * self._options[self._name]
616
+
617
+ def __bool__(self) -> bool:
618
+ r"""
619
+ Return the value of this option interpreted as a boolean.
620
+
621
+ EXAMPLES::
622
+
623
+ sage: # needs sage.combinat sage.graphs sage.modules
624
+ sage: RiggedConfigurations.options.half_width_boxes_type_B
625
+ True
626
+ sage: 'yes' if RiggedConfigurations.options.half_width_boxes_type_B else 'no'
627
+ 'yes'
628
+ sage: RiggedConfigurations.options.half_width_boxes_type_B = False
629
+ sage: 'yes' if RiggedConfigurations.options.half_width_boxes_type_B else 'no'
630
+ 'no'
631
+ sage: RiggedConfigurations.options._reset()
632
+ """
633
+ return bool(self._options[self._name])
634
+
635
+ def __call__(self, *args, **kwds):
636
+ r"""
637
+ Get or set value of the option ``self``.
638
+
639
+ EXAMPLES::
640
+
641
+ sage: # needs sage.combinat
642
+ sage: Partitions.options.display() # indirect doctest
643
+ 'list'
644
+ sage: Partitions.options.display('exp') # indirect doctest
645
+ sage: Partitions.options.display() # indirect doctest
646
+ 'exp_low'
647
+ sage: Partitions.options._reset()
648
+
649
+ TESTS:
650
+
651
+ Check that values can be set to ``None`` (:issue:`30763`)::
652
+
653
+ sage: from sage.structure.global_options import GlobalOptions
654
+ sage: class config(GlobalOptions):
655
+ ....: size = dict(default=42,
656
+ ....: description='integer or None',
657
+ ....: checker=lambda val: val is None or val >= 0)
658
+ sage: config.size()
659
+ 42
660
+ sage: config.size(None)
661
+ sage: config.size() is None
662
+ True
663
+ sage: config._reset()
664
+
665
+ Check the deprecation::
666
+
667
+ sage: config.size(value=None)
668
+ doctest:...: DeprecationWarning: keyword argument "value" should be replaced by positional argument
669
+ See https://github.com/sagemath/sage/issues/30763 for details.
670
+ sage: config.size() is None
671
+ True
672
+ sage: config.size(1, 2)
673
+ Traceback (most recent call last):
674
+ ...
675
+ TypeError: option takes at most one argument "value"
676
+ sage: config.size(unknown=3)
677
+ Traceback (most recent call last):
678
+ ...
679
+ TypeError: option takes at most one argument "value"
680
+ sage: config.size(4, value=5)
681
+ Traceback (most recent call last):
682
+ ...
683
+ TypeError: option takes at most one argument "value"
684
+ """
685
+ if not args and not kwds:
686
+ return self._options[self._name]
687
+ if 'value' in kwds:
688
+ from sage.misc.superseded import deprecation
689
+ deprecation(30763, 'keyword argument "value" should be replaced '
690
+ 'by positional argument')
691
+ args += (kwds.pop('value'),)
692
+ if len(args) > 1 or kwds:
693
+ raise TypeError('option takes at most one argument "value"')
694
+ self._options[self._name] = args[0]
695
+
696
+ def __eq__(self, other):
697
+ r"""
698
+ Equality testing for an option in based on the value of the attribute.
699
+
700
+ EXAMPLES::
701
+
702
+ sage: Tableaux.options.convention # needs sage.combinat
703
+ English
704
+ sage: Tableaux.options.convention == "English" # needs sage.combinat
705
+ True
706
+ sage: Tableaux.options.convention == "French" # needs sage.combinat
707
+ False
708
+ """
709
+ return self._options[self._name] == other
710
+
711
+ def __ne__(self, other):
712
+ r"""
713
+ Inequality testing for an option in based on the value of
714
+ the attribute.
715
+
716
+ EXAMPLES::
717
+
718
+ sage: Tableaux.options.convention # needs sage.combinat
719
+ English
720
+ sage: Tableaux.options.convention != "English" # needs sage.combinat
721
+ False
722
+ sage: Tableaux.options.convention != "French" # needs sage.combinat
723
+ True
724
+ """
725
+ return self._options[self._name] != other
726
+
727
+ def __hash__(self):
728
+ r"""
729
+ Return the hash of ``self``, which is the hash of the corresponding
730
+ value.
731
+
732
+ EXAMPLES::
733
+
734
+ sage: hash(Tableaux.options.convention) == hash(Tableaux.options('convention')) # needs sage.combinat
735
+ True
736
+ """
737
+ return hash(self._options[self._name])
738
+
739
+ def __str__(self):
740
+ r"""
741
+ Return the string representation of ``self``, which is the string of
742
+ the corresponding value.
743
+
744
+ EXAMPLES::
745
+
746
+ sage: str(Tableaux.options.convention) # needs sage.combinat
747
+ 'English'
748
+ """
749
+ return str(self._options[self._name])
750
+
751
+
752
+ class GlobalOptionsMetaMeta(type):
753
+ def __call__(self, name, bases, dict):
754
+ """
755
+ Called when subclassing an instance of ``self``.
756
+
757
+ Python translates ``class C(B): ...`` to
758
+ ``meta = type(B); C = meta("C", (B,), ...)``.
759
+ If we want to intercept this call ``meta(...)``, we need to
760
+ customize ``__call__`` in the metaclass of ``meta``, which is
761
+ this metametaclass.
762
+
763
+ EXAMPLES::
764
+
765
+ sage: from sage.structure.global_options import GlobalOptions
766
+ sage: type(GlobalOptions)
767
+ <class 'sage.structure.global_options.GlobalOptionsMeta'>
768
+ sage: type(type(GlobalOptions))
769
+ <class 'sage.structure.global_options.GlobalOptionsMetaMeta'>
770
+ sage: class G(GlobalOptions): pass
771
+ sage: type(G)
772
+ <class 'sage.structure.global_options.GlobalOptions'>
773
+
774
+ Since ``G`` is constructed using ``class`` syntax, the object
775
+ gets a ``__module__`` attribute, different from the
776
+ ``__module__`` attribute of its type (:class:`GlobalOptions`)::
777
+
778
+ sage: G.__module__
779
+ '__main__'
780
+ sage: type(G).__module__
781
+ 'sage.structure.global_options'
782
+
783
+ Multiple base classes are not allowed::
784
+
785
+ sage: class G(GlobalOptions, object): pass
786
+ Traceback (most recent call last):
787
+ ...
788
+ TypeError: GlobalOptions must be the only base class
789
+ """
790
+ # Allow only a single base class (which is GlobalOptions in
791
+ # practice).
792
+ # If we ever find a reasonable meaning for multiple base
793
+ # classes, note that Python 2 and Python 3 have different
794
+ # semantics for determining the metaclass when multiple base
795
+ # classes are involved.
796
+ #
797
+ # Note: On Python 3 bases is empty if the class was declared
798
+ # without any explicted bases:
799
+ if not bases:
800
+ bases = (object,)
801
+
802
+ if len(bases) != 1:
803
+ raise TypeError("GlobalOptions must be the only base class")
804
+
805
+ base = bases[0]
806
+ if not isinstance(base, self):
807
+ # For the creation of the initial GlobalOptions class, fall
808
+ # back to the usual class creation
809
+ return self.__new__(self, name, bases, dict)
810
+
811
+ # Create an instance of the base class (as opposed to an
812
+ # instance of self, which would be typical for a metaclass)
813
+ instance = base.__new__(base)
814
+
815
+ # Split dict in options for instance.__init__ and attributes to
816
+ # insert in the class __dict__
817
+ kwds = {"NAME": name}
818
+ for key, value in dict.items():
819
+ if key.startswith("__"):
820
+ instance.__dict__[key] = value
821
+ else:
822
+ kwds[key] = value
823
+
824
+ instance.__init__(**kwds)
825
+ return instance
826
+
827
+
828
+ class GlobalOptionsMeta(type, metaclass=GlobalOptionsMetaMeta):
829
+ """
830
+ Metaclass for :class:`GlobalOptions`.
831
+
832
+ This class is itself an instance of :class:`GlobalOptionsMetaMeta`,
833
+ which implements the subclass magic.
834
+ """
835
+
836
+
837
+ @instancedoc
838
+ class GlobalOptions(metaclass=GlobalOptionsMeta):
839
+ r"""
840
+ The :class:`GlobalOptions` class is a generic class for setting and
841
+ accessing global options for Sage objects.
842
+
843
+ While it is possible to create instances of :class:`GlobalOptions`
844
+ the usual way, the recommended syntax is to subclass from
845
+ ``GlobalOptions``. Thanks to some metaclass magic, this actually
846
+ creates an instance of ``GlobalOptions`` instead of a subclass.
847
+
848
+ INPUT (as "attributes" of the class):
849
+
850
+ - ``NAME`` -- specifies a name for the options class (optional;
851
+ default: class name)
852
+
853
+ - ``module`` -- gives the module that contains the associated options class
854
+
855
+ - ``option_class`` -- gives the name of the associated module class
856
+ (default: ``NAME``)
857
+
858
+ - option = ``dict(...)`` -- dictionary specifying an option
859
+
860
+ The options are specified by keyword arguments with their values
861
+ being a dictionary which describes the option. The
862
+ allowed/expected keys in the dictionary are:
863
+
864
+ - ``alias`` -- defines alias/synonym for option values
865
+ - ``alt_name`` -- alternative name for an option
866
+ - ``checker`` -- a function for checking whether a particular value for
867
+ the option is valid
868
+ - ``default`` -- the default value of the option
869
+ - ``description`` -- documentation string
870
+ - ``link_to`` -- links to an option for this set of options to an
871
+ option in another :class:`GlobalOptions`
872
+ - ``setter`` -- a function (class method) which is called whenever this
873
+ option changes
874
+ - ``values`` -- dictionary of the legal values for this option (this
875
+ automatically defines the corresponding ``checker``); this dictionary
876
+ gives the possible options, as keys, together with a brief description
877
+ of them
878
+ - ``case_sensitive`` -- boolean (default: ``True``); depending on whether
879
+ the values of the option are case sensitive
880
+
881
+ Options and their values can be abbreviated provided that this
882
+ abbreviation is a prefix of a unique option.
883
+
884
+ EXAMPLES::
885
+
886
+ sage: from sage.structure.global_options import GlobalOptions
887
+ sage: class Menu():
888
+ ....: class options(GlobalOptions):
889
+ ....: '''
890
+ ....: Fancy documentation
891
+ ....: -------------------
892
+ ....:
893
+ ....: @OPTIONS@
894
+ ....:
895
+ ....: End of Fancy documentation
896
+ ....: '''
897
+ ....: NAME = 'menu'
898
+ ....: entree = dict(default='soup',
899
+ ....: description='The first course of a meal',
900
+ ....: values=dict(soup='soup of the day', bread='oven baked'),
901
+ ....: alias=dict(rye='bread'))
902
+ ....: appetizer = dict(alt_name='entree')
903
+ ....: main = dict(default='pizza', description='Main meal',
904
+ ....: values=dict(pizza='thick crust', pasta='penne arrabiata'),
905
+ ....: case_sensitive=False)
906
+ ....: dessert = dict(default='espresso', description='Dessert',
907
+ ....: values=dict(espresso='life begins again',
908
+ ....: cake='waist begins again',
909
+ ....: cream='fluffy white stuff'))
910
+ ....: tip = dict(default=10, description='Reward for good service',
911
+ ....: checker=lambda tip: tip in range(20))
912
+ sage: Menu.options
913
+ Current options for menu
914
+ - dessert: espresso
915
+ - entree: soup
916
+ - main: pizza
917
+ - tip: 10
918
+ sage: Menu.options(entree='s') # unambiguous abbreviations are allowed
919
+ sage: Menu.options(t=15)
920
+ sage: (Menu.options['tip'], Menu.options('t'))
921
+ (15, 15)
922
+ sage: Menu.options()
923
+ Current options for menu
924
+ - dessert: espresso
925
+ - entree: soup
926
+ - main: pizza
927
+ - tip: 15
928
+ sage: Menu.options._reset(); Menu.options()
929
+ Current options for menu
930
+ - dessert: espresso
931
+ - entree: soup
932
+ - main: pizza
933
+ - tip: 10
934
+ sage: Menu.options.tip=40
935
+ Traceback (most recent call last):
936
+ ...
937
+ ValueError: 40 is not a valid value for tip in the options for menu
938
+ sage: Menu.options(m='p') # ambiguous abbreviations are not allowed
939
+ Traceback (most recent call last):
940
+ ...
941
+ ValueError: p is not a valid value for main in the options for menu
942
+
943
+ The documentation for the options class is automatically generated from the
944
+ information which specifies the options:
945
+
946
+ .. CODE-BLOCK:: text
947
+
948
+ Fancy documentation
949
+ -------------------
950
+
951
+ OPTIONS:
952
+
953
+ - dessert: (default: espresso)
954
+ Dessert
955
+
956
+ - ``cake`` -- waist begins again
957
+ - ``cream`` -- fluffy white stuff
958
+ - ``espresso`` -- life begins again
959
+
960
+ - entree: (default: soup)
961
+ The first course of a meal
962
+
963
+ - ``bread`` -- oven baked
964
+ - ``rye`` -- alias for bread
965
+ - ``soup`` -- soup of the day
966
+
967
+ - main: (default: pizza)
968
+ Main meal
969
+
970
+ - ``pasta`` -- penne arrabiata
971
+ - ``pizza`` -- thick crust
972
+
973
+ - tip: (default: 10)
974
+ Reward for good service
975
+
976
+ End of Fancy documentation
977
+
978
+ See :class:`~sage.structure.global_options.GlobalOptions` for more features of these options.
979
+
980
+ The possible values for an individual option can be obtained by
981
+ (trying to) set it equal to '?'::
982
+
983
+ sage: Menu.options(des='?')
984
+ - ``dessert`` -- (default: ``espresso``)
985
+ Dessert
986
+ <BLANKLINE>
987
+ - ``cake`` -- waist begins again
988
+ - ``cream`` -- fluffy white stuff
989
+ - ``espresso`` -- life begins again
990
+ <BLANKLINE>
991
+ Current value: espresso
992
+ """
993
+ __name__ = 'options'
994
+
995
+ def __init__(self, NAME=None, module='', option_class='', doc='', end_doc='', **options):
996
+ r"""
997
+ Initialize ``self``.
998
+
999
+ TESTS::
1000
+
1001
+ sage: from sage.structure.global_options import GlobalOptions
1002
+ sage: class menu(GlobalOptions):
1003
+ ....: entree = dict(default='soup',
1004
+ ....: description='The first course of a meal',
1005
+ ....: values=dict(soup='soup of the day', bread='oven baked'),
1006
+ ....: alias=dict(rye='bread'))
1007
+ ....: appetizer = dict(alt_name='entree')
1008
+ ....: main = dict(default='pizza', description='Main meal',
1009
+ ....: values=dict(pizza='thick crust', pasta='penne arrabiata'),
1010
+ ....: case_sensitive=False)
1011
+ ....: dessert = dict(default='espresso', description='Dessert',
1012
+ ....: values=dict(espresso='life begins again',
1013
+ ....: cake='waist begins again',
1014
+ ....: cream='fluffy white stuff'))
1015
+ ....: tip = dict(default=10, description='Reward for good service',
1016
+ ....: checker=lambda tip: tip in range(20))
1017
+ sage: menu._name # Default name is class name
1018
+ 'menu'
1019
+ sage: class specials(GlobalOptions):
1020
+ ....: entree = dict(link_to=(menu, 'entree'))
1021
+ ....: main_specials = dict(default='salmon', description='main course specials',
1022
+ ....: values=dict(salmon='a fish', crab='Sebastian'))
1023
+ sage: specials['entree'] = 'rye'
1024
+ sage: menu['entree']
1025
+ 'bread'
1026
+
1027
+ sage: class alias_test(GlobalOptions):
1028
+ ....: "Test aliases with case sensitivity"
1029
+ ....: test_opt = dict(default='Upper',
1030
+ ....: description = 'Starts with an uppercase',
1031
+ ....: values = dict(Upper="Starts with uppercase",
1032
+ ....: lower="only lowercase"),
1033
+ ....: case_sensitive = False,
1034
+ ....: alias = dict(UpperAlias='Upper', lower_alias='lower'))
1035
+ sage: alias_test['test_opt'] = 'Lower_Alias'
1036
+ sage: alias_test['test_opt']
1037
+ 'lower'
1038
+ sage: alias_test['test_opt'] = 'upperalias'
1039
+ sage: alias_test['test_opt']
1040
+ 'Upper'
1041
+ """
1042
+ if NAME is None:
1043
+ # Require a "name" keyword in **options
1044
+ try:
1045
+ NAME = options.pop("name")
1046
+ except KeyError:
1047
+ raise TypeError("GlobalOptions() is missing keyword argument 'name'")
1048
+ self._name = NAME
1049
+
1050
+ # initialise the various dictionaries used by GlobalOptions
1051
+ self._alias = {} # a dictionary of alias for the values of some options
1052
+ self._alt_names = {} # a dictionary of alternative names for some options
1053
+ self._case_sensitive = {} # a dictionary of booleans indicating to check case sensitivity
1054
+ self._checker = {} # a dictionary of validity checkers for each option
1055
+ self.__default_value = {} # a dictionary of the default options
1056
+ self._display_values = {} # a dictionary of the output of the values
1057
+ self._doc = {} # a dictionary of doc strings, forced by the linked options
1058
+ self._legal_values = {} # a dictionary of lists of the legal values for each option
1059
+ self._linked_value = {} # a dictionary of linked to other global options as (link, linked_option)
1060
+ self._setter = {} # a dictionary of the list of setters
1061
+ self._value = {} # a dictionary of the current options
1062
+ for option in options:
1063
+ self._add_option(option, options[option])
1064
+
1065
+ self._options_module = module
1066
+ self._option_class = option_class or self._name
1067
+
1068
+ # If the instance dict has a __doc__ attribute, use that as
1069
+ # docstring.
1070
+ try:
1071
+ self._docstring = dedent(self.__dict__.pop("__doc__"))
1072
+ except KeyError:
1073
+ self._docstring = "@OPTIONS@"
1074
+
1075
+ # Finally, we build the doc string for the options
1076
+ # First we strip common white space off the front of doc and end_doc
1077
+ if doc:
1078
+ self._docstring = dedent(doc) + "\n\n" + self._docstring
1079
+
1080
+ if end_doc:
1081
+ self._docstring = self._docstring + "\n\n" + dedent(end_doc)
1082
+
1083
+ # Add docstring footer
1084
+ self._docstring += "\nSee :class:`~sage.structure.global_options.GlobalOptions` for more features of these options."
1085
+
1086
+ def __repr__(self):
1087
+ r"""
1088
+ Return a string representation for this collection of options.
1089
+
1090
+ EXAMPLES::
1091
+
1092
+ sage: from sage.structure.global_options import GlobalOptions
1093
+ sage: class FoodOptions(GlobalOptions):
1094
+ ....: NAME = 'daily meal'
1095
+ ....: food = dict(default='apple', values=dict(apple='a fruit', pair='of what?'))
1096
+ ....: drink = dict(default='water', values=dict(water='a drink', coffee='a lifestyle'))
1097
+ sage: FoodOptions
1098
+ Current options for daily meal
1099
+ - drink: water
1100
+ - food: apple
1101
+ """
1102
+ options = list(self._value) + list(self._linked_value)
1103
+ for x in self._alt_names:
1104
+ options.remove(x)
1105
+ if not options:
1106
+ return 'Current options for {}'.format(self._name)
1107
+
1108
+ options.sort()
1109
+ width = 1 + max(len(option) for option in options)
1110
+ txt = '\n'.join(' - {:{}} {}'.format(option + ':', width, self[option])
1111
+ for option in options)
1112
+ return 'Current options for {}\n{}'.format(self._name, txt)
1113
+
1114
+ def __call__(self, *get_value, **set_value):
1115
+ r"""
1116
+ Get or set value of the option ``option``.
1117
+
1118
+ EXAMPLES::
1119
+
1120
+ sage: from sage.structure.global_options import GlobalOptions
1121
+ sage: class FoodOptions(GlobalOptions):
1122
+ ....: NAME = 'daily meal'
1123
+ ....: food = dict(default='apple', values=dict(apple='a fruit', pair='of what?'))
1124
+ ....: drink = dict(default='water', values=dict(water='a drink', coffee='a lifestyle'))
1125
+ ....: beverage = dict(alt_name='drink')
1126
+ sage: FoodOptions()
1127
+ Current options for daily meal
1128
+ - drink: water
1129
+ - food: apple
1130
+ sage: FoodOptions('food')
1131
+ 'apple'
1132
+ sage: FoodOptions(food='pair'); FoodOptions()
1133
+ Current options for daily meal
1134
+ - drink: water
1135
+ - food: pair
1136
+ sage: FoodOptions('beverage')
1137
+ 'water'
1138
+ sage: FoodOptions(food='apple', drink='coffee'); FoodOptions()
1139
+ Current options for daily meal
1140
+ - drink: coffee
1141
+ - food: apple
1142
+ """
1143
+ if not get_value and not set_value:
1144
+ return self
1145
+
1146
+ if get_value:
1147
+ # use __getitem__ to return these options
1148
+ if len(get_value) == 1:
1149
+ return self[get_value[0]]
1150
+ else:
1151
+ return [self[option] for option in get_value]
1152
+
1153
+ # use __setitem__ to set these options
1154
+ if set_value:
1155
+ for option in set_value:
1156
+ self[option] = set_value[option]
1157
+
1158
+ def __getitem__(self, option):
1159
+ r"""
1160
+ Return the current value of the option ``option``.
1161
+
1162
+ EXAMPLES::
1163
+
1164
+ sage: from sage.structure.global_options import GlobalOptions
1165
+ sage: class FoodOptions(GlobalOptions):
1166
+ ....: NAME = 'daily meal'
1167
+ ....: food = dict(default='apple', values=dict(apple='a fruit', pair='of what?'))
1168
+ ....: drink = dict(default='water', values=dict(water='a drink', coffee='a lifestyle'))
1169
+ sage: FoodOptions['drink']
1170
+ 'water'
1171
+ sage: FoodOptions['d']
1172
+ 'water'
1173
+ """
1174
+ option = self._match_option(option)
1175
+ if option in self._linked_value:
1176
+ link, linked_opt = self._linked_value[option]
1177
+ return link[linked_opt]
1178
+ elif option in self._value:
1179
+ if option in self._display_values:
1180
+ return self._display_values[option][self._value[option]]
1181
+ return self._value[option]
1182
+
1183
+ def __setitem__(self, option, value):
1184
+ r"""
1185
+ The ``__setitem__`` method is used to change the current values of the
1186
+ options. It also checks that the supplied options are valid and changes
1187
+ any alias to its generic value.
1188
+
1189
+ EXAMPLES::
1190
+
1191
+ sage: from sage.structure.global_options import GlobalOptions
1192
+ sage: class FoodOptions(GlobalOptions):
1193
+ ....: NAME = 'daily meal'
1194
+ ....: food = dict(default='apple', values=dict(apple='a fruit', pair='of what?'))
1195
+ ....: drink = dict(default='water', values=dict(water='a drink', coffee='a lifestyle'))
1196
+ sage: FoodOptions['drink']='coffee'; FoodOptions()
1197
+ Current options for daily meal
1198
+ - drink: coffee
1199
+ - food: apple
1200
+ sage: FoodOptions(drink='w'); FoodOptions()
1201
+ Current options for daily meal
1202
+ - drink: water
1203
+ - food: apple
1204
+ sage: FoodOptions(drink='?')
1205
+ - ``drink`` -- (default: ``water``)
1206
+ <BLANKLINE>
1207
+ - ``coffee`` -- a lifestyle
1208
+ - ``water`` -- a drink
1209
+ <BLANKLINE>
1210
+ Current value: water
1211
+ """
1212
+ option = self._match_option(option)
1213
+ if not callable(value):
1214
+ value = self._match_value(option, value)
1215
+
1216
+ if value == '?': # return help
1217
+ print('%s\nCurrent value: %s' % (self._doc[option], self[option]))
1218
+ return # we do not want to call the setter below
1219
+
1220
+ elif option in self._linked_value:
1221
+ link, linked_opt = self._linked_value[option]
1222
+ link[linked_opt] = value
1223
+
1224
+ else:
1225
+ self._value[option] = value
1226
+
1227
+ if option in self._setter:
1228
+ # if a setter function exists then call it with the associated
1229
+ # class, option and value
1230
+ self._setter[option](option, value)
1231
+
1232
+ def _instancedoc_(self):
1233
+ r"""
1234
+ Return the docstring for the options class ``self``.
1235
+
1236
+ EXAMPLES::
1237
+
1238
+ sage: print(Partitions.options.__doc__)
1239
+ <BLANKLINE>
1240
+ Set and display the global options for elements of the partition,
1241
+ skew partition, and partition tuple classes. If no parameters are
1242
+ set, then the function returns a copy of the options dictionary.
1243
+ <BLANKLINE>
1244
+ The ``options`` to partitions can be accessed as the method
1245
+ :obj:`Partitions.options` of :class:`Partitions` and
1246
+ related parent classes.
1247
+ <BLANKLINE>
1248
+ <BLANKLINE>
1249
+ OPTIONS:
1250
+ <BLANKLINE>
1251
+ - ``convention`` -- (default: ``English``)
1252
+ Sets the convention used for displaying tableaux and partitions
1253
+ <BLANKLINE>
1254
+ - ``English`` -- use the English convention
1255
+ - ``French`` -- use the French convention
1256
+ ...
1257
+
1258
+ TESTS::
1259
+
1260
+ sage: from sage.structure.global_options import GlobalOptions
1261
+ sage: print(GlobalOptions.__doc__)
1262
+ <BLANKLINE>
1263
+ The :class:`GlobalOptions` class is a generic class for setting...
1264
+ """
1265
+ options = 'OPTIONS:\n\n{}\n\n'.format('\n'.join(self._doc[opt] for opt in sorted(self._doc)))
1266
+ return self._docstring.replace("@OPTIONS@", options)
1267
+
1268
+ def __setattr__(self, name, value=None):
1269
+ r"""
1270
+ Set the attribute ``name`` of the option class ``self`` equal to
1271
+ ``value``, if the attribute ``name`` exists.
1272
+
1273
+ As the attributes of an option class are the actual options we need
1274
+ to be able to "trap" invalid options in a sensible way. We do this
1275
+ by sending any "non-standard" to :meth:`__setitem__` for processing.
1276
+
1277
+ EXAMPLES::
1278
+
1279
+ sage: Partitions.options.display = 'exp'
1280
+ sage: Partitions.options.dispplay = 'list'
1281
+ Traceback (most recent call last):
1282
+ ...
1283
+ ValueError: dispplay is not an option for Partitions
1284
+ sage: Partitions.options._reset()
1285
+ """
1286
+ # Underscore, and "special", attributes are set using type.__setattr__
1287
+ if name[0] == '_' or name in ['reset', 'dispatch', 'default_value']:
1288
+ return super().__setattr__(name, value)
1289
+
1290
+ # General case: redirect to __setitem__
1291
+ self[name] = value
1292
+
1293
+ def __setstate__(self, state):
1294
+ r"""
1295
+ This is a custom :meth:`__setstate__` method for unpickling instances of
1296
+ the :class:`GlobalOptions` class.
1297
+
1298
+ The :meth:`__getstate__` method returns a dictionary with an
1299
+ ``options_class`` key which identifies the "parent" class for the options.
1300
+ This is then used to unpickle the options class.
1301
+
1302
+ EXAMPLES::
1303
+
1304
+ sage: # needs sage.combinat
1305
+ sage: Partitions.options()
1306
+ Current options for Partitions
1307
+ - convention: English
1308
+ - diagram_str: *
1309
+ - display: list
1310
+ - latex: young_diagram
1311
+ - latex_diagram_str: \ast
1312
+ sage: Partitions.options.convention = "French"
1313
+ sage: pickle = dumps(Partitions.options)
1314
+ sage: Partitions.options._reset() # reset options
1315
+ sage: loads(pickle) # indirect doctest
1316
+ Current options for Partitions
1317
+ - convention: French
1318
+ - diagram_str: *
1319
+ - display: list
1320
+ - latex: young_diagram
1321
+ - latex_diagram_str: \ast
1322
+ sage: Partitions.options._reset()
1323
+ """
1324
+ # open the options for the corresponding "parent" and copy all of
1325
+ # the data from its options class into unpickle
1326
+ options_class = getattr(import_module(state['options_module']), state['option_class'])
1327
+ unpickle = options_class.options
1328
+ state.pop('option_class')
1329
+ state.pop('options_module')
1330
+ for setting in unpickle.__dict__:
1331
+ self.__dict__[setting] = unpickle.__dict__[setting]
1332
+
1333
+ # reset the options in ``self`` to their defaults
1334
+ self._reset()
1335
+ # apply the options stored in state
1336
+ for opt in state:
1337
+ self[opt] = state[opt]
1338
+ options_class.options = self
1339
+
1340
+ def __getstate__(self):
1341
+ r"""
1342
+ Return a dictionary that can be used to pickle an instance of a
1343
+ :class:`GlobalOptions` class.
1344
+
1345
+ This is called by :func:`pickle_GlobalOptions`.
1346
+
1347
+ Typically instances of :class:`GlobalOptions` are
1348
+ complicated to create, so they do no pickle. If the options are
1349
+ associated to "parent" class then it is possible to create the
1350
+ default version of the class and then add the non-default
1351
+ settings on top of this. This method returns a dictionary of the
1352
+ non-default options that can then be used to unpickle an
1353
+ instance of the option using :func:`unpickle_GlobalOptions`.
1354
+
1355
+ EXAMPLES::
1356
+
1357
+ sage: Partitions.options._reset()
1358
+ sage: Partitions.options.__getstate__()
1359
+ {'convention': 'English',
1360
+ 'option_class': 'Partitions',
1361
+ 'options_module': 'sage.combinat.partition'}
1362
+ """
1363
+
1364
+ # options classes can be pickled only if they are the options for an
1365
+ # associated "parent" class that lives in self._module
1366
+
1367
+ if not self._options_module:
1368
+ pickleable = False
1369
+ else:
1370
+ opt_mod = import_module(self._options_module)
1371
+ pickleable = hasattr(opt_mod, self._name) and hasattr(getattr(opt_mod, self._name), 'options')
1372
+
1373
+ if not pickleable:
1374
+ raise PicklingError('%s cannot be pickled because it is not associated with a class' % self)
1375
+
1376
+ pickle = {'option_class': self._option_class, 'options_module': self._options_module}
1377
+ for opt in self._value:
1378
+ if opt not in self._alt_names and self[opt] != self.__default_value[opt]:
1379
+ pickle[opt] = self[opt]
1380
+ for opt in self._linked_value:
1381
+ link, linked_opt = self._linked_value[opt]
1382
+ if opt not in self._alt_names and link[opt] != link.__default_value[opt]:
1383
+ pickle[opt] = self[opt]
1384
+ return pickle
1385
+
1386
+ def __eq__(self, other):
1387
+ r"""
1388
+ Two options classes are equal if they return the same :meth:`__getstate__`.
1389
+
1390
+ EXAMPLES::
1391
+
1392
+ sage: Partitions.options == PartitionsGreatestLE.options # indirect doctest
1393
+ True
1394
+ sage: Partitions.options == Tableaux.options # needs sage.combinat
1395
+ False
1396
+ """
1397
+ return isinstance(other, GlobalOptions) and self.__getstate__() == other.__getstate__()
1398
+
1399
+ def _add_option(self, option, specifications):
1400
+ r"""
1401
+ Add an option.
1402
+
1403
+ INPUT:
1404
+
1405
+ - ``option`` -- string
1406
+ - ``specifications`` -- dictionary
1407
+
1408
+ .. SEEALSO::
1409
+
1410
+ :class:`GlobalOptions` for a description of the required
1411
+ ``specifications``.
1412
+ """
1413
+ if not isinstance(specifications, dict):
1414
+ raise TypeError("expected dict as specification of %r, got %r" % (option, specifications))
1415
+
1416
+ doc = {} # will be used to build the doc string
1417
+ self._case_sensitive[option] = True # ``True`` by default
1418
+ self._legal_values[option] = []
1419
+ for spec in sorted(specifications): # NB: options processed alphabetically!
1420
+ if spec == 'alias':
1421
+ self._alias[option] = specifications[spec]
1422
+ self._legal_values[option] += list(specifications[spec])
1423
+ for opt in specifications[spec]:
1424
+ doc[opt] = 'alias for ``%s``' % specifications[spec][opt]
1425
+ elif spec == 'alt_name':
1426
+ self._alt_names[option] = specifications[spec]
1427
+ self._linked_value[option] = (self, specifications[spec])
1428
+ doc = '- ``%s`` -- alternative name for ``%s``' % (option, specifications[spec].lower())
1429
+ elif spec == 'case_sensitive':
1430
+ if not specifications[spec]:
1431
+ for opt in self._legal_values:
1432
+ self._display_values[option] = {val.lower(): val for val in self._legal_values[option]}
1433
+ self._legal_values[option] = [val.lower() for val in self._legal_values[option]]
1434
+ if option in self._alias:
1435
+ self._alias[option] = {k.lower(): v.lower()
1436
+ for k, v in self._alias[option].items()}
1437
+ self._case_sensitive[option] = bool(specifications[spec])
1438
+ elif spec == 'checker':
1439
+ if not callable(specifications[spec]):
1440
+ raise ValueError('the checker for %s must be callable' % option)
1441
+ self._checker[option] = specifications[spec]
1442
+ elif spec == 'default':
1443
+ self.__default_value[option] = specifications[spec]
1444
+ elif spec == 'link_to':
1445
+ if (isinstance(specifications[spec], tuple) and
1446
+ len(specifications[spec]) == 2 and
1447
+ isinstance(specifications[spec][0], GlobalOptions)):
1448
+ link, linked_opt = specifications['link_to'] # for sanity
1449
+ if linked_opt in link._value:
1450
+ self._linked_value[option] = specifications['link_to']
1451
+ link, linked_opt = specifications['link_to'] # for sanity
1452
+ doc = link._doc[linked_opt]
1453
+ elif linked_opt in link._linked_value:
1454
+ self._linked_value[option] = link._linked_value[linked_opt]
1455
+ doc = link._doc[linked_opt]
1456
+ else:
1457
+ raise ValueError("could not find link to {1} in {0}".format(*specifications[spec]))
1458
+ else:
1459
+ raise ValueError("linked options must be specified as a string: 'linked_option' or a tuple: (link,linked_option)")
1460
+ elif spec == 'setter':
1461
+ if callable(specifications[spec]):
1462
+ self._setter[option] = specifications[spec]
1463
+ else:
1464
+ raise ValueError('the setter for %s must be a function' % option)
1465
+ elif spec == 'values':
1466
+ for val in specifications[spec]:
1467
+ doc[val] = specifications[spec][val]
1468
+ doc.update(specifications[spec])
1469
+ if self._case_sensitive[option]:
1470
+ self._legal_values[option] += list(specifications[spec])
1471
+ self._display_values[option] = {val: val for val in specifications[spec]}
1472
+ else:
1473
+ self._legal_values[option] += [val.lower() for val in specifications[spec]]
1474
+ self._display_values[option] = {val.lower(): val for val in specifications[spec]}
1475
+ elif spec != 'description':
1476
+ raise ValueError('Initialization error in Global options for %s: %s not recognized!' % (self._name, spec))
1477
+
1478
+ # now build the doc string for this option
1479
+ if doc == {} and 'description' not in specifications:
1480
+ raise ValueError('no documentation specified for %s in the options for %s' % (option, self._name))
1481
+
1482
+ # first a necessary hack to initialise the option in self._doc because __setitem__ calls _match_option
1483
+ self._doc[option] = ''
1484
+ if option in self._linked_value:
1485
+ self._doc[option] = doc
1486
+ else:
1487
+ width = max(len(v) for v in doc) + 4 if doc != {} else 4
1488
+ if len(doc) > 0:
1489
+ self._doc[option] = '- ``{}`` -- (default: ``{}``)\n{}\n{}\n'.format(
1490
+ option, self._default_value(option),
1491
+ ' %s\n' % specifications['description'] if 'description' in specifications else '',
1492
+ '\n'.join(' - {:{}} -- {}'.format('``' + val + '``', width, doc[val])
1493
+ for val in sorted(doc)))
1494
+ else:
1495
+ self._doc[option] = '- ``{}`` -- (default: ``{}``)\n{}'.format(
1496
+ option, self._default_value(option),
1497
+ ' %s\n' % specifications['description'] if 'description' in specifications else '')
1498
+
1499
+ # sanity check for non-linked options
1500
+ if option not in self._linked_value:
1501
+ if 'default' not in specifications:
1502
+ raise ValueError('a default value for %s must be given' % option)
1503
+
1504
+ if not (option in self._checker or option in self._legal_values):
1505
+ raise ValueError('a value checker or a list of valid values for %s must be given' % option)
1506
+
1507
+ # finally, set, check and process the default value using __setitem__
1508
+ self[option] = self.__default_value[option]
1509
+ self.__default_value[option] = self._value[option] # in case the default is an alias
1510
+
1511
+ # Build getters and setters for this option. As we have
1512
+ # overridden __setattr__, we call object.__setattr__ directly
1513
+ super().__setattr__(option, Option(self, option))
1514
+
1515
+ def _match_option(self, option):
1516
+ r"""
1517
+ Check whether ``option`` is the name of an option of ``self``, or a
1518
+ prefix thereof.
1519
+
1520
+ INPUT:
1521
+
1522
+ - ``option`` -- string
1523
+
1524
+ EXAMPLES::
1525
+
1526
+ sage: from sage.structure.global_options import GlobalOptions
1527
+ sage: class FoodOptions(GlobalOptions):
1528
+ ....: NAME = 'daily meal'
1529
+ ....: food = dict(default='apple', values=dict(apple='a fruit', pair='of what?'))
1530
+ ....: drink = dict(default='water', values=dict(water='a drink', coffee='a lifestyle'))
1531
+ sage: FoodOptions('food') # indirect doctest
1532
+ 'apple'
1533
+ sage: FoodOptions('f')
1534
+ 'apple'
1535
+ """
1536
+ if option in self._doc:
1537
+ return option
1538
+
1539
+ # a lower case version of the option
1540
+ loption = option.lower()
1541
+
1542
+ # as it is not an option try and match it with a prefix to an option,
1543
+ # without checking case using the fact that the keys of self._doc is a
1544
+ # list of the options, both normal and linked
1545
+ matches = [opt for opt in self._doc if opt.lower().startswith(loption)]
1546
+ if matches and all(m.startswith(matches[0]) for m in matches):
1547
+ return matches[0]
1548
+ elif len(matches) > 1:
1549
+ # as there is more than one match check case as well
1550
+ matches = [mat for mat in matches if mat.startswith(option)]
1551
+ if matches and all(m.startswith(matches[0]) for m in matches):
1552
+ return matches[0]
1553
+ else:
1554
+ raise ValueError('%s is an ambiguous option for %s' % (option, self._name))
1555
+
1556
+ # if we are still here this is not a good option!
1557
+ raise ValueError('%s is not an option for %s' % (option, self._name))
1558
+
1559
+ def _match_value(self, option, value):
1560
+ r"""
1561
+ Check whether ``value`` is a valid value for ``option``.
1562
+
1563
+ INPUT:
1564
+
1565
+ - ``option`` -- string: the name of an option, or prefix thereof
1566
+ - ``value`` -- a value or ``'?'``
1567
+
1568
+ EXAMPLES::
1569
+
1570
+ sage: from sage.structure.global_options import GlobalOptions
1571
+ sage: class FoodOptions(GlobalOptions):
1572
+ ....: NAME = 'daily meal'
1573
+ ....: food = dict(default='apple', values=dict(apple='a fruit', pair='of what?'))
1574
+ ....: drink = dict(default='water', values=dict(water='a drink', wine='a lifestyle'))
1575
+ sage: FoodOptions(f='a') # indirect doctest
1576
+ sage: FoodOptions('f')
1577
+ 'apple'
1578
+ sage: FoodOptions(d='wi'); FoodOptions('f')
1579
+ 'apple'
1580
+ sage: FoodOptions(d='w')
1581
+ Traceback (most recent call last):
1582
+ ...
1583
+ ValueError: w is not a valid value for drink in the options for daily meal
1584
+ """
1585
+ if value == "?":
1586
+ return value # help on this value
1587
+
1588
+ if option in self._linked_value:
1589
+ link, linked_opt = self._linked_value[option]
1590
+ return link._match_value(linked_opt, value)
1591
+
1592
+ orig_value = value
1593
+
1594
+ # convert to proper case if it is a string
1595
+ if isinstance(value, str) and not self._case_sensitive[option]:
1596
+ value = value.lower()
1597
+
1598
+ if option in self._legal_values:
1599
+ if value in self._legal_values[option]:
1600
+ if option in self._alias and value in self._alias[option]:
1601
+ return self._alias[option][value]
1602
+ return value
1603
+
1604
+ # as it is not a value try and match it with a prefix of a value
1605
+ matches = [val for val in self._legal_values[option] if val.startswith(value)]
1606
+ if matches and all(m.startswith(matches[0]) for m in matches):
1607
+ val = matches[0]
1608
+ if option in self._alias and val in self._alias[option]:
1609
+ return self._alias[option][val]
1610
+ return val
1611
+
1612
+ if option in self._checker and self._checker[option](value):
1613
+ return value
1614
+
1615
+ # if we are still here this is not a good value!
1616
+
1617
+ # replace any value alias with its "real" value
1618
+ if option in self._alias and value in self._alias[option]:
1619
+ orig_value = self._alias[option][value]
1620
+ raise ValueError('%s is not a valid value for %s in the options for %s' % (orig_value, option, self._name))
1621
+
1622
+ def _default_value(self, option):
1623
+ r"""
1624
+ Return the default value of the option.
1625
+
1626
+ EXAMPLES::
1627
+
1628
+ sage: from sage.structure.global_options import GlobalOptions
1629
+ sage: class FoodOptions(GlobalOptions):
1630
+ ....: NAME = 'daily meal'
1631
+ ....: food = dict(default='apple', values=dict(apple='a fruit', pair='of what?'))
1632
+ ....: drink = dict(default='water', values=dict(water='a drink', coffee='a lifestyle'))
1633
+ sage: FoodOptions._default_value('food')
1634
+ 'apple'
1635
+ """
1636
+ option = self._match_option(option)
1637
+ if option in self.__default_value:
1638
+ return self.__default_value[option]
1639
+ else:
1640
+ link, linked_opt = self._linked_value[option]
1641
+ return link._default_value(linked_opt)
1642
+
1643
+ def _dispatch(self, obj, dispatch_to, option, *args, **kargs):
1644
+ r"""
1645
+ The *dispatchable* options are options which dispatch related methods of
1646
+ the corresponding class - or user defined methods which are passed to
1647
+ :class:`GlobalOptions`. The format for specifying a dispatchable option
1648
+ is to include ``dispatch_to = <option name>`` in the specifications for
1649
+ the options and then to add the options to the (element) class. Each
1650
+ option is then assumed to be a method of the element class with a name
1651
+ of the form ``<option name> + '_' + <current vale for this option'``.
1652
+ These options are called by the element class via::
1653
+
1654
+ return self.options._dispatch(self, dispatch_to, option, *args, **kargs)
1655
+
1656
+ Note that the argument ``self`` is necessary here because the
1657
+ dispatcher is a method of the options class and not of
1658
+ ``self``. The value of the option can also be set to a
1659
+ user-defined function, with arguments ``self`` and ``option``;
1660
+ in this case the user's function is called instead.
1661
+
1662
+ EXAMPLES:
1663
+
1664
+ Here is a contrived example::
1665
+
1666
+ sage: from sage.structure.global_options import GlobalOptions
1667
+ sage: class DelimitedListOptions(GlobalOptions):
1668
+ ....: delim=dict(default='b', values={'b':'brackets', 'p':'parentheses'})
1669
+ sage: class DelimitedList(SageObject):
1670
+ ....: options = DelimitedListOptions
1671
+ ....: def __init__(self, L):
1672
+ ....: self._list = L
1673
+ ....: def _repr_b(self): return '[%s]' % ','.join('%s'%i for i in self._list)
1674
+ ....: def _repr_p(self): return '(%s)' % ','.join('%s'%i for i in self._list)
1675
+ ....: def _repr_(self): return self.options._dispatch(self, '_repr_','delim')
1676
+ sage: dlist = DelimitedList([1,2,3]); dlist
1677
+ [1,2,3]
1678
+ sage: dlist.options.delim='p'; dlist
1679
+ (1,2,3)
1680
+ sage: dlist.options(delim=lambda self: '<%s>' % ','.join('%s'%i for i in self._list)); dlist
1681
+ <1,2,3>
1682
+ """
1683
+ if callable(self._value[option]):
1684
+ try:
1685
+ return self._value[option](obj, *args, **kargs)
1686
+ except TypeError:
1687
+ raise ValueError('the user defined dispatcher function failed!')
1688
+ else:
1689
+ if dispatch_to[-1] == '_':
1690
+ dispatch_to = dispatch_to[:-1]
1691
+ dispatch = getattr(obj, dispatch_to + '_' + self._value[option])
1692
+ return dispatch(*args, **kargs)
1693
+
1694
+ raise ValueError('%s is not a dispatchable option!' % option)
1695
+
1696
+ def _reset(self, option=None):
1697
+ r"""
1698
+ Reset options to their default value.
1699
+
1700
+ INPUT:
1701
+
1702
+ - ``option`` -- (default: ``None``) the name of an option as a string
1703
+ or ``None``. If ``option`` is specified only this option is reset to
1704
+ its default value; otherwise all options are reset.
1705
+
1706
+ EXAMPLES::
1707
+
1708
+ sage: from sage.structure.global_options import GlobalOptions
1709
+ sage: class Meal():
1710
+ ....: class options(GlobalOptions):
1711
+ ....: NAME = 'daily meal'
1712
+ ....: food = dict(default='bread', values=dict(bread='rye bread', salmon='a fish'))
1713
+ ....: drink = dict(default='water',values=dict(water='essential for life', wine='essential'))
1714
+ sage: Meal.options.food='salmon'; Meal.options
1715
+ Current options for daily meal
1716
+ - drink: water
1717
+ - food: salmon
1718
+ sage: Meal.options._reset('drink'); Meal.options()
1719
+ Current options for daily meal
1720
+ - drink: water
1721
+ - food: salmon
1722
+ sage: Meal.options._reset(); Meal.options()
1723
+ Current options for daily meal
1724
+ - drink: water
1725
+ - food: bread
1726
+ """
1727
+ if option is None:
1728
+ for option in self.__default_value:
1729
+ self._value[option] = self.__default_value[option]
1730
+ if not self._case_sensitive[option] and isinstance(self._value[option], str):
1731
+ self._value[option] = self._value[option].lower()
1732
+ for option in self._linked_value:
1733
+ link, linked_opt = self._linked_value[option]
1734
+ link._reset(linked_opt)
1735
+ else:
1736
+ option = self._match_option(option)
1737
+ if option in self.__default_value:
1738
+ self._value[option] = self.__default_value[option]
1739
+ if not self._case_sensitive[option] and isinstance(self._value[option], str):
1740
+ self._value[option] = self._value[option].lower()
1741
+ elif option in self._linked_value:
1742
+ link, linked_opt = self._linked_value[option]
1743
+ link._reset(linked_opt)