def get_default_args_dict(function):
    '''
    Get ordered dict from arguments which have a default to their default.
    
    Example:
    
        >>> def f(a, b, c=1, d='meow'): pass
        >>> get_default_args_dict(f)
        OrderedDict([('c', 1), ('d', 'meow')])
        
    '''
    arg_spec = cute_inspect.getargspec(function)
    (s_args, s_star_args, s_star_kwargs, s_defaults) = arg_spec
        
    # `getargspec` has a weird policy, when inspecting a function with no
    # defaults, to give a `defaults` of `None` instead of the more consistent
    # `()`. We fix that here:
    if s_defaults is None:
        s_defaults = ()
    
    # The number of args which have default values:
    n_defaultful_args = len(s_defaults)
    
    defaultful_args = s_args[-n_defaultful_args:] if n_defaultful_args \
                       else []
    
    return OrderedDict(list(zip(defaultful_args, s_defaults)))
    
    
Esempio n. 2
0
 def __init__(self, argument_control, step_function):
     self.argument_control = argument_control
     
     wx.StaticBox.__init__(self, argument_control,
                           label='Additional arguments')
     
     self.SetMinSize(argument_control.box_size)
     self.SetMaxSize(argument_control.box_size)
     
     self.sizer = wx.StaticBoxSizer(self, wx.VERTICAL)
     
     self.sizer.SetMinSize(argument_control.box_size)
     
     self.step_function = step_function
     
     arg_spec = cute_inspect.getargspec(step_function)
     
     star_arg_list = \
         argument_control.step_profile_dialog.step_functions_to_star_args[
             step_function
         ]
     
     
     self.star_args = []
     
     for star_arg_value in star_arg_list:
         star_arg = StarArg(argument_control, self, star_arg_value)
         self.star_args.append(star_arg)
         self.sizer.Add(star_arg, 0, wx.EXPAND | wx.ALL, border=5)
         
     self.star_adder = StarAdder(argument_control)
     self.sizer.Add(self.star_adder, 0, wx.EXPAND | wx.ALL, border=5)
     
     self.Parent.Bind(EVT_STAR_ADDER_PRESSED, self.on_star_adder_pressed,
                      source=self.star_adder)
Esempio n. 3
0
def get_default_args_dict(function):
    '''
    Get ordered dict from arguments which have a default to their default.
    
    Example:
    
        >>> def f(a, b, c=1, d='meow'): pass
        >>> get_default_args_dict(f)
        OrderedDict([('c', 1), ('d', 'meow')])
        
    '''
    arg_spec = cute_inspect.getargspec(function)
    (s_args, s_star_args, s_star_kwargs, s_defaults) = arg_spec
        
    # `getargspec` has a weird policy, when inspecting a function with no
    # defaults, to give a `defaults` of `None` instead of the more consistent
    # `()`. We fix that here:
    if s_defaults is None:
        s_defaults = ()
    
    # The number of args which have default values:
    n_defaultful_args = len(s_defaults)
    
    defaultful_args = s_args[-n_defaultful_args:] if n_defaultful_args \
                       else []
    
    return OrderedDict(zip(defaultful_args, s_defaults))
    
    
Esempio n. 4
0
    def __init__(self, argument_control, step_function):
        self.argument_control = argument_control

        wx.StaticBox.__init__(self,
                              argument_control,
                              label='Arguments',
                              size=argument_control.box_size)

        self.SetMinSize(argument_control.box_size)
        self.SetMaxSize(argument_control.box_size)

        self.sizer = wx.StaticBoxSizer(self, wx.VERTICAL)

        self.sizer.SetMinSize(argument_control.box_size)

        self.step_function = step_function

        arg_spec = cute_inspect.getargspec(step_function)

        arg_dict = argument_control.step_profile_dialog.\
            step_functions_to_argument_dicts[
                step_function
            ]

        self.args = []

        for i, arg_name in list(enumerate(arg_spec.args))[1:]:
            value = arg_dict[arg_name]
            if not value and (arg_name in arg_spec.defaults):
                value = arg_dict[arg_name] = repr(arg_spec.defaults[i])
            arg = Arg(argument_control, arg_name, value)
            self.args.append(arg)
            self.sizer.Add(arg, 0, wx.EXPAND | wx.ALL, border=5)
Esempio n. 5
0
 def __init__(self, argument_control, step_function):
     self.argument_control = argument_control
     
     wx.StaticBox.__init__(self, argument_control, label='Arguments',
                           size=argument_control.box_size)
     
     self.SetMinSize(argument_control.box_size)
     self.SetMaxSize(argument_control.box_size)
     
     self.sizer = wx.StaticBoxSizer(self, wx.VERTICAL)
     
     self.sizer.SetMinSize(argument_control.box_size)
     
     self.step_function = step_function
     
     arg_spec = cute_inspect.getargspec(step_function)
     
     arg_dict = argument_control.step_profile_dialog.\
         step_functions_to_argument_dicts[
             step_function
         ]
     
     self.args = []
     
     for i, arg_name in list(enumerate(arg_spec.args))[1:]:
         value = arg_dict[arg_name]
         if not value and (arg_name in arg_spec.defaults):
             value = arg_dict[arg_name] = repr(arg_spec.defaults[i])
         arg = Arg(argument_control, arg_name, value)
         self.args.append(arg)
         self.sizer.Add(arg, 0, wx.EXPAND | wx.ALL, border=5)
         
Esempio n. 6
0
 def create_from_dld_format(cls, function, args_dict, star_args_list,
                            star_kwargs_dict):
     '''
     Create an arguments profile from data given in "dict-list-dict" format.
     
     The "dict-list-dict" format means that in addition to a function, we
     get a `dict` of arguments, a `list` of `*args`, and a `dict` of
     `**kwargs`.
     '''
     args_spec = cute_inspect.getargspec(function)
     new_args = [args_dict[name] for name in args_spec.args] + \
                list(star_args_list)
     return cls(function, *new_args, **star_kwargs_dict)
Esempio n. 7
0
 def create_from_dld_format(cls, function, args_dict, star_args_list,
                            star_kwargs_dict):
     '''
     Create an arguments profile from data given in "dict-list-dict" format.
     
     The "dict-list-dict" format means that in addition to a function, we
     get a `dict` of arguments, a `list` of `*args`, and a `dict` of
     `**kwargs`.
     '''
     args_spec = cute_inspect.getargspec(function)
     new_args = [args_dict[name] for name in args_spec.args] + \
                list(star_args_list)
     return cls(function, *new_args, **star_kwargs_dict)
