Statistics
| Branch: | Tag: | Revision:

root / snf-webproject / synnefo / webproject / management / util.py @ 225cea18

History | View | Annotate | Download (4.7 kB)

1
# Copyright 2012 - 2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
from datetime import datetime
35
from django.utils.timesince import timesince, timeuntil
36

    
37
from synnefo.util.text import uenc, udec
38

    
39

    
40
def parse_bool(value, strict=True):
41
    """Convert a string to boolen value.
42

43
    If string is True, then ValueError will be raised, if the string can not be
44
    converted to boolean. Otherwise the string will be returned as is.
45

46
    """
47
    if value.lower() in ("yes", "true", "t", "1"):
48
        return True
49
    if value.lower() in ("no", "false", "f", "0"):
50
        return False
51

    
52
    if strict:
53
        raise ValueError("Can convert '%s' to boolean value")
54
    else:
55
        return value
56

    
57

    
58
def format_bool(b):
59
    """Convert a boolean value to YES or NO."""
60
    return "YES" if b else "NO"
61

    
62

    
63
def format_date(d):
64
    if not d:
65
        return ""
66

    
67
    if d < datetime.now():
68
        return timesince(d) + " ago"
69
    else:
70
        return "in " + timeuntil(d)
71

    
72

    
73
def parse_filters(filter_by):
74
    """Parse a string into lookup parameters for QuerySet.filter(**kwargs).
75

76
    This functions converts a string of comma-separated key 'cond' val triples
77
    to two dictionaries, containing lookup parameters to be used for filter
78
    and exclude functions of QuerySet.
79

80
    e.g. filter_by="foo>=2, baz!=4" -> ({"foo__gte": "2"}, {"baz": "4"})
81

82
    """
83

    
84
    filter_dict = {}
85
    exclude_dict = {}
86

    
87
    filter_list = filter_by.split(",")
88

    
89
    def map_field_type(query):
90
        if "!=" in query:
91
            key, val = query.split("!=")
92
            exclude_dict[key] = parse_bool(val, strict=False)
93
            return
94

    
95
        OP_MAP = {
96
            ">=": "__gte",
97
            "=>": "__gte",
98
            ">":  "__gt",
99
            "<=": "__lte",
100
            "=<": "__lte",
101
            "<":  "__lt",
102
            "=":  "",
103
        }
104

    
105
        for op, new_op in OP_MAP.items():
106
            if op in query:
107
                key, val = query.split(op)
108
                filter_dict[key + new_op] = parse_bool(val, strict=False)
109
                return
110

    
111
    map(lambda x: map_field_type(x), filter_list)
112

    
113
    return (filter_dict, exclude_dict)
114

    
115

    
116
def pprint_table(out, table, headers=None, separator=None):
117
    """Print a pretty, aligned string representation of table.
118

119
    Works by finding out the max width of each column and padding to data
120
    to this value.
121
    """
122

    
123
    assert(isinstance(table, (list, tuple))), "Invalid table type"
124
    sep = separator if separator else "  "
125

    
126
    if headers:
127
        assert(isinstance(headers, (list, tuple))), "Invalid headers type"
128
        table.insert(0, headers)
129

    
130
    def strignify(obj):
131
        if isinstance(obj, (unicode, str)):
132
            return udec(obj)
133
        else:
134
            return str(obj)
135

    
136
    table = [map(strignify, row) for row in table]
137

    
138
    # Find out the max width of each column
139
    widths = [max(map(len, col)) for col in zip(*table)]
140

    
141
    t_length = sum(widths) + len(sep) * (len(widths) - 1)
142
    if headers:
143
        # pretty print the headers
144
        line = sep.join(uenc(v.rjust(w)) for v, w in zip(headers, widths))
145
        out.write(line + "\n")
146
        out.write("-" * t_length + "\n")
147
        # remove headers
148
        table = table[1:]
149

    
150
    # print the rest table
151
    for row in table:
152
        line = sep.join(uenc(v.rjust(w)) for v, w in zip(row, widths))
153
        out.write(line + "\n")