Statistics
| Branch: | Tag: | Revision:

root / snf-webproject / synnefo / webproject / management / util.py @ b0e7f310

History | View | Annotate | Download (5.3 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
import json
35
from datetime import datetime
36
from django.utils.timesince import timesince, timeuntil
37

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

    
40

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

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

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

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

    
58

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

    
63

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

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

    
73

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

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

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

83
    """
84

    
85
    filter_dict = {}
86
    exclude_dict = {}
87

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

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

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

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

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

    
114
    return (filter_dict, exclude_dict)
115

    
116

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

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

    
125
    assert(isinstance(table, (list, tuple))), "Invalid table type"
126
    if headers:
127
        assert(isinstance(headers, (list, tuple))), "Invalid headers type"
128

    
129
    sep = separator if separator else "  "
130

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

    
137
    headers = map(stringnify, headers)
138
    table = [map(stringnify, row) for row in table]
139

    
140
    if output_format == "json":
141
        table = [dict(zip(headers, row)) for row in table]
142
        out.write(json.dumps(table, indent=4))
143
        out.write("\n")
144
    elif output_format == "csv":
145
        if headers:
146
            line = ",".join("\"%s\"" % uenc(v) for v in headers)
147
            out.write(line + "\n")
148
            for row in table:
149
                line = ",".join("\"%s\"" % uenc(v) for v in row)
150
                out.write(line + "\n")
151
    elif output_format == "pretty":
152
        # Find out the max width of each column
153
        widths = [max(map(len, col)) for col in zip(*([headers] + table))]
154

    
155
        t_length = sum(widths) + len(sep) * (len(widths) - 1)
156
        if headers:
157
            # pretty print the headers
158
            line = sep.join(uenc(v.rjust(w)) for v, w in zip(headers, widths))
159
            out.write(line + "\n")
160
            out.write("-" * t_length + "\n")
161

    
162
        # print the rest table
163
        for row in table:
164
            line = sep.join(uenc(v.rjust(w)) for v, w in zip(row, widths))
165
            out.write(line + "\n")
166
    else:
167
        raise ValueError("Unknown output format '%s'" % output_format)