Esempio n. 8
0
 def __init__(self, containing_dict, function, *args, **kwargs):
     '''
     Construct the `SleekCallArgs`.
     
     `containing_dict` is the `dict` we'll try to remove ourselves from when
     one of our sleekrefs dies. `function` is the function for which we
     calculate call args from `*args` and `**kwargs`.
     '''
     
     self.containing_dict = containing_dict
     '''
     `dict` we'll try to remove ourselves from when 1 of our sleekrefs dies.
     '''
     
     args_spec = cute_inspect.getargspec(function)
     star_args_name, star_kwargs_name = \
                   args_spec.varargs, args_spec.keywords
     
     call_args = cute_inspect.getcallargs(function, *args, **kwargs)
     del args, kwargs
     
     self.star_args_refs = []
     '''Sleekrefs to star-args.'''
     
     if star_args_name:
         star_args = call_args.pop(star_args_name, None)
         if star_args:
             self.star_args_refs = [SleekRef(star_arg, self.destroy) for
                                    star_arg in star_args]
     
     self.star_kwargs_refs = {}
     '''Sleerefs to star-kwargs.'''
     if star_kwargs_name:            
         star_kwargs = call_args.pop(star_kwargs_name, {})
         if star_kwargs:
             self.star_kwargs_refs = CuteSleekValueDict(self.destroy,
                                                        star_kwargs)
     
     self.args_refs = CuteSleekValueDict(self.destroy, call_args)
     '''Mapping from argument name to value, sleek-style.'''
     
     # In the future the `.args`, `.star_args` and `.star_kwargs` attributes
     # may change, so we must record the hash now:
     self._hash = cheat_hashing.cheat_hash(
         (
             self.args,
             self.star_args,
             self.star_kwargs
         )
     )
Esempio n. 9
0
    def __init__(self, containing_dict, function, *args, **kwargs):
        '''
        Construct the `SleekCallArgs`.
        
        `containing_dict` is the `dict` we'll try to remove ourselves from when
        one of our sleekrefs dies. `function` is the function for which we
        calculate call args from `*args` and `**kwargs`.
        '''

        self.containing_dict = containing_dict
        '''
        `dict` we'll try to remove ourselves from when 1 of our sleekrefs dies.
        '''

        args_spec = cute_inspect.getargspec(function)
        star_args_name, star_kwargs_name = \
                      args_spec.varargs, args_spec.keywords

        call_args = cute_inspect.getcallargs(function, *args, **kwargs)
        del args, kwargs

        self.star_args_refs = []
        '''Sleekrefs to star-args.'''

        if star_args_name:
            star_args = call_args.pop(star_args_name, None)
            if star_args:
                self.star_args_refs = [
                    SleekRef(star_arg, self.destroy) for star_arg in star_args
                ]

        self.star_kwargs_refs = {}
        '''Sleerefs to star-kwargs.'''
        if star_kwargs_name:
            star_kwargs = call_args.pop(star_kwargs_name, {})
            if star_kwargs:
                self.star_kwargs_refs = CuteSleekValueDict(
                    self.destroy, star_kwargs)

        self.args_refs = CuteSleekValueDict(self.destroy, call_args)
        '''Mapping from argument name to value, sleek-style.'''

        # In the future the `.args`, `.star_args` and `.star_kwargs` attributes
        # may change, so we must record the hash now:
        self._hash = cheat_hashing.cheat_hash(
            (self.args, self.star_args, self.star_kwargs))
Esempio n. 10
0
    def __init__(self, argument_control, step_function):
        self.argument_control = argument_control

        wx.StaticBox.__init__(self,
                              argument_control,
                              label='Additional arguments')

        self.SetMinSize(argument_control.box_size)
        self.SetMaxSize(argument_control.box_size)

        self.sizer = wx.StaticBoxSizer(self, wx.VERTICAL)

        self.sizer.SetMinSize(argument_control.box_size)

        self.step_function = step_function

        arg_spec = cute_inspect.getargspec(step_function)

        star_arg_list = \
            argument_control.step_profile_dialog.step_functions_to_star_args[
                step_function
            ]

        self.star_args = []

        for star_arg_value in star_arg_list:
            star_arg = StarArg(argument_control, self, star_arg_value)
            self.star_args.append(star_arg)
            self.sizer.Add(star_arg, 0, wx.EXPAND | wx.ALL, border=5)

        self.star_adder = StarAdder(argument_control)
        self.sizer.Add(self.star_adder, 0, wx.EXPAND | wx.ALL, border=5)

        self.Parent.Bind(EVT_STAR_ADDER_PRESSED,
                         self.on_star_adder_pressed,
                         source=self.star_adder)
Esempio n. 11
0
    def set_step_function(self, step_function):
        '''Set the step function for which we are specifying arguments.'''
        if self.step_function == step_function:
            return

        if self.step_function is not None:
            try:
                self.save()
            except ResolveFailed:
                pass

        self.step_function = step_function

        self.main_h_sizer.Clear(deleteWindows=True)

        arg_spec = cute_inspect.getargspec(step_function)

        step_profile_dialog = self.step_profile_dialog

        arg_dict = step_profile_dialog.\
                 step_functions_to_argument_dicts[step_function]

        star_arg_list = step_profile_dialog.\
                      step_functions_to_star_args[step_function]

        star_kwarg_dict = step_profile_dialog.\
                        step_functions_to_star_kwargs[step_function]

        if arg_spec.args[1:]:  # Filtering the state which is always present
            self.arg_box = ArgBox(self, step_function)
            self.main_h_sizer.Add(self.arg_box.sizer, 0, wx.ALL, border=10)
        else:
            self.arg_box = None
            self.main_h_sizer.Add(Placeholder(self, '(No named arguments)'),
                                  0,
                                  wx.ALL,
                                  border=10)

        if arg_spec.varargs:
            self.star_arg_box = StarArgBox(self, step_function)
            self.main_h_sizer.Add(self.star_arg_box.sizer,
                                  0,
                                  wx.ALL,
                                  border=10)
        else:
            self.star_arg_box = None
            self.main_h_sizer.Add(Placeholder(
                self, '(No additional positional arguments)'),
                                  0,
                                  wx.ALL,
                                  border=10)

        if arg_spec.keywords:
            self.star_kwarg_box = StarKwargBox(self, step_function)
            self.main_h_sizer.Add(self.star_kwarg_box.sizer,
                                  0,
                                  wx.ALL,
                                  border=10)
        else:
            self.star_kwarg_box = None
            self.main_h_sizer.Add(Placeholder(
                self, '(No additional keyword arguments)'),
                                  0,
                                  wx.ALL,
                                  border=10)

        self.main_h_sizer.Fit(self)
        self.Layout()
        self.step_profile_dialog.main_v_sizer.Fit(self.step_profile_dialog)
        self.step_profile_dialog.Layout()

        self.step_profile_dialog.Refresh()
