示例#1
0
class TimedProgressBar(ProgressBar):
    """A 3-line progress bar, which looks like::
                                      title
        39% [================>----------------------------] ETA mm:ss
                                     message
    
        p = ProgressBar('spam') # create bar
        p.update(0, 'starting spam') # start printing it out
        p.update(50, 'spam almost ready') # progress
        p.update(100, 'spam complete')
    """

    BAR_FORMAT = {
        'text':
        ' %3d%% ' + '[%s' + display('dim') + '%s' + display('default') + ']',
        'length': 13,
        'padding': 2
    }
    ' ETA 12:23'

    # what fraction of percent it acurate too
    precision = 100

    def __init__(self, title=None):
        ProgressBar.__init__(self, title)
        self.start = datetime.today()

    def get_bar(self, percent):
        now = datetime.today()
        timed = now - self.start
        etatext = ''
        etadiv = int(percent * self.precision)
        if timed.seconds >= 1:
            etatext += ' '
            if int(percent * self.precision) != 0:
                eta = (timed * 100 * self.precision) / int(
                    percent * self.precision)
                days = eta.days
                min, sec = divmod(eta.seconds, 60)
                hours, min = divmod(min, 60)
                if days == 1: etatext += '1 day, '
                elif days: etatext += '%d days, ' % days
                if hours: etatext += '%02d:' % hours
                etatext += '%02d:%02d' % (min, sec)
            else:
                etatext += 'Never'
        barlength = (self.width - self.BAR_FORMAT['padding'] * 2 -
                     self.BAR_FORMAT['length'] - len(etatext))
        full = int(math.ceil(barlength * (percent / 100.0)))
        empty = int(barlength - full)
        if full == 0 or empty == 0: fullpiece = ('=' * full)
        else: fullpiece = ('=' * (full - 1)) + '>'
        emptypiece = ('-' * empty)
        return [(self.BAR_FORMAT['text'] % (percent, fullpiece, emptypiece)) +
                etatext]
示例#2
0
def query(question, values, default=None, list_values = False, ignorecase = True ):
    """Preset a few options
    
    The question argument is a string, nothing magical.
    
    The values argument accepts input in two different forms. The simpler form
    (a tuple with strings) looks like:
    
        .. code-block:: python
        
            ('Male','Female')
    
    And it will pop up a question asking the user for a gender and requiring
    the user to enter either 'male' or 'female' (case doesn't matter unless
    you set the third arguement to false).
    The other form is something like:
    
        .. code-block:: python
        
            ({'values':('Male','M'),'fg':'cyan'},
            {'values':('Female','F'),'fg':'magenta'})
    
    This will pop up a question with Male/Female (each with appropriate
    colouring). Additionally, if the user types in just 'M', it will be
    treated as if 'Male' was typed in. The first item in the 'values' tuple
    is treated as default and is the one that is returned by the function
    if the user chooses one in that group.
    In addition the function can handle non-string objects quite fine. It
    simple displays the output object.__str__() and compares the user's input
    against that. So the the code
    
        .. code-block:: python
        
            query("Python rocks? ",(True, False))
    
    will return a bool (True) when the user types in the string 'True' (Of
    course there isn't any other reasonable answer than True anyways :P)
    
    ``default`` is the value function returns if the user types nothing in. This is
    can be used to cancel the input so-to-speek
    
    Using list_values = False will display a list, with descriptions printed out
    from the 'desc' keyword
    """
    values = list(values)
    for i in range(len(values)):
        if not isinstance(values[i], dict):
            values[i] = {'values': [values[i]]}
    try:
        import readline, rlcomplete
        wordlist = [ str(v) for value in values
                    for v in value['values']]
        completer = rlcomplete.ListCompleter(wordlist, ignorecase)
        readline.parse_and_bind("tab: complete")
        readline.set_completer(completer.complete)
    except ImportError:
        pass
    valuelist = []
    for item in values:
        entry = ( display('bright', item.get('fg'), item.get('bg')) +
            str(item['values'][0]) + display(['default']) )
        if str(item['values'][0]) == str(default): entry = '['+entry+']'
        if list_values: entry += ' : ' + item['desc']
        valuelist.append(entry)
    if list_values: question += os.linesep + os.linesep.join(valuelist) + os.linesep
    else: question += ' (' + '/'.join(valuelist) + ')'
    return input_object(question, cast = query_cast, default=default,
                 castarg=[values,ignorecase])
