Changeset 430

Show
Ignore:
Timestamp:
05/21/07 19:44:44 (2 years ago)
Author:
athomas
Message:

cly:

  • Cleaned up and added a few more doctests.
  • You can now set a Variable's var_name after construction.
  • Renamed Interact.interact_{loop,once}() to Interact.{loop,once}()
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • cly/trunk/cly/extra.py

    r429 r430  
    4848 
    4949    Each underscore separated part of the function name is converted into a 
    50     Node, each argument without a default is converted into a Variable, and 
    51     each argument with a default is converted into a non-optional Variable. 
     50    Node, each argument without a default is converted into a required 
     51    Variable, and each argument with a default is converted into an optional 
     52    Variable. 
    5253 
    5354    >>> from cly import Grammar 
     
    5657    >>> grammar = Grammar() 
    5758    >>> integrate(grammar, [foo_bar]) 
    58     >>> for i in grammar.walk(): print i 
    59     <Grammar:/> 
    60     <Node:/foo> 
    61     <Node:/foo/bar> 
    62     <Variable:/foo/bar/one> 
    63     <Variable:/foo/bar/one/two> 
    64     <Action:/foo/bar/one/two/action> 
    65     <Node:/foo/bar/one/two/four> 
    66     <Variable:/foo/bar/one/two/four/four> 
    67     <Alias:/foo/bar/one/two/four/four/__anonymous_0 for /foo/bar/one/two/*> 
    68     <Node:/foo/bar/one/two/three> 
    69     <Variable:/foo/bar/one/two/three/three> 
    70     <Alias:/foo/bar/one/two/three/three/__anonymous_0 for /foo/bar/one/two/*> 
     59    >>> list(grammar.walk())    # doctest: +NORMALIZE_WHITESPACE 
     60    [<Grammar:/>, <Node:/foo>, <Node:/foo/bar>, <Variable:/foo/bar/one>, 
     61    <Variable:/foo/bar/one/two>, <Action:/foo/bar/one/two/action>, 
     62    <Node:/foo/bar/one/two/four>, <Variable:/foo/bar/one/two/four/four>, 
     63    <Alias:/foo/bar/one/two/four/four/__anonymous_0 for /foo/bar/one/two/*>, 
     64    <Node:/foo/bar/one/two/three>, <Variable:/foo/bar/one/two/three/three>, 
     65    <Alias:/foo/bar/one/two/three/three/__anonymous_0 for /foo/bar/one/two/*>] 
    7166    """ 
    7267    import inspect 
  • cly/trunk/cly/__init__.py

    r429 r430  
    246246 
    247247        >>> tree = Node('One')(two=Node('Two'), three=Node('Three')) 
    248         >>> for child in tree: print child 
    249         <Node:/three> 
    250         <Node:/two> 
     248        >>> list(tree) 
     249        [<Node:/three>, <Node:/two>] 
    251250        """ 
    252251        children = sorted(self._children.values(), 
     
    260259        >>> node = Node('One') 
    261260        >>> node['two'] = Node('Two') 
    262         >>> for i in node.walk(): print i 
    263         <Node:/> 
    264         <Node:/two> 
     261        >>> list(node.walk()) 
     262        [<Node:/>, <Node:/two>] 
    265263        """ 
    266264        self(**{key: child}) 
     
    279277 
    280278        >>> node = Node('One')(two=Node('Two'), three=Node('Three')) 
    281         >>> for i in node.walk(): print i 
    282         <Node:/> 
    283         <Node:/three> 
    284         <Node:/two> 
     279        >>> list(node.walk()) 
     280        [<Node:/>, <Node:/three>, <Node:/two>] 
    285281        >>> del node['two'] 
    286         >>> for i in node.walk(): print i 
    287         <Node:/> 
    288         <Node:/three> 
     282        >>> list(node.walk()) 
     283        [<Node:/>, <Node:/three>] 
    289284        """ 
    290285        child = self._children.pop(key) 
     
    305300        >>> tree = Node('One')(two=Node('Two', three=Node('Three'), 
    306301        ...                             four=Node('Four'))) 
    307         >>> for i in tree.walk(): print i 
    308         <Node:/> 
    309         <Node:/two> 
    310         <Node:/two/four> 
    311         <Node:/two/three> 
     302        >>> list(tree.walk()) 
     303        [<Node:/>, <Node:/two>, <Node:/two/four>, <Node:/two/three>] 
    312304        """ 
    313305        def walk(root): 
     
    325317        ...                             four=Node('Four')), five=Alias('../two/*')) 
    326318        >>> context = Context(None, None) 
    327         >>> for i in tree.children(context): print i 
    328         <Alias:/five for /two/*> 
    329         <Node:/two> 
    330         >>> for i in tree.children(context, follow=True): print i 
    331         <Node:/two/four> 
    332         <Node:/two/three> 
    333         <Node:/two> 
     319        >>> list(tree.children(context)) 
     320        [<Alias:/five for /two/*>, <Node:/two>] 
     321        >>> list(tree.children(context, follow=True)) 
     322        [<Node:/two/four>, <Node:/two/three>, <Node:/two>] 
    334323        """ 
    335324        for child in self: 
     
    522511    <Alias:/four for /one> 
    523512    >>> context = Context(None, None) 
    524     >>> for node in alias.follow(context): print node 
    525     <Node:/one> 
     513    >>> list(alias.follow(context)) 
     514    [<Node:/one>] 
    526515    >>> alias = parser.find('/five/six') 
    527516    >>> alias 
    528517    <Alias:/five/six for /*> 
    529     >>> for node in alias.follow(context): print node 
    530     <Node:/five> 
    531     <Node:/one> 
    532     <Node:/one> 
    533     <Node:/two> 
     518    >>> list(alias.follow(context)) 
     519    [<Node:/five>, <Node:/one>, <Node:/one>, <Node:/two>] 
    534520    """ 
    535521 
     
    590576    ...     print "some text" 
    591577    >>> grammar = Grammar(action=Action("Write some text", write_text)) 
     578    >>> parser = Parser(grammar) 
     579    >>> context = Context(parser, 'foo bar') 
    592580    >>> node = grammar.find('action') 
    593581    >>> node.help(None) 
     
    595583    >>> list(node.help(None)) 
    596584    [('<eol>', 'Write some text')] 
    597     >>> node.terminal(Context(None, 'foo bar')
     585    >>> node.terminal(context
    598586    some text 
    599587    """ 
    600588    pattern = '$' 
    601589    group = 9999 
    602     with_context = Fals
     590    with_context = Non
    603591 
    604592    def __init__(self, help, callback=None, *args, **kwargs): 
     
    609597 
    610598    def help(self, context): 
     599        """Return help for this action. 
     600 
     601        >>> Action('Test', None).help(None) 
     602        (('<eol>', 'Test'),) 
     603        """ 
    611604        if not self.visible(context): 
    612605            return 
     
    617610 
    618611    def terminal(self, context): 
    619         if self.with_context
     612        if self.with_context or (self.with_context is None and self.parser.with_context)
    620613            return self.callback(context.user_context, **context.vars) 
    621614        else: 
     
    642635    pattern = r'\w+' 
    643636 
    644     def __init__(self, help, var_name=None, *args, **kwargs): 
    645         Node.__init__(self, help, *args, **kwargs) 
    646         self._var_name = var_name 
     637    def __init__(self, *args, **kwargs): 
     638        self._var_name = kwargs.pop('var_name', None) 
     639        Node.__init__(self, *args, **kwargs) 
     640 
     641    def _set_var_name(self, value): 
     642        self._var_name = value 
    647643 
    648644    def _get_var_name(self): 
    649         """Get the var name for this variable. Will use ``var_name`` if provided 
    650         to the constructor, otherwise it will use the node name.""" 
     645        """Get the var name for this variable. Will use ``var_name`` if 
     646        provided to the constructor, otherwise it will use the node name.""" 
    651647        if self._var_name is not None: 
    652648            return self._var_name 
    653649        return self.name 
    654650 
    655     var_name = property(_get_var_name
     651    var_name = property(_get_var_name, _set_var_name
    656652 
    657653    def valid(self, context): 
    658         if not self.traversals or self.traversals > 1 or \ 
     654        if self.traversals != 1 or \ 
    659655                (self.traversals == 1 and self.name not in context.vars) or \ 
    660656                len(context.vars.get(self.name, [])) < self.traversals: 
     
    909905class Parser(object): 
    910906    """Parse and execute CLY grammars.""" 
    911     def __init__(self, grammar): 
     907    def __init__(self, grammar, with_context=False): 
    912908        self.grammar = grammar 
     909        self.with_context = with_context 
    913910 
    914911    def _set_grammar(self, grammar): 
     
    928925 
    929926        >>> parser = Parser(Grammar(one=Node('One'), two=Node('Two', three=Node('Three')))) 
    930         >>> for node in parser: print node 
    931         <Grammar:/> 
    932         <Node:/two> 
    933         <Node:/two/three> 
    934         <Node:/one> 
     927        >>> list(parser) 
     928        [<Grammar:/>, <Node:/two>, <Node:/two/three>, <Node:/one>] 
    935929        """ 
    936930        for node in self.grammar.walk(): 
  • cly/trunk/cly/interactive.py

    r425 r430  
    4949        parse ``Context`` with this object, which in turn will deliver this 
    5050        object on to terminal nodes that have set ``with_context=True``. 
     51 
     52    ``with_context=False``: `boolean` 
     53        Force ``user_context`` to be passed to all action nodes, unless they 
     54        explicitly set the member variable ``with_context=False``. 
     55 
     56    ``history_file=None``: `string` 
     57        Defaults to ``~/.<application>_history``. 
     58 
     59    ``history_length=500``: `integer` 
     60        Lines of history to keep. 
     61 
     62    ``completion_key='tab'``: `string` 
     63        Key to use for completion, per the readline documentation. 
     64 
     65    ``completion_delimiters=' \t'``: `string` 
     66        Characters that terminate completion. 
     67 
     68    ``help_key='?'``: `key` 
     69        Key to use for tab completion. 
     70 
    5171    """ 
    5272    _cli_inject_text = '' 
     
    5979 
    6080    def __init__(self, parser, application='cly', prompt=None, 
    61                  user_context=None, history_file=None, history_length=500
    62                  completion_key='tab', 
     81                 user_context=None, with_context=None, history_file=None
     82                 history_length=500, completion_key='tab', 
    6383                 #completion_delimiters='`!#$%^&*()=+[{]}\|;\'",<>? \t', 
    6484                 completion_delimiters=' \t', 
    65                  help_key='?'): 
     85                 help_key='?', inhibit_exceptions=False, 
     86                 with_backtrace=False): 
    6687        if prompt is None: 
    6788            prompt = application + '> ' 
     
    7192            parser = cly.Parser(parser) 
    7293 
     94        if with_context is not None: 
     95            parser.with_context = with_context 
     96        if user_context is not None: 
     97            parser.user_context = user_context 
    7398        Interact._parser = parser 
    7499        Interact.prompt = prompt 
     
    95120 
    96121 
    97     def interact_once(self, default_text='', callback=None): 
    98         """ Input one command from the user and return the result of the 
     122    def once(self, default_text='', callback=None): 
     123        """Input one command from the user and return the result of the 
    99124        executed command. `callback` is called with the Interact object before 
    100         each line is displayed. """ 
     125        each line is displayed.""" 
    101126        Interact._cli_inject_text = default_text 
    102127 
     
    113138 
    114139            try: 
    115                 context = Interact._parser.parse(command
     140                context = Interact._parser.parse(command, user_context=self.user_context
    116141                context.execute() 
    117142            except cly.ParseError, e: 
     
    119144            return context 
    120145 
     146    def loop(self, inhibit_exceptions=False, with_backtrace=False): 
     147        """Repeatedly read and execute commands from the user. 
     148 
     149        Arguments: 
     150 
     151        ``inhibit_exceptions=True``: `boolean` 
     152            Normally, ``interact_loop`` will pass exceptions back to the caller for 
     153            handling. Setting this to ``True`` will cause an error message to 
     154            be printed, but interaction will continue. 
     155 
     156        ``with_backtrace=False``: `boolean` 
     157            Whether to print a full backtrace when ``inhibit_exceptions=True``. 
     158        """ 
     159        try: 
     160            while True: 
     161                try: 
     162                    if not self.once(): 
     163                        break 
     164                except Exception, e: 
     165                    if inhibit_exceptions: 
     166                        if with_backtrace: 
     167                            import traceback 
     168                            console.error(traceback.format_exc()) 
     169                        else: 
     170                            console.error('error: %s' % e) 
     171                    else: 
     172                        raise 
     173        finally: 
     174            self.write_history() 
     175 
    121176    def print_error(self, context, e): 
    122         """Called by `interact_once()` to print a ParseError.""" 
     177        """Called by `once()` to print a ParseError.""" 
    123178        candidates = [help[1] for help in context.help()] 
    124179        if len(candidates) > 1: 
     
    141196        else: 
    142197            console.error(indent + '^ ' + text) 
    143  
    144     def interact_loop(self): 
    145         """ Repeatedly read and execute commands from the user. """ 
    146         try: 
    147             while self.interact_once(): 
    148                 pass 
    149         finally: 
    150             self.write_history() 
    151198 
    152199    def write_history(self):