Esempio n. 12
0
    def __init__(self, function, *args, **kwargs):
        '''
        Construct the arguments profile.
        
        `*args` and `**kwargs` are the arguments that go into the `function`.
        '''
        
        if not callable(function):
            raise Exception('%s is not a callable object.' % function)
        self.function = function
        
        raw_args = args
        raw_kwargs = kwargs
        del args, kwargs
        
        self.args = ()
        '''Tuple of positional arguments.'''
        
        self.kwargs = OrderedDict()
        '''Ordered dict of keyword arguments.'''
        
        
        args_spec = cute_inspect.getargspec(function)
        
        (s_args, s_star_args, s_star_kwargs, s_defaults) = args_spec
        
        # `getargspec` has a weird policy, when inspecting a function with no
        # defaults, to give a `defaults` of `None` instead of the more
        # consistent `()`. We fix that here:
        if s_defaults is None:
            s_defaults = ()
        
        getcallargs_result = cute_inspect.getcallargs(function,
                                                      *raw_args,
                                                      **raw_kwargs)
        self.getcallargs_result = getcallargs_result
        
        
        # The number of args which have default values:
        n_defaultful_args = len(s_defaults)
        # The word "defaultful" means "something which has a default."
        
        #######################################################################
        #######################################################################
        # Now we'll create the arguments profile, using a 4-phases algorithm. #
        #                                                                     #
        
        #######################################################################
        # Phase 1: We specify all the args that don't have a default as
        # positional args:
        defaultless_args = s_args[:-n_defaultful_args] if n_defaultful_args \
                           else s_args[:]
        self.args += tuple(
            dict_tools.get_list(getcallargs_result, defaultless_args)
        )

        
        #######################################################################
        # Phase 2: We now have to deal with args that have a default. Some of
        # them, possibly none and possibly all of them, should be given
        # positionally. Some of them, possibly none, should be given by
        # keyword. And some of them, possibly none and possibly all of them,
        # should not be given at all. It is our job to figure out in which way
        # each argument should be given.
        
        # In this variable:
        n_defaultful_args_to_specify_positionally = None
        # We will put the number of defaultful arguments that should be
        # specified positionally.
        
        defaultful_args = s_args[-n_defaultful_args:] if n_defaultful_args \
                          else []
        
        # `dict` that maps from argument name to default value:
        defaults = OrderedDict(zip(defaultful_args, s_defaults))
        
        defaultful_args_differing_from_defaults = set((
            defaultful_arg for defaultful_arg in defaultful_args
            if defaults[defaultful_arg] != getcallargs_result[defaultful_arg]
        ))
        
        if s_star_args and getcallargs_result[s_star_args]:
            # We have some arguments that go into `*args`! This means that we
            # don't even need to think hard, we can already be sure that we're
            # going to have to specify *all* of the defaultful arguments
            # positionally, otherwise it will be impossible to put arguments in
            # `*args`.
            n_defaultful_args_to_specify_positionally = n_defaultful_args
            
            
        else:

            # `dict` mapping from each defaultful arg to the "price" of
            # specifying its value:
            prices_of_values = OrderedDict((
                (defaultful_arg, len(repr(getcallargs_result[defaultful_arg])))
                 for defaultful_arg in defaultful_args
            ))
            # The price is simply the string length of the value's `repr`.
            
            # `dict` mapping from each defaultful arg to the "price" of
            # specifying it as a keyword (not including the length of the
            # value):
            prices_of_keyword_prefixes = OrderedDict(
                ((defaultful_arg, len(defaultful_arg)+1) for 
                 defaultful_arg in defaultful_args)
            )
            # For example, if we have a defaultful arg "gravity_strength", then
            # specifiying it by keyword will require using the string
            # "gravity_strength=", which is 17 characters long, therefore the
            # price is 17.
            
            # Now we need to decide just how many defaultful args we are going
            # to specify positionally. The options are anything from `0` to
            # `n_defaultful_args`. We're going to go one by one, and calcluate
            # the price for each candidate, and put it in this dict:
            total_price_for_n_dasp_candidate = OrderedDict()
            # (The `n_dasp` here is an abbreivation of the
            # `n_defaultful_args_to_specify_positionally` variable defined
            # before.)
            #
            # After we have the price for each option, we'll select the one
            # with the lowest price.
            
            # One thing to do before iterating on the candidates is to find out
            # whether the "lonely comma discount" is in effect.
            #
            # The "lonely comma discount" is given when there's nothing but
            # defaultful arguments to this function, and therefore the number
            # of ", " strings needed here is not `candidate`, but `candidate -
            # 1`, unless of course candidate is zero.
            
            if not defaultless_args and \
                (not s_star_args or not getcallargs_result[s_star_args]) and \
                (not s_star_kwargs or not getcallargs_result[s_star_kwargs]):
                
                lonely_comma_discount_may_be_given = True
            
            else:
                
                lonely_comma_discount_may_be_given = False
            
            # Now we iterate on the candidates to find out which one has the
            # lowest price:
            
            for candidate in xrange(n_defaultful_args + 1):

                defaultful_args_to_specify_positionally = \
                    defaultful_args[:candidate]
                
                price_for_positionally_specified_defaultful_args = \
                    2 * candidate + \
                    sum(
                        dict_tools.get_list(
                            prices_of_values,
                            defaultful_args_to_specify_positionally
                        )
                    )
                # The `2 * candidate` addend is to account for the ", " parts
                # between the arguments.
                    
                defaultful_args_to_specify_by_keyword = filter(
                    defaultful_args_differing_from_defaults.__contains__,
                    defaultful_args[candidate:]
                )
                
                price_for_defaultful_args_specified_by_keyword = \
                    2 * len(defaultful_args_to_specify_by_keyword) + \
                    sum(
                        dict_tools.get_list(
                            prices_of_keyword_prefixes,
                            defaultful_args_to_specify_by_keyword
                        )
                    ) + \
                    sum(
                        dict_tools.get_list(
                            prices_of_values,
                            defaultful_args_to_specify_by_keyword
                        )
                    )
                # The `2 * len(...)` addend is to account for the ", " parts
                # between the arguments.
                
                # Now we need to figure out if this candidate gets the "lonely
                # comma discount".
                if lonely_comma_discount_may_be_given and \
                   (defaultful_args_to_specify_by_keyword or \
                    defaultful_args_to_specify_positionally):
                    
                    lonely_comma_discount = -2
                    
                else:
                    lonely_comma_discount = 0
                
                price = price_for_positionally_specified_defaultful_args + \
                        price_for_defaultful_args_specified_by_keyword + \
                        lonely_comma_discount
                
                total_price_for_n_dasp_candidate[candidate] = price


            # Finished iterating on candidates! Time to pick our winner.
                
            minimum_price = min(total_price_for_n_dasp_candidate.itervalues())
            
            leading_candidates = [
                candidate for candidate in 
                total_price_for_n_dasp_candidate.iterkeys() if
                total_price_for_n_dasp_candidate[candidate] == minimum_price
            ]
            
            if len(leading_candidates) == 1:
                # We finished with one candidate which has the minimum price.
                # This is our winner.
                (winner,) = leading_candidates
                n_defaultful_args_to_specify_positionally = winner
            
            else:
                # We have a draw! We're gonna have to settle it by picking the
                # lowest candidate, because in our definition of "canonical
                # arguments profile", our second priority after "as few
                # characters as possible" is "as many keyword arguments as
                # possible".
                winner = leading_candidates[0]
                
            n_defaultful_args_to_specify_positionally = winner
            
        # We have a winner! Now we know exactly which defaultful args should
        # be specified positionally and which should be specified by
        # keyword.
            
        # First we add the positionally specified:
            
        defaultful_args_to_specify_positionally = \
            defaultful_args[:n_defaultful_args_to_specify_positionally]
        self.args += tuple(
            (getcallargs_result[defaultful_arg] for defaultful_arg
             in defaultful_args_to_specify_positionally)
        )
        
        # Now we add those specified by keyword:

        defaultful_args_to_specify_by_keyword = filter(
                defaultful_args_differing_from_defaults.__contains__,
                defaultful_args[n_defaultful_args_to_specify_positionally:]
            )
        for defaultful_arg in defaultful_args_to_specify_by_keyword:
            self.kwargs[defaultful_arg] = getcallargs_result[defaultful_arg]
                
        
        #######################################################################
        # Phase 3: Add the star args:
        
        if s_star_args and getcallargs_result[s_star_args]:
            
            assert not self.kwargs
            # Just making sure that no non-star args were specified by keyword,
            # which would make it impossible for us to put stuff in `*args`.
            
            self.args += getcallargs_result[s_star_args]        

            
        #######################################################################
        # Phase 4: Add the star kwargs:
        
        if s_star_kwargs and getcallargs_result[s_star_kwargs]:
            
            # We can't just add the `**kwargs` as is; we need to add them
            # according to canonical ordering. So we need to sort them first.
            
            unsorted_star_kwargs_names = \
                getcallargs_result[s_star_kwargs].keys()
            sorted_star_kwargs_names = sorted(
                unsorted_star_kwargs_names,
                cmp=cmp_tools.underscore_hating_cmp
            )
            
            sorted_star_kwargs = OrderedDict(
                zip(
                    sorted_star_kwargs_names,
                    dict_tools.get_list(
                        getcallargs_result[s_star_kwargs],
                        sorted_star_kwargs_names
                    )
                )
            )
            
            
            self.kwargs.update(sorted_star_kwargs)
            
        # Our 4-phases algorithm is done! The argument profile is canonical.  #
        #######################################################################
        #######################################################################
        
        
        #######################################################################
        # Now a bit of post-processing:
        
        _arguments = OrderedDict()
        
        dict_of_positional_arguments = OrderedDict(
            dict_tools.filter_items(
                getcallargs_result,
                lambda key, value: ((key not in self.kwargs) and \
                                    (key != s_star_args) and \
                                    (key != s_star_kwargs))
            )
        )
        dict_of_positional_arguments.sort(key=s_args.index)
        _arguments.update(dict_of_positional_arguments)
        
        if s_star_args:
            _arguments['*'] = getcallargs_result[s_star_args]
            
        _arguments.update(self.kwargs)
        
        self._arguments = _arguments
        '''Ordered dict of arguments, both positional- and keyword-.'''
        
        # Caching the hash, since its computation can take a long time:
        self._hash = cheat_hashing.cheat_hash(
            (
                self.function,
                self.args,
                tuple(self.kwargs)
            )
        )
