Ticket #14248: trac_14248-global_options_case-ts.patch

File trac_14248-global_options_case-ts.patch, 25.0 KB (added by Travis Scrimshaw, 9 years ago)
  • sage/combinat/output.py

    # HG changeset patch
    # User Travis Scrimshaw <tscrim@ucdavis.edu>
    # Date 1363015327 25200
    # Node ID 4698acde860867da56b69ed39c37d1665fc704bb
    # Parent c62ef5b1ce5ab859511522633d1da93b87e26e7d
    #14248: Add case checks to global options.
    * * *
    Fixing doc-strngs and fine-tuning case sensitivity
    
    diff --git a/sage/combinat/output.py b/sage/combinat/output.py
    a b def tex_from_array(array, with_lines=Tru 
    167167        sage: Tableaux.global_options.reset()
    168168    """
    169169    lr=lr_macro.substitute(bar='|' if with_lines else '')
    170     if Tableaux.global_options("convention")=='english':
     170    if Tableaux.global_options("convention") == "English":
    171171        return '{%s\n%s\n}' % (lr, tex_from_skew_array(array, with_lines))
    172172    else:
    173173        return '{%s\n%s\n}' % (lr, tex_from_skew_array(array[::-1], with_lines, align='t'))
    def tex_from_array_tuple(a_tuple, with_l 
    236236        }
    237237    """
    238238    lr=lr_macro.substitute(bar='|' if with_lines else '')
    239     if Tableaux.global_options("convention")=='english':
     239    if Tableaux.global_options("convention") == "English":
    240240        return '{%s\n%s\n}' % (lr, ','.join(
    241241            r'\emptyset' if comp==[] else tex_from_skew_array(comp, with_lines) for comp in a_tuple))
    242242    else:
  • sage/combinat/partition.py

    diff --git a/sage/combinat/partition.py b/sage/combinat/partition.py
    a b PartitionOptions=GlobalOptions(name='par 
    380380                 alias=dict(exp="exp_low", compact="compact_low", array="diagram",
    381381                           ferrers_diagram="diagram", young_diagram="diagram",
    382382                           ferrers_diagram_str="diagram_str",young_diagram_str="diagram_str"),
    383                 ),
     383                 case_sensitive=False),
    384384    latex=dict(default="young_diagram",
    385385               description='Specifies how partitions should be latexed',
    386386               values=dict(diagram='latex as a Ferrers diagram',
    PartitionOptions=GlobalOptions(name='par 
    388388                           list='latex as a list',
    389389                           exp_high='latex as a list in exponential notation (highest first)',
    390390                           exp_low='as a list latex in exponential notation (lowest first)'),
    391                alias=dict(exp="exp_low", array="diagram", ferrers_diagram="diagram")
    392               ),
     391               alias=dict(exp="exp_low", array="diagram", ferrers_diagram="diagram"),
     392               case_sensitive=False),
    393393    diagram_str=dict(default="*",
    394394                     description='The character used for the cells when printing Ferrers diagrams',
    395395                     checker=lambda char: isinstance(char,str)),
    class Partition(CombinatorialObject, Ele 
    10421042            sage: Partitions.global_options.reset()
    10431043        """
    10441044        diag_str = self.parent().global_options('diagram_str')
    1045         if self.parent().global_options('convention') == 'english':
     1045        if self.parent().global_options('convention') == "English":
    10461046            return '\n'.join([diag_str*p for p in self])
    10471047        else:
    10481048            return '\n'.join([diag_str*p for p in reversed(self)])
  • sage/combinat/partition_tuple.py

    diff --git a/sage/combinat/partition_tuple.py b/sage/combinat/partition_tuple.py
    a b class PartitionTuple(CombinatorialObject 
    780780                else:
    781781                    line += '   {:{}}'.format('',col_len[c])
    782782            diag.append(line.rstrip())
    783         if PartitionTuples.global_options('convention')=='english':
     783        if PartitionTuples.global_options('convention') == "English":
    784784            return '\n'.join(map(str, diag))
    785785        else:
    786786            return '\n'.join(map(str, diag[::-1]))
  • sage/combinat/rigged_configurations/rigged_partition.py

    diff --git a/sage/combinat/rigged_configurations/rigged_partition.py b/sage/combinat/rigged_configurations/rigged_partition.py
    a b class RiggedPartition(CombinatorialObjec 
    131131            return("(/)\n")
    132132
    133133        from sage.combinat.partition import Partitions
    134         if Partitions.global_options("convention") == "french":
     134        if Partitions.global_options("convention") == "French":
    135135            itr = reversed(list(enumerate(self._list)))
    136136        else:
    137137            itr = enumerate(self._list)
  • sage/combinat/skew_partition.py

    diff --git a/sage/combinat/skew_partition.py b/sage/combinat/skew_partition.py
    a b class SkewPartition_class(CombinatorialO 
    206206        # TODO: Should be SkewPartitions.global_options
    207207        char, convention = sage.combinat.partition.Partitions.global_options('diagram_str','convention')
    208208
    209         if convention == "english":
     209        if convention == "English":
    210210            L = range(len(self[0]))
    211211        else:
    212212            L = reversed(range(len(self[0])))
  • sage/combinat/tableau.py

    diff --git a/sage/combinat/tableau.py b/sage/combinat/tableau.py
    a b TableauOptions=GlobalOptions(name='table 
    151151                 values=dict(list='print tableaux as lists',
    152152                             diagram='display as Young diagram (simlar to :meth:`~sage.combinat.tableau.Tableau.pp()`',
    153153                             compact='minimal length string representation'),
    154                  alias=dict(array="diagram", ferrers_diagram="diagram", young_diagram="diagram")
    155                 ),
     154                 alias=dict(array="diagram", ferrers_diagram="diagram", young_diagram="diagram"),
     155                 case_sensitive=False),
    156156    latex=dict(default="diagram",
    157157               description='Controls the way in wich tableaux are latexed',
    158158               values=dict(list='as a list', diagram='as a Young diagram'),
    159                alias=dict(array="diagram", ferrers_diagram="diagram", young_diagram="diagram")
    160               ),
    161     convention=dict(default="english",
     159               alias=dict(array="diagram", ferrers_diagram="diagram", young_diagram="diagram"),
     160               case_sensitive=False),
     161    convention=dict(default="English",
    162162                    description='Sets the convention used for displaying tableaux and partitions',
    163                     values=dict(English='use the English convention',French='use the French convention')),
     163                    values=dict(English='use the English convention',French='use the French convention'),
     164                    case_sensitive=False),
    164165    notation = dict(alt_name="convention")
    165166)
    166167
    class Tableau(CombinatorialObject, Eleme 
    365366              1  2  3
    366367            sage: Tableaux.global_options.reset()
    367368        """
    368         if self.parent().global_options('convention') == "english":
     369        if self.parent().global_options('convention') == "English":
    369370            return '\n'.join(["".join(map(lambda x: "%3s"%str(x) , row)) for row in self])
    370371        else:
    371372            return '\n'.join(["".join(map(lambda x: "%3s"%str(x) , row)) for row in reversed(self)])
  • sage/combinat/tableau_tuple.py

    diff --git a/sage/combinat/tableau_tuple.py b/sage/combinat/tableau_tuple.py
    a b class TableauTuple(CombinatorialObject,E 
    495495                else:
    496496                    line += '   '+'   '*col_len[c]
    497497            diag.append(line)
    498         if TableauTuples.global_options('convention')=='english':
     498        if TableauTuples.global_options('convention') == "English":
    499499            return '\n'.join(map(str,diag))
    500500        else:
    501501            return '\n'.join(map(str,diag[::-1]))
  • sage/structure/global_options.py

    diff --git a/sage/structure/global_options.py b/sage/structure/global_options.py
    a b dictionary are: 
    6262- ``values`` -- A dictionary assigning each valid value for the option
    6363  to a short description of what it does.
    6464
    65 For each option, one must supply either a complete list of values via ``values``
    66 or a validation function via ``checker``. The values can be quite arbitrary,
    67 including user-defined functions which customize the default behaviour of the
    68 classes such as the output of ``_repr_`` or :func:`latex`. See
    69 :ref:`dispatcher` below, and :meth:`~GlobalOptions.dispatcher`,
    70 for more information.
     65- ``case_sensitive`` -- (Default: ``True``) ``True`` or ``False`` depending on
     66  whether the values of the option are case sensitive.
     67
     68For each option, either a complete list of possible values, via ``values``, or a
     69validation function, via ``checker``, must be given. The values can be quite
     70arbitrary, including user-defined functions which customize the default
     71behaviour of the classes such as the output of ``_repr_`` or :func:`latex`. See
     72:ref:`dispatcher` below, and :meth:`~GlobalOptions.dispatcher`, for more
     73information.
    7174
    7275The documentation for the options is automatically constructed by combining the
    7376description of each option with a header and footer which are given by the
    illustrated by an example:: 
    9194    ...                   alias=dict(rye='bread')),
    9295    ...       appetizer=dict(alt_name='entree'),
    9396    ...       main=dict(default='pizza', description='Main meal',
    94     ...                   values=dict(pizza='thick crust', pasta='penne arrabiata')),
     97    ...                 values=dict(pizza='thick crust', pasta='penne arrabiata'),
     98    ...                 case_sensitive=False),
    9599    ...       dessert=dict(default='espresso', description='Dessert',
    96     ...                   values=dict(espresso='life begins again',
    97     ...                               cake='waist begins again',
    98     ...                               cream='fluffy, white stuff')),
     100    ...                    values=dict(espresso='life begins again',
     101    ...                                cake='waist begins again',
     102    ...                                cream='fluffy, white stuff')),
    99103    ...       tip=dict(default=10, description='Reward for good service',
    100104    ...       checker=lambda tip: tip in range(0,20))
    101105    ...   )
    Continuing the example from :ref:`constr 
    124128    sage: menu['dessert']
    125129    'espresso'
    126130
    127 Note that, provided there is no ambiguity. all options and their values can be
     131Note that, provided there is no ambiguity, options and their values can be
    128132abbreviated::
    129133
    130134    sage: menu['d']
    abbreviated:: 
    133137    ['pizza', 10]
    134138    sage: menu(t=15); menu['tip']
    135139    15
    136     sage: menu(e='s', m='pi'); menu()
     140    sage: menu(e='s', m='Pi'); menu()
    137141    Current options for menu
    138142      - dessert: espresso
    139143      - entree:  soup
    140144      - main:    pizza
    141145      - tip:     15
    142     sage: menu(m='p')
     146    sage: menu(m='P')
    143147    Traceback (most recent call last):
    144148    ...
    145     ValueError: p is not a valid value for main in the options for menu
     149    ValueError: P is not a valid value for main in the options for menu
    146150
    147151
    148152Setter functions
    149153----------------
    150154
    151 Each option of a :class:`GlobalOptions` can be equipped with an optiona setter
    152 function which is called **after** each change of value. In the following
    153 example, setting the option 'add' changes the state of the class by setting an
    154 attribute in this class using a :func:`classmethod`. Note that the options
    155 object is inserted after the creation of the class in order to access the
    156 :func:`classmethod` as ``A.setter``::
     155Each option of a :class:`GlobalOptions` can be equipped with an optional setter
     156function which is called **after** the value of the option is changed. In the
     157following example, setting the option 'add' changes the state of the class by
     158setting an attribute in this class using a :func:`classmethod`. Note that the
     159options object is inserted after the creation of the class in order to access
     160the :func:`classmethod` as ``A.setter``::
    157161
    158162    sage: from sage.structure.global_options import GlobalOptions
    159163    sage: class A(SageObject):
    Documentation for options 
    187191
    188192The documentation for a :class:`GlobalOptions` is automatically generated from
    189193the supplied options. For example, the generated documentation for the options
    190 ``menu`` defined in :ref:`construction_section`::
     194``menu`` defined in :ref:`construction_section` is the following::
    191195
    192196    Fancy documentation
    193197    -------------------
    Dispatchers 
    242246-----------
    243247
    244248The whole idea of a :class:`GlobalOptions` class is that the options change the
    245 default behaviour of associated classes. This can be done either by simply
     249default behaviour of the associated classes. This can be done either by simply
    246250checking what the current value of the relevant option is. Another possibility
    247251is to use the options class as a dispatcher to associated methods. To use the
    248252dispatcher feature of a :class:`GlobalOptions` class it is necessary to implement
    these methods is that they start with a  
    251255of the option.
    252256
    253257If the value of a dispatchable option is set equal to a (user defined) function
    254 then this function is called in instead of a class method.
     258then this function is called instead of a class method.
    255259
    256260For example, the options ``MyOptions`` can be used to dispatch the ``_repr_``
    257261method of the associated class ``MyClass`` as follows:
    In this example, ``first_option`` is an  
    271275values ``bells``, ``whistles``, and so on. Note that it is necessary to make
    272276``self``, which is an instance of ``MyClass``, an argument of the dispatcher
    273277because :meth:`~GlobalOptions.dispatch()` is a method of :class:`GlobalOptions`
    274 and not a method of ``MyClass``. Apart form ``MyOptions``, as it is a method of
     278and not a method of ``MyClass``. Apart from ``MyOptions``, as it is a method of
    275279this class, the arguments are the attached class (here ``MyClass``), the prefix
    276280of the method of ``MyClass`` being dispatched, the option of ``MyOptions``
    277281which controls the dispatching. All other arguments are passed through to the
    See :meth:`~GlobalOptions.dispatch` for  
    314318Doc testing
    315319-----------
    316320
    317 All of the options and their effects should be doctested. However, in order
     321All of the options and their effects should be doc-tested. However, in order
    318322not to break other tests, all options should be returned to their default state
    319323at the end of each test. To make this easier, every :class:`GlobalOptions` class has
    320324a :meth:`~GlobalOptions.reset()` method for doing exactly this.
    pickled:: 
    335339    ...                   alias=dict(rye='bread')),
    336340    ...       appetizer=dict(alt_name='entree'),
    337341    ...       main=dict(default='pizza', description='Main meal',
    338     ...                   values=dict(pizza='thick crust', pasta='penne arrabiata')),
     342    ...                 values=dict(pizza='thick crust', pasta='penne arrabiata'),
     343    ...                 case_sensitive=False),
    339344    ...       dessert=dict(default='espresso', description='Dessert',
    340     ...                   values=dict(espresso='life begins again',
    341     ...                               cake='waist begins again',
    342     ...                               cream='fluffy, white stuff')),
     345    ...                    values=dict(espresso='life begins again',
     346    ...                                cake='waist begins again',
     347    ...                                cream='fluffy, white stuff')),
    343348    ...       tip=dict(default=10, description='Reward for good service',
    344349    ...       checker=lambda tip: tip in range(0,20))
    345350    ...   )
    class GlobalOptions(SageObject): 
    404409      automatically defines the corresponding ``checker``). This dictionary
    405410      gives the possible options, as keys, together with a brief description
    406411      of them.
     412    - ``case_sensitive`` -- (Default: ``True``) ``True`` or ``False`` depending on
     413      whether the values of the option are case sensitive.
    407414
    408     The values of all options are forced to be in lower case. Options
    409     and their values can be abbreviated provided that this
     415    Options and their values can be abbreviated provided that this
    410416    abbreviation is a prefix of a unique option.
    411417
    412418    Calling the options with no arguments results in the list of
    class GlobalOptions(SageObject): 
    422428        ...                   alias=dict(rye='bread')),
    423429        ...       appetizer=dict(alt_name='entree'),
    424430        ...       main=dict(default='pizza', description='Main meal',
    425         ...                 values=dict(pizza='thick crust', pasta='penne arrabiata')),
     431        ...                 values=dict(pizza='thick crust', pasta='penne arrabiata'),
     432        ...                 case_sensitive=False),
    426433        ...       dessert=dict(default='espresso', description='Dessert',
    427434        ...                    values=dict(espresso='life begins again',
    428435        ...                                cake='waist begins again',
    class GlobalOptions(SageObject): 
    519526            ...                   alias=dict(rye='bread')),
    520527            ...       appetizer=dict(alt_name='entree'),
    521528            ...       main=dict(default='pizza', description='Main meal',
    522             ...                 values=dict(pizza='thick crust', pasta='penne arrabiata')),
     529            ...                 values=dict(pizza='thick crust', pasta='penne arrabiata'),
     530            ...                 case_sensitive=False),
    523531            ...       dessert=dict(default='espresso', description='Dessert',
    524532            ...                    values=dict(espresso='life begins again',
    525533            ...                                cake='waist begins again',
    class GlobalOptions(SageObject): 
    535543            sage: specials['entree'] = 'rye'
    536544            sage: menu['entree']
    537545            'bread'
     546
     547            sage: alias_test = GlobalOptions( name='alias_test',
     548            ...         doc="Test aliases with case sensitivity",
     549            ...         test_opt=dict(default="Upper",
     550            ...         description='Starts with an uppercase',
     551            ...         values=dict(Upper="Starts with uppercase",
     552            ...                     lower="only lowercase"),
     553            ...         case_sensitive=False,
     554            ...         alias=dict(UpperAlias="Upper", lower_alias="lower")) )
     555            sage: alias_test['test_opt'] = 'Lower_Alias'
     556            sage: alias_test['test_opt']
     557            'lower'
     558            sage: alias_test['test_opt'] = 'upperalias'
     559            sage: alias_test['test_opt']
     560            'Upper'
    538561        """
    539562        self._name=name
    540563        # initialise the various dictionaries used by GlobalOptions
    class GlobalOptions(SageObject): 
    547570        self._setter={}           # a dictionary of the list of setters
    548571        self._value={}            # the current options
    549572        self._values={}           # a dictionary of lists of the legal values for each option
     573        self._display_values={}   # a dictionary of the output of the values
     574        self._case_sensitive = {} # a dictionary of booleans indicating to check case sensitivity
    550575        for option in options:
    551576            self._add_option(option, options[option])
    552577
    class GlobalOptions(SageObject): 
    667692            link,linked_opt=self._linked_value[option]
    668693            return link[linked_opt]
    669694        elif option in self._value:
     695            if self._display_values.has_key(option):
     696                return self._display_values[option][self._value[option]]
    670697            return self._value[option]
    671698
    672699
    class GlobalOptions(SageObject): 
    747774        doc={}  # will be used to build the doc string
    748775        option = option.lower()
    749776        self._values[option] = []
     777        self._case_sensitive[option] = True    # ``True`` by default
    750778        for spec in sorted(specifications):   # NB: options processed alphabetically!
    751779            if spec=='alias':
    752780                self._alias[option]=specifications[spec]
    class GlobalOptions(SageObject): 
    785813                    raise ValueError('the setter for %s must be a function' % option)
    786814            elif spec=='values':
    787815                for val in specifications[spec]:
    788                     doc[val]=specifications[spec][val]
     816                    doc[val] = specifications[spec][val]
    789817                doc.update(specifications[spec])
    790                 self._values[option]+=[val.lower() for val in specifications[spec].keys()]
     818                if self._case_sensitive[option]:
     819                    self._values[option] += [val for val in specifications[spec].keys()]
     820                    self._display_values[option] = {val:val for val in specifications[spec].keys()}
     821                else:
     822                    self._values[option] += [val.lower() for val in specifications[spec].keys()]
     823                    self._display_values[option] = {val.lower():val for val in specifications[spec].keys()}
     824            elif spec == 'case_sensitive':
     825                if not specifications[spec]:
     826                    for opt in self._values:
     827                        self._display_values[option] = {val.lower():val for val in self._values[option]}
     828                        self._values[option] = [val.lower() for val in self._values[option]]
     829                    if self._alias.has_key(option):
     830                        self._alias[option] = {k.lower():v.lower() for k,v in self._alias[option].iteritems()}
     831                self._case_sensitive[option] = bool(specifications[spec])
    791832            elif spec!='description':
    792833                raise ValueError('Initialization error in Global options for %s: %s not recognized!'%(self._name, spec))
    793834
    class GlobalOptions(SageObject): 
    795836        if doc == {} and not 'description' in specifications:
    796837            raise ValueError('no documentation specified for %s in the %s' % (option, self))
    797838
    798         self._doc[option]=''   # a hack to put option in self._doc because __setitem_ calls _match_option
     839        self._doc[option]=''   # a hack to put option in self._doc because __setitem__ calls _match_option
    799840        if option in self._linked_value:
    800841            self._doc[option]=doc
    801842        else:
    class GlobalOptions(SageObject): 
    844885            'apple'
    845886        """
    846887        # the keys of self._doc is a list of the options, both normal and linked
    847         option=option.lower()
     888        option = option.lower()
     889
    848890        if option in self._doc: return option
    849891
    850892        # as it is not an option try and match it with a prefix to an option
    class GlobalOptions(SageObject): 
    889931            link, linked_opt = self._linked_value[option]
    890932            return link._match_value(linked_opt, value)
    891933
    892         # convert value to lower case if it is a string
    893         if isinstance(value, str):
     934        orig_value = value
     935
     936        # convert to proper case if it is a string
     937        if isinstance(value, str) and not self._case_sensitive[option]:
    894938            value = value.lower()
    895939
    896940        if option in self._values:
    897941            if value in self._values[option]:
    898942                if option in self._alias and value in self._alias[option]:
    899943                    return self._alias[option][value]
    900                 else: return value
     944                return value
    901945
    902946            # as it is not a value try and match it with a prefix of a value
    903947            matches=[val for val in self._values[option] if val.startswith(value)]
    class GlobalOptions(SageObject): 
    905949                val=matches[0]
    906950                if option in self._alias and val in self._alias[option]:
    907951                    return self._alias[option][val]
    908                 else: return val
     952                return val
    909953
    910954        if option in self._checker and self._checker[option](value):
    911955            return value
    912956
     957        # if we are still here this is not a good value!
     958
    913959        # replace any value alias with its "real" value
    914960        if option in self._alias and value in self._alias[option]:
    915             value=self._alias[option][value]
    916 
    917         # if we are still here this is not a good value!
    918         raise ValueError('%s is not a valid value for %s in the %s'%(value, option, self))
     961            orig_value = self._alias[option][value]
     962        raise ValueError('%s is not a valid value for %s in the %s'%(orig_value, option, self))
    919963
    920964
    921965    def default_value(self, option):
    class GlobalOptions(SageObject): 
    10231067        """
    10241068        if option is None:
    10251069            for option in self._default_value:
    1026                 self._value[option]=self._default_value[option]
     1070                self._value[option] = self._default_value[option]
     1071                if not self._case_sensitive[option] and isinstance(self._value[option],str):
     1072                    self._value[option] = self._value[option].lower()
    10271073            for option in self._linked_value:
    10281074                link, linked_opt=self._linked_value[option]
    10291075                link.reset(linked_opt)
    10301076        else:
    10311077            option=self._match_option(option)
    10321078            if option in self._default_value:
    1033                 self._value[option]=self._default_value[option]
     1079                self._value[option] = self._default_value[option]
     1080                if not self._case_sensitive[option] and isinstance(self._value[option],str):
     1081                    self._value[option] = self._value[option].lower()
    10341082            elif option in self._linked_value:
    10351083                link, linked_opt=self._linked_value[option]
    10361084                link.reset(linked_opt)