示例#3
0
"""Input and output functions
"""

import sys
import os
import os.path
import term
from term import stdout, stderr, display

__all__ = ["input_object","query","file_chooser"]

# this constant is here because float() and int() give error messages
# that would confuse most sane users.

ERROR_MESSAGE = ( display('bright','red') + 'Error: ' + display('default') +
                 '%s' + '\a' + os.linesep )
NICE_INPUT_ERRORS = {
    float: "The input ('%s') must be a number",
    int: "The input ('%s') must be an integer (-1, 0, 1, 2, etc.)"
}

DEFAULT_INPUT_ERRORS = "Bad input (%s)"

def input_object(prompt_text, cast = None, default = None,
                 prompt_ext = ': ', castarg = [], castkwarg = {}):
    """Gets input from the command line and validates it.
    
    prompt_text
        A string. Used to prompt the user. Do not include a trailing
        space.
示例#4
0
def query(question, values, default=None, list_values=False, ignorecase=True):
    """Preset a few options
    
    The question argument is a string, nothing magical.
    
    The values argument accepts input in two different forms. The simpler form
    (a tuple with strings) looks like:
    
        .. code-block:: python
        
            ('Male','Female')
    
    And it will pop up a question asking the user for a gender and requiring
    the user to enter either 'male' or 'female' (case doesn't matter unless
    you set the third arguement to false).
    The other form is something like:
    
        .. code-block:: python
        
            ({'values':('Male','M'),'fg':'cyan'},
            {'values':('Female','F'),'fg':'magenta'})
    
    This will pop up a question with Male/Female (each with appropriate
    colouring). Additionally, if the user types in just 'M', it will be
    treated as if 'Male' was typed in. The first item in the 'values' tuple
    is treated as default and is the one that is returned by the function
    if the user chooses one in that group.
    In addition the function can handle non-string objects quite fine. It
    simple displays the output object.__str__() and compares the user's input
    against that. So the the code
    
        .. code-block:: python
        
            query("Python rocks? ",(True, False))
    
    will return a bool (True) when the user types in the string 'True' (Of
    course there isn't any other reasonable answer than True anyways :P)
    
    ``default`` is the value function returns if the user types nothing in. This is
    can be used to cancel the input so-to-speek
    
    Using list_values = False will display a list, with descriptions printed out
    from the 'desc' keyword
    """
    values = list(values)
    for i in range(len(values)):
        if not isinstance(values[i], dict):
            values[i] = {'values': [values[i]]}
    try:
        import readline, rlcomplete
        wordlist = [str(v) for value in values for v in value['values']]
        completer = rlcomplete.ListCompleter(wordlist, ignorecase)
        readline.parse_and_bind("tab: complete")
        readline.set_completer(completer.complete)
    except ImportError:
        pass
    valuelist = []
    for item in values:
        entry = (display('bright', item.get('fg'), item.get('bg')) +
                 str(item['values'][0]) + display(['default']))
        if str(item['values'][0]) == str(default): entry = '[' + entry + ']'
        if list_values: entry += ' : ' + item['desc']
        valuelist.append(entry)
    if list_values:
        question += os.linesep + os.linesep.join(valuelist) + os.linesep
    else:
        question += ' (' + '/'.join(valuelist) + ')'
    return input_object(question,
                        cast=query_cast,
                        default=default,
                        castarg=[values, ignorecase])
示例#5
0
# limitations under the License.
"""Input and output functions
"""

import sys
import os
import os.path
import term
from term import stdout, stderr, display

__all__ = ["input_object", "query", "file_chooser"]

# this constant is here because float() and int() give error messages
# that would confuse most sane users.

ERROR_MESSAGE = (display('bright', 'red') + 'Error: ' + display('default') +
                 '%s' + '\a' + os.linesep)
NICE_INPUT_ERRORS = {
    float: "The input ('%s') must be a number",
    int: "The input ('%s') must be an integer (-1, 0, 1, 2, etc.)"
}

DEFAULT_INPUT_ERRORS = "Bad input (%s)"


def input_object(prompt_text,
                 cast=None,
                 default=None,
                 prompt_ext=': ',
                 castarg=[],
                 castkwarg={}):
示例#6
0
class ProgressBar(object):
    """A 3-line progress bar, which looks like::
                                title
        39% [================>----------------------------]
                               message
    
        p = ProgressBar('spam') # create bar
        p.update(0, 'starting spam') # start printing it out
        p.update(50, 'spam almost ready') # progress
        p.update(100, 'spam complete')
    """
    # content, length
    TITLE_FORMAT = {
        'text': display('bright', 'cyan') + '%s' + display('default'),
        'length': 0,
        'padding': 0
    }
    BAR_FORMAT = {
        'text':
        ' %3d%% ' + '[%s' + display('dim') + '%s' + display('default') + ']',
        'length': 8,
        'padding': 2
    }
    MESSAGE_FORMAT = {'text': '%s', 'length': 0, 'padding': 0}

    def __init__(self, title=None):
        """
        """
        self.drawn = False
        cols = stdout.get_size()[0]
        self.width = cols - 1  # TODO: make a better fix for systems that put \n on new line
        self.title = []
        self.barlines = 0
        self.message = []
        self.messageline = None
        self.refresh = False
        self.set_title(title)

    def set_title(self, title=None):
        """
        """
        if title == None:
            self.title = []
        else:
            length = self.width - self.TITLE_FORMAT[
                'padding'] * 2 - self.TITLE_FORMAT['length']
            text = title[:length].center(
                length)  # we need to keep it on one line for now
            padding = ' ' * self.TITLE_FORMAT['padding']
            self.title = [
                padding + (self.TITLE_FORMAT['text'] % text) + padding
            ]
        self.refresh = self.drawn
        #lines = [(padding + line + padding) for line in textwrap.wrap(
        #          text, self.width - (self.TITLE_FORMAT['padding']*2),
        #          replace_whitespace=False)]
        #self.title = os.linesep.split(
        #          self.TITLE_FORMAT['text'] % os.linesep.join(lines))

    def get_title(self):
        """
        """
        return self.title

    def get_bar(self, percent):
        """
        """
        barlength = self.width - self.BAR_FORMAT[
            'padding'] * 2 - self.BAR_FORMAT['length']
        full = int(math.ceil(barlength * (percent / 100.0)))
        empty = int(barlength - full)
        if full == 0 or empty == 0: fullpiece = ('=' * full)
        else: fullpiece = ('=' * (full - 1)) + '>'
        emptypiece = ('-' * empty)
        return [(self.BAR_FORMAT['text'] % (percent, fullpiece, emptypiece))]

    def set_message(self, message=None):
        """
        """
        """"""
        if message == None:
            self.message = []
        else:
            length = self.width - self.MESSAGE_FORMAT[
                'padding'] * 2 - self.MESSAGE_FORMAT['length']
            text = message[:length].center(
                length)  # we need to keep it on one line for now
            padding = ' ' * self.MESSAGE_FORMAT['padding']
            self.message = [
                padding + (self.MESSAGE_FORMAT['text'] % text) + padding
            ]

    def get_message(self):
        """returns None or string"""
        if self.message == []: return None
        else: return os.linesep.join(self.message)

    def update(self, percent, message=None, test=False):
        """
        """
        if self.refresh:
            self.clear()
        if self.drawn:
            stdout.move('beginning of line')
            stdout.move('up', len(self.message) + self.barlines)
        else:
            title = self.get_title()
            if title != None:
                for line in self.get_title():
                    stdout.write(line + os.linesep)
            self.drawn = True
        bar = self.get_bar(percent)
        refresh = (len(bar) != self.barlines)
        self.barlines = len(bar)
        for line in bar:
            stdout.clear('line')
            stdout.write(line)
            stdout.move('down')
            stdout.move('beginning of line')
        if (message != self.get_message()) or refresh:
            stdout.clear('end of screen')
            self.set_message(message)
            for line in self.message:
                stdout.write(line)
                stdout.move('down')
        else:
            stdout.move('down', len(self.message))

    def clear(self):
        """
        """
        if self.drawn:
            stdout.move('beginning of line')
            stdout.move('up', len(self.message))
            stdout.move('up', self.barlines)
            stdout.move('up', len(self.get_title()))
            stdout.clear('end of screen')
            self.drawn = False
        self.refresh = False