Esempio n. 13
0
    def __init__(self, step_profiles_controls, step_profile=None,
                 and_fork=False):
        '''
        Construct the `StepProfileDialog`.
        
        If given a `step_profile`, use it as a template. If it's `None`, start
        from scratch. Set `and_fork=True` if you intend to fork right after
        getting the step profile, though note it will only affect the labels;
        the actual forking is not done here.
        '''
        
        self.step_profiles_controls = step_profiles_controls
        
        self.gui_project = step_profiles_controls.gui_project
        assert isinstance(self.gui_project, garlicsim_wx.GuiProject)
        
        self.frame = step_profiles_controls.frame
        
        self.and_fork = and_fork
        
        self.simpack = self.gui_project.simpack
        
        self.simpack_grokker = simpack_grokker = \
            self.gui_project.simpack_grokker
        
        title = 'Create a new step profile' if not and_fork else \
                'Create a new step profile and fork with it'
        CuteDialog.__init__(self, step_profiles_controls.GetTopLevelParent(),
                            title=title)
        
        self.SetDoubleBuffered(True)
        
        self.original_step_profile = original_step_profile = step_profile
        
        del step_profile        
        
        
        self.hue = self.gui_project.step_profiles_to_hues.default_factory()
        
        self.step_functions_to_argument_dicts = \
            StepFunctionsToArgumentDicts(self.describe)
        
        self.step_functions_to_star_args = \
            collections.defaultdict(lambda: [])
        
        self.step_functions_to_star_kwargs = \
            collections.defaultdict(lambda: {})

        
        if original_step_profile:
            
            original_step_function = original_step_profile.step_function

            self.step_function = original_step_function
            
            initial_step_function_address = self.describe(
                original_step_function
            )

            original_argument_dict = collections.defaultdict(
                lambda: '',
                original_step_profile.getcallargs_result
            )

            self.step_functions_to_argument_dicts[original_step_function] = \
                dict((key, self.describe(value)) for (key, value) in
                 original_argument_dict.iteritems())
            

            original_arg_spec = cute_inspect.getargspec(original_step_function)
            
            
            if original_arg_spec.varargs:
                star_args_value = original_step_profile.getcallargs_result[
                    original_arg_spec.varargs
                ]
                
                self.step_functions_to_star_args[original_step_function] = \
                    [self.describe(value) for value in
                     star_args_value]
            
            
            if original_arg_spec.keywords:
                star_kwargs_value = original_step_profile.getcallargs_result[
                    original_arg_spec.keywords
                ]
                
                self.step_functions_to_star_kwargs[original_step_function] = \
                    dict((key, self.describe(value)) for (key, value)
                         in star_kwargs_value.iteritems())
                
            
            
            
        else:
            
            self.step_function = None
            
            if len(simpack_grokker.all_step_functions) >= 2:
                initial_step_function_address = ''
            else: # len(simpack_grokker.all_step_functions) == 1
                initial_step_function_address = self.describe(
                    simpack_grokker.default_step_function
                )
        
            
        #######################################################################
        # Setting up widgets and sizers:
        
        self.main_v_sizer = wx.BoxSizer(wx.VERTICAL)

        
        
        self.static_text = wx.StaticText(self, label="Choose a step function:")
        
        self.main_v_sizer.Add(self.static_text,
                              0,
                              wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT,
                              border=10)
        
        
        self.h_sizer = wx.BoxSizer(wx.HORIZONTAL)
        
        self.main_v_sizer.Add(
            self.h_sizer,
            0,
            wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,            
            border=10
        )
        
        
        self.hue_control = \
            garlicsim_wx.widgets.general_misc.hue_control.HueControl(
                self,
                lambda: getattr(self, 'hue'),
                lambda hue: setattr(self, 'hue', hue),
                emitter=None,
                lightness=0.8,
                saturation=1,
                dialog_title='Select hue for new step profile',
                size=(25, 20)
            )
        
        self.h_sizer.Add(
            self.hue_control,
            0,
            wx.ALIGN_CENTER_VERTICAL
        )
        
        
        self.h_sizer.AddSpacer(5)
        
        
        self.step_function_input = StepFunctionInput(
            self,
            value=initial_step_function_address
        )
        
        self.h_sizer.Add(
            self.step_function_input,
            0,
            wx.ALIGN_CENTER_VERTICAL,
        )
        
        
        self.static_function_text = StaticFunctionText(
            self,
            step_function=original_step_function if original_step_profile \
                          else None
        )
        
        self.h_sizer.Add(
            self.static_function_text,
            0,
            wx.ALIGN_CENTER_VERTICAL | wx.LEFT,
            border=15
        )
        
        
        self.argument_control = ArgumentControl(
            self,
            original_step_function if original_step_profile else None
        )
        
        self.main_v_sizer.Add(
            self.argument_control,
            1,
            wx.ALIGN_CENTER_HORIZONTAL | wx.TOP,
            border=0
        )
        
        
        self.dialog_button_sizer = wx.StdDialogButtonSizer()
        
        self.main_v_sizer.Add(
            self.dialog_button_sizer,
            0,
            wx.ALIGN_CENTER | wx.ALL,
            border=10
        )
        
        ok_title = 'Create step profile' if not and_fork else \
                   'Create step profile and fork with it'
        self.ok_button = wx.Button(self, wx.ID_OK, title)
        self.dialog_button_sizer.AddButton(self.ok_button)
        self.ok_button.SetDefault()
        self.dialog_button_sizer.SetAffirmativeButton(self.ok_button)
        self.Bind(wx.EVT_BUTTON, self.on_ok, source=self.ok_button)
        
        self.cancel_button = wx.Button(self, wx.ID_CANCEL, 'Cancel')
        self.dialog_button_sizer.AddButton(self.cancel_button)
        self.Bind(wx.EVT_BUTTON, self.on_cancel, source=self.cancel_button)
        self.dialog_button_sizer.Realize()
    
        
        self.SetSizer(self.main_v_sizer)
        self.main_v_sizer.Fit(self)
