Lichen

lib/operator/core.py

503:644952535f7a
2017-01-23 Paul Boddie Added another, shorter test of get_using, commenting the existing test slightly.
     1 #!/usr/bin/env python     2      3 """     4 Operator support.     5      6 Copyright (C) 2010, 2013, 2015, 2016 Paul Boddie <paul@boddie.org.uk>     7      8 This program is free software; you can redistribute it and/or modify it under     9 the terms of the GNU General Public License as published by the Free Software    10 Foundation; either version 3 of the License, or (at your option) any later    11 version.    12     13 This program is distributed in the hope that it will be useful, but WITHOUT    14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    15 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more    16 details.    17     18 You should have received a copy of the GNU General Public License along with    19 this program.  If not, see <http://www.gnu.org/licenses/>.    20 """    21     22 # Define "is" and "is not" in terms of native operations. They are imported by    23 # the operator.binary module.    24     25 from native import is_, is_not    26     27 def binary_op(a, b, left_accessor, right_accessor, default=None):    28     29     """    30     A single parameterised function providing the binary operator mechanism for    31     arguments 'a' and 'b' using accessors given as 'left_accessor' and    32     'right_accessor' which provide the methods for the operands.    33     """    34     35     # First, try and get a method for the left argument, and then call it with    36     # the right argument.    37     38     try:    39         fn = left_accessor(a)    40     except TypeError:    41         pass    42     else:    43         result = fn(b)    44         if is_not(result, NotImplemented):    45             return result    46     47     # Otherwise, try and get a method for the right argument, and then call it    48     # with the left argument.    49     50     try:    51         fn = right_accessor(b)    52     except TypeError:    53         pass    54     else:    55         result = fn(a)    56         if is_not(result, NotImplemented):    57             return result    58     59     # Where no methods were available, or if neither method could support the    60     # operation, raise an exception or provide a default result.    61     62     if default is None:    63         raise TypeError    64     else:    65         return default    66     67 def unary_op(a, accessor, default=None):    68     69     """    70     A single parameterised function providing the unary operator mechanism for    71     the argument 'a' using the given 'accessor' to provide the method for the    72     operand.    73     """    74     75     # First, try and get a method for the argument, and then call it.    76     77     try:    78         fn = accessor(a)    79     except TypeError:    80         pass    81     else:    82         result = fn()    83         if is_not(result, NotImplemented):    84             return result    85     86     # Where no method was available, or if the method could not support the    87     # operation, raise an exception or provide a default result.    88     89     if default is None:    90         raise TypeError    91     else:    92         return default    93     94 def augassign(a, b, augmented_accessor, left_accessor, right_accessor):    95     96     """    97     A single parameterised function providing the augmented assignment mechanism    98     for arguments 'a' and 'b' either using 'augmented_accessor' (directly    99     affecting 'a') or using 'left_accessor' and 'right_accessor' (conventional   100     operator method accessors).   101    102     The result of the assignment is returned.   103     """   104    105     # First, try and get a method that directly affects the assignment target.   106    107     try:   108         fn = augmented_accessor(a)   109     except TypeError:   110         pass   111     else:   112         result = fn(b)   113         if is_not(result, NotImplemented):   114             return result   115    116     # Otherwise, attempt a conventional binary operation.   117    118     return binary_op(a, b, left_accessor, right_accessor)   119    120 # vim: tabstop=4 expandtab shiftwidth=4