def assert_same_signature(*callables):
    '''Assert that all the `callables` have the same function signature.'''
    arg_specs = [cute_inspect.getargspec(callable_) for callable_ in callables]
    if not logic_tools.all_equal(arg_specs, exhaustive=True):
        raise Failure('Not all the callables have the same signature.')
Esempio n. 15
0
    def set_step_function(self, step_function):
        '''Set the step function for which we are specifying arguments.'''
        if self.step_function == step_function:
            return
        
        if self.step_function is not None:
            try:
                self.save()
            except ResolveFailed:
                pass

        self.step_function = step_function

        self.main_h_sizer.Clear(deleteWindows=True)
        
        arg_spec = cute_inspect.getargspec(step_function)
        
        step_profile_dialog = self.step_profile_dialog
        
        arg_dict = step_profile_dialog.\
                 step_functions_to_argument_dicts[step_function]
        
        star_arg_list = step_profile_dialog.\
                      step_functions_to_star_args[step_function]
        
        star_kwarg_dict = step_profile_dialog.\
                        step_functions_to_star_kwargs[step_function]
        
        
        if arg_spec.args[1:]: # Filtering the state which is always present
            self.arg_box = ArgBox(self, step_function)
            self.main_h_sizer.Add(self.arg_box.sizer, 0, wx.ALL, border=10)
        else:
            self.arg_box = None
            self.main_h_sizer.Add(
                Placeholder(self, '(No named arguments)'),
                0,
                wx.ALL,
                border=10
            )
            
        
        if arg_spec.varargs:
            self.star_arg_box = StarArgBox(self, step_function)
            self.main_h_sizer.Add(self.star_arg_box.sizer, 0, wx.ALL,
                                  border=10)
        else:
            self.star_arg_box = None
            self.main_h_sizer.Add(
                Placeholder(self, '(No additional positional arguments)'),
                0,
                wx.ALL,
                border=10
            )
                
            
        if arg_spec.keywords:
            self.star_kwarg_box = StarKwargBox(self, step_function)
            self.main_h_sizer.Add(self.star_kwarg_box.sizer, 0, wx.ALL,
                                  border=10)
        else:
            self.star_kwarg_box = None
            self.main_h_sizer.Add(
                Placeholder(self, '(No additional keyword arguments)'),
                0,
                wx.ALL,
                border=10
            )
            
        
        self.main_h_sizer.Fit(self)
        self.Layout()
        self.step_profile_dialog.main_v_sizer.Fit(self.step_profile_dialog)
        self.step_profile_dialog.Layout()
        
        
        self.step_profile_dialog.Refresh()
Esempio n. 16
0
    def __init__(self, function, *args, **kwargs):
        '''
        Construct the arguments profile.
        
        `*args` and `**kwargs` are the arguments that go into the `function`.
        '''

        if not callable(function):
            raise Exception('%s is not a callable object.' % function)
        self.function = function

        raw_args = args
        raw_kwargs = kwargs
        del args, kwargs

        self.args = ()
        '''Tuple of positional arguments.'''

        self.kwargs = OrderedDict()
        '''Ordered dict of keyword arguments.'''

        args_spec = cute_inspect.getargspec(function)

        (s_args, s_star_args, s_star_kwargs, s_defaults) = args_spec

        # `getargspec` has a weird policy, when inspecting a function with no
        # defaults, to give a `defaults` of `None` instead of the more
        # consistent `()`. We fix that here:
        if s_defaults is None:
            s_defaults = ()

        getcallargs_result = cute_inspect.getcallargs(function, *raw_args,
                                                      **raw_kwargs)
        self.getcallargs_result = getcallargs_result

        # The number of args which have default values:
        n_defaultful_args = len(s_defaults)
        # The word "defaultful" means "something which has a default."

        #######################################################################
        #######################################################################
        # Now we'll create the arguments profile, using a 4-phases algorithm. #
        #                                                                     #

        #######################################################################
        # Phase 1: We specify all the args that don't have a default as
        # positional args:
        defaultless_args = s_args[:-n_defaultful_args] if n_defaultful_args \
                           else s_args[:]
        self.args += tuple(
            dict_tools.get_list(getcallargs_result, defaultless_args))

        #######################################################################
        # Phase 2: We now have to deal with args that have a default. Some of
        # them, possibly none and possibly all of them, should be given
        # positionally. Some of them, possibly none, should be given by
        # keyword. And some of them, possibly none and possibly all of them,
        # should not be given at all. It is our job to figure out in which way
        # each argument should be given.

        # In this variable:
        n_defaultful_args_to_specify_positionally = None
        # We will put the number of defaultful arguments that should be
        # specified positionally.

        defaultful_args = s_args[-n_defaultful_args:] if n_defaultful_args \
                          else []

        # `dict` that maps from argument name to default value:
        defaults = OrderedDict(zip(defaultful_args, s_defaults))

        defaultful_args_differing_from_defaults = set((
            defaultful_arg for defaultful_arg in defaultful_args
            if defaults[defaultful_arg] != getcallargs_result[defaultful_arg]))

        if s_star_args and getcallargs_result[s_star_args]:
            # We have some arguments that go into `*args`! This means that we
            # don't even need to think hard, we can already be sure that we're
            # going to have to specify *all* of the defaultful arguments
            # positionally, otherwise it will be impossible to put arguments in
            # `*args`.
            n_defaultful_args_to_specify_positionally = n_defaultful_args

        else:

            # `dict` mapping from each defaultful arg to the "price" of
            # specifying its value:
            prices_of_values = OrderedDict(
                ((defaultful_arg,
                  len(repr(getcallargs_result[defaultful_arg])))
                 for defaultful_arg in defaultful_args))
            # The price is simply the string length of the value's `repr`.

            # `dict` mapping from each defaultful arg to the "price" of
            # specifying it as a keyword (not including the length of the
            # value):
            prices_of_keyword_prefixes = OrderedDict(
                ((defaultful_arg, len(defaultful_arg) + 1)
                 for defaultful_arg in defaultful_args))
            # For example, if we have a defaultful arg "gravity_strength", then
            # specifiying it by keyword will require using the string
            # "gravity_strength=", which is 17 characters long, therefore the
            # price is 17.

            # Now we need to decide just how many defaultful args we are going
            # to specify positionally. The options are anything from `0` to
            # `n_defaultful_args`. We're going to go one by one, and calcluate
            # the price for each candidate, and put it in this dict:
            total_price_for_n_dasp_candidate = OrderedDict()
            # (The `n_dasp` here is an abbreivation of the
            # `n_defaultful_args_to_specify_positionally` variable defined
            # before.)
            #
            # After we have the price for each option, we'll select the one
            # with the lowest price.

            # One thing to do before iterating on the candidates is to find out
            # whether the "lonely comma discount" is in effect.
            #
            # The "lonely comma discount" is given when there's nothing but
            # defaultful arguments to this function, and therefore the number
            # of ", " strings needed here is not `candidate`, but `candidate -
            # 1`, unless of course candidate is zero.

            if not defaultless_args and \
                (not s_star_args or not getcallargs_result[s_star_args]) and \
                (not s_star_kwargs or not getcallargs_result[s_star_kwargs]):

                lonely_comma_discount_may_be_given = True

            else:

                lonely_comma_discount_may_be_given = False

            # Now we iterate on the candidates to find out which one has the
            # lowest price:

            for candidate in xrange(n_defaultful_args + 1):

                defaultful_args_to_specify_positionally = \
                    defaultful_args[:candidate]

                price_for_positionally_specified_defaultful_args = \
                    2 * candidate + \
                    sum(
                        dict_tools.get_list(
                            prices_of_values,
                            defaultful_args_to_specify_positionally
                        )
                    )
                # The `2 * candidate` addend is to account for the ", " parts
                # between the arguments.

                defaultful_args_to_specify_by_keyword = filter(
                    defaultful_args_differing_from_defaults.__contains__,
                    defaultful_args[candidate:])

                price_for_defaultful_args_specified_by_keyword = \
                    2 * len(defaultful_args_to_specify_by_keyword) + \
                    sum(
                        dict_tools.get_list(
                            prices_of_keyword_prefixes,
                            defaultful_args_to_specify_by_keyword
                        )
                    ) + \
                    sum(
                        dict_tools.get_list(
                            prices_of_values,
                            defaultful_args_to_specify_by_keyword
                        )
                    )
                # The `2 * len(...)` addend is to account for the ", " parts
                # between the arguments.

                # Now we need to figure out if this candidate gets the "lonely
                # comma discount".
                if lonely_comma_discount_may_be_given and \
                   (defaultful_args_to_specify_by_keyword or \
                    defaultful_args_to_specify_positionally):

                    lonely_comma_discount = -2

                else:
                    lonely_comma_discount = 0

                price = price_for_positionally_specified_defaultful_args + \
                        price_for_defaultful_args_specified_by_keyword + \
                        lonely_comma_discount

                total_price_for_n_dasp_candidate[candidate] = price

            # Finished iterating on candidates! Time to pick our winner.

            minimum_price = min(total_price_for_n_dasp_candidate.itervalues())

            leading_candidates = [
                candidate
                for candidate in total_price_for_n_dasp_candidate.iterkeys()
                if total_price_for_n_dasp_candidate[candidate] == minimum_price
            ]

            if len(leading_candidates) == 1:
                # We finished with one candidate which has the minimum price.
                # This is our winner.
                (winner, ) = leading_candidates
                n_defaultful_args_to_specify_positionally = winner

            else:
                # We have a draw! We're gonna have to settle it by picking the
                # lowest candidate, because in our definition of "canonical
                # arguments profile", our second priority after "as few
                # characters as possible" is "as many keyword arguments as
                # possible".
                winner = leading_candidates[0]

            n_defaultful_args_to_specify_positionally = winner

        # We have a winner! Now we know exactly which defaultful args should
        # be specified positionally and which should be specified by
        # keyword.

        # First we add the positionally specified:

        defaultful_args_to_specify_positionally = \
            defaultful_args[:n_defaultful_args_to_specify_positionally]
        self.args += tuple(
            (getcallargs_result[defaultful_arg]
             for defaultful_arg in defaultful_args_to_specify_positionally))

        # Now we add those specified by keyword:

        defaultful_args_to_specify_by_keyword = filter(
            defaultful_args_differing_from_defaults.__contains__,
            defaultful_args[n_defaultful_args_to_specify_positionally:])
        for defaultful_arg in defaultful_args_to_specify_by_keyword:
            self.kwargs[defaultful_arg] = getcallargs_result[defaultful_arg]

        #######################################################################
        # Phase 3: Add the star args:

        if s_star_args and getcallargs_result[s_star_args]:

            assert not self.kwargs
            # Just making sure that no non-star args were specified by keyword,
            # which would make it impossible for us to put stuff in `*args`.

            self.args += getcallargs_result[s_star_args]

        #######################################################################
        # Phase 4: Add the star kwargs:

        if s_star_kwargs and getcallargs_result[s_star_kwargs]:

            # We can't just add the `**kwargs` as is; we need to add them
            # according to canonical ordering. So we need to sort them first.

            unsorted_star_kwargs_names = \
                getcallargs_result[s_star_kwargs].keys()
            sorted_star_kwargs_names = sorted(
                unsorted_star_kwargs_names,
                cmp=cmp_tools.underscore_hating_cmp)

            sorted_star_kwargs = OrderedDict(
                zip(
                    sorted_star_kwargs_names,
                    dict_tools.get_list(getcallargs_result[s_star_kwargs],
                                        sorted_star_kwargs_names)))

            self.kwargs.update(sorted_star_kwargs)

        # Our 4-phases algorithm is done! The argument profile is canonical.  #
        #######################################################################
        #######################################################################

        #######################################################################
        # Now a bit of post-processing:

        _arguments = OrderedDict()

        dict_of_positional_arguments = OrderedDict(
            dict_tools.filter_items(
                getcallargs_result,
                lambda key, value: ((key not in self.kwargs) and \
                                    (key != s_star_args) and \
                                    (key != s_star_kwargs))
            )
        )
        dict_of_positional_arguments.sort(key=s_args.index)
        _arguments.update(dict_of_positional_arguments)

        if s_star_args:
            _arguments['*'] = getcallargs_result[s_star_args]

        _arguments.update(self.kwargs)

        self._arguments = _arguments
        '''Ordered dict of arguments, both positional- and keyword-.'''

        # Caching the hash, since its computation can take a long time:
        self._hash = cheat_hashing.cheat_hash(
            (self.function, self.args, tuple(self.kwargs)))
Esempio n. 17
0
def assert_same_signature(*callables):
    '''Assert that all the `callables` have the same function signature.'''
    arg_specs = [cute_inspect.getargspec(callable_) for callable_ in callables]
    if not logic_tools.all_equal(arg_specs, exhaustive=True):
        raise Failure('Not all the callables have the same signature.')
Esempio n. 18
0
    def __init__(self,
                 step_profiles_controls,
                 step_profile=None,
                 and_fork=False):
        '''
        Construct the `StepProfileDialog`.
        
        If given a `step_profile`, use it as a template. If it's `None`, start
        from scratch. Set `and_fork=True` if you intend to fork right after
        getting the step profile, though note it will only affect the labels;
        the actual forking is not done here.
        '''

        self.step_profiles_controls = step_profiles_controls

        self.gui_project = step_profiles_controls.gui_project
        assert isinstance(self.gui_project, garlicsim_wx.GuiProject)

        self.frame = step_profiles_controls.frame

        self.and_fork = and_fork

        self.simpack = self.gui_project.simpack

        self.simpack_grokker = simpack_grokker = \
            self.gui_project.simpack_grokker

        title = 'Create a new step profile' if not and_fork else \
                'Create a new step profile and fork with it'
        CuteDialog.__init__(self,
                            step_profiles_controls.GetTopLevelParent(),
                            title=title)

        self.SetDoubleBuffered(True)

        self.original_step_profile = original_step_profile = step_profile

        del step_profile

        self.hue = self.gui_project.step_profiles_to_hues.default_factory()

        self.step_functions_to_argument_dicts = \
            StepFunctionsToArgumentDicts(self.describe)

        self.step_functions_to_star_args = \
            collections.defaultdict(lambda: [])

        self.step_functions_to_star_kwargs = \
            collections.defaultdict(lambda: {})

        if original_step_profile:

            original_step_function = original_step_profile.step_function

            self.step_function = original_step_function

            initial_step_function_address = self.describe(
                original_step_function)

            original_argument_dict = collections.defaultdict(
                lambda: '', original_step_profile.getcallargs_result)

            self.step_functions_to_argument_dicts[original_step_function] = \
                dict((key, self.describe(value)) for (key, value) in
                 original_argument_dict.iteritems())

            original_arg_spec = cute_inspect.getargspec(original_step_function)

            if original_arg_spec.varargs:
                star_args_value = original_step_profile.getcallargs_result[
                    original_arg_spec.varargs]

                self.step_functions_to_star_args[original_step_function] = \
                    [self.describe(value) for value in
                     star_args_value]

            if original_arg_spec.keywords:
                star_kwargs_value = original_step_profile.getcallargs_result[
                    original_arg_spec.keywords]

                self.step_functions_to_star_kwargs[original_step_function] = \
                    dict((key, self.describe(value)) for (key, value)
                         in star_kwargs_value.iteritems())

        else:

            self.step_function = None

            if len(simpack_grokker.all_step_functions) >= 2:
                initial_step_function_address = ''
            else:  # len(simpack_grokker.all_step_functions) == 1
                initial_step_function_address = self.describe(
                    simpack_grokker.default_step_function)

        #######################################################################
        # Setting up widgets and sizers:

        self.main_v_sizer = wx.BoxSizer(wx.VERTICAL)

        self.static_text = wx.StaticText(self, label="Choose a step function:")

        self.main_v_sizer.Add(self.static_text,
                              0,
                              wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT,
                              border=10)

        self.h_sizer = wx.BoxSizer(wx.HORIZONTAL)

        self.main_v_sizer.Add(self.h_sizer,
                              0,
                              wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
                              border=10)


        self.hue_control = \
            garlicsim_wx.widgets.general_misc.hue_control.HueControl(
                self,
                lambda: getattr(self, 'hue'),
                lambda hue: setattr(self, 'hue', hue),
                emitter=None,
                lightness=0.8,
                saturation=1,
                dialog_title='Select hue for new step profile',
                size=(25, 20)
            )

        self.h_sizer.Add(self.hue_control, 0, wx.ALIGN_CENTER_VERTICAL)

        self.h_sizer.AddSpacer(5)

        self.step_function_input = StepFunctionInput(
            self, value=initial_step_function_address)

        self.h_sizer.Add(
            self.step_function_input,
            0,
            wx.ALIGN_CENTER_VERTICAL,
        )


        self.static_function_text = StaticFunctionText(
            self,
            step_function=original_step_function if original_step_profile \
                          else None
        )

        self.h_sizer.Add(self.static_function_text,
                         0,
                         wx.ALIGN_CENTER_VERTICAL | wx.LEFT,
                         border=15)

        self.argument_control = ArgumentControl(
            self, original_step_function if original_step_profile else None)

        self.main_v_sizer.Add(self.argument_control,
                              1,
                              wx.ALIGN_CENTER_HORIZONTAL | wx.TOP,
                              border=0)

        self.dialog_button_sizer = wx.StdDialogButtonSizer()

        self.main_v_sizer.Add(self.dialog_button_sizer,
                              0,
                              wx.ALIGN_CENTER | wx.ALL,
                              border=10)

        ok_title = 'Create step profile' if not and_fork else \
                   'Create step profile and fork with it'
        self.ok_button = wx.Button(self, wx.ID_OK, title)
        self.dialog_button_sizer.AddButton(self.ok_button)
        self.ok_button.SetDefault()
        self.dialog_button_sizer.SetAffirmativeButton(self.ok_button)
        self.Bind(wx.EVT_BUTTON, self.on_ok, source=self.ok_button)

        self.cancel_button = wx.Button(self, wx.ID_CANCEL, 'Cancel')
        self.dialog_button_sizer.AddButton(self.cancel_button)
        self.Bind(wx.EVT_BUTTON, self.on_cancel, source=self.cancel_button)
        self.dialog_button_sizer.Realize()

        self.SetSizer(self.main_v_sizer)
        self.main_v_sizer.Fit(self)
Esempio n. 19
0
            return

        try:
            self.argument_control.save()
        except ResolveFailed, resolve_failed_exception:
            error_dialog = ErrorDialog(self, resolve_failed_exception.message)
            try:
                error_dialog.ShowModal()
            finally:
                error_dialog.Destroy()
            resolve_failed_exception.widget.SetFocus()
            return

        step_function = self.step_function

        arg_spec = cute_inspect.getargspec(step_function)

        step_profile = StepProfile.create_from_dld_format(

            step_function,

            dict((key, self.resolve(value_string)) for
                 (key, value_string) in self.\
                 step_functions_to_argument_dicts[step_function].iteritems()
                 if key in arg_spec.args),

            [self.resolve(value_string) for value_string in
             self.step_functions_to_star_args[step_function]],

            dict((key, self.resolve(value_string)) for
                 (key, value_string) in
Esempio n. 20
0
            return
        
        try:
            self.argument_control.save()
        except ResolveFailed, resolve_failed_exception:
            error_dialog = ErrorDialog(self, resolve_failed_exception.message)
            try:
                error_dialog.ShowModal()
            finally:
                error_dialog.Destroy()
            resolve_failed_exception.widget.SetFocus()
            return

        step_function = self.step_function
        
        arg_spec = cute_inspect.getargspec(step_function)
        
        step_profile = StepProfile.create_from_dld_format(
            
            step_function,
            
            dict((key, self.resolve(value_string)) for 
                 (key, value_string) in self.\
                 step_functions_to_argument_dicts[step_function].iteritems()
                 if key in arg_spec.args),
            
            [self.resolve(value_string) for value_string in 
             self.step_functions_to_star_args[step_function]],
            
            dict((key, self.resolve(value_string)) for 
                 (key, value_string) in