vidjil_utils.py 6.47 KB
Newer Older
1
import math
2
import re
3
import defs
4
import json
5
from gluon import current
6
from datetime import date
7

8
def format_size(n, unit='B'):
9 10
    '''
    Takes an integer n, representing a filesize and returns a string
11 12
    where the size is formatted with the correct SI prefix and
    with a constant number of significant digits.
13 14

    Example:
15 16 17 18 19 20
    >>> format_size(42)
    '42 B'
    >>> format_size(123456)
    '123 kB'
    >>> format_size(1000*1000)
    '1.00 MB'
21
    >>> format_size(1024*1024*1024)
22 23 24
    '1.07 GB'
    >>> format_size(42*(2**40))
    '46.2 TB'
25
    '''
26 27 28 29

    if n == 0:
        return '0'

30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
    size = float(n)
    PREFIXES = ['', 'k', 'M', 'G', 'T', 'P']

    for prefix in PREFIXES:
        if size < 1000:
            break
        size /= 1000


    if size > 100 or not prefix:
        fmt = '%.0f'
    elif size > 10:
        fmt = '%.1f'
    else:
        fmt = '%.2f'

    return fmt % size + ' ' + prefix + unit

48

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67


def age_years_months(birth, months_below_year=4):
    '''Get the age in years, and possibly months.'''

    today = date.today()
    years = today.year - birth.year - ((today.month, today.day) < (birth.month, birth.day))
    age = '%dy' % years

    if years >= months_below_year:
        return age

    months = today.month - birth.month - (today.day < birth.day)
    if months < 0:
        months += 12

    age += ' %dm' % months
    return age

68 69 70 71 72 73 74 75 76 77 78 79 80
def anon_birth(patient_id, user_id):
    '''Anonymize birth date. Only the 'anon' access see the full birth date.'''
    db = current.db
    auth=current.auth

    birth = db.patient[patient_id].birth
    age = age_years_months(birth)

    if auth.has_permission("anon", "patient", patient_id, user_id):
        return "%s (%s)" % (birth, age)
    else:
        return age

81
def anon(patient_id, user_id):
82
    '''Anonymize patient name. Only the 'anon' access see the full patient name.'''
83 84 85 86 87 88 89
    db = current.db
    auth=current.auth
    
    last_name = db.patient[patient_id].last_name
    first_name = db.patient[patient_id].first_name
    
    if auth.has_permission("anon", "patient", patient_id, user_id):
90
        name = last_name + " " + first_name
91
    else:
92 93 94 95 96 97
        try:
            ln = unicode(last_name, 'utf-8')
        except UnicodeDecodeError:
            ln = last_name
        name = ln[:3]

98 99 100 101
    # Admins also see the patient id
    if auth.has_membership("admin"):
        name += ' (%s)' % patient_id

102
    return name
103 104 105 106 107 108 109 110 111


# take a string to check and a filter_str (list of word to find (or not)) 
# return true if the string respect the filter list 
def filter(str, filter_str):
    filter_list = filter_str.split(" ")
    
    for f in filter_list :
        if len(f) > 0 and f[0] == "-" :
112
            if f[1:].lower() in str.lower():
113 114
                return False
        else :
115
            if f.lower() not in str.lower():
116 117
                return False
    return True
118 119


120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
#### Utilities on regex
def search_first_regex_in_file(regex, filename, max_nb_line=None):
    try:
        if max_nb_line is None:
            results = open(filename).readlines()
        else:
            results = open(filename).readlines(max_nb_line)
    except IOError as e:
        results = []

    matched_keys = {}
    for r in regex:
        for line in results:
            m = r.search(line)
            if m:
                for (key, val) in m.groupdict().items():
                    matched_keys[key] = val.replace('\\', '')
                break
    return matched_keys

140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

#### Utilities on JSON

def extract_value_from_json_path(json_path, json):
    '''
    Highly inspired from http://stackoverflow.com/a/7320664/1192742

    Takes a path (for instance field1/field2/field3) and returns
    the value at that path.

    If the value doesn't exist None will be returned.
    '''
    elem = json
    try:
        for x in json_path.strip("/").split("/"):
            elem = elem.get(x)
    except:
        pass

    return elem

def extract_fields_from_json(json_fields, pos_in_list, filename):
    '''
    Takes a map of JSON fields (the key is a common name
    and the value is a path) and return a similar map
    where the values are the values from the JSON filename.

    If the value retrieved from a JSON is an array, we will
    get only the item at position <pos_in_list>
    '''
    try:
        json_dict = json.loads(open(filename).read())
    except IOError:
        json_dict = {}

    matched_keys = {}
    for field in json_fields:
        value = extract_value_from_json_path(json_fields[field], json_dict)
        if  not isinstance(value, basestring):
            matched_keys[field] = value[pos_in_list]
        else:
            matched_keys[field] = value

    return matched_keys

####

187 188
log_patient = re.compile('\((\d+)\)')
log_config = re.compile(' c(\d+)')
189
log_task = re.compile('\[(\d+)\]')
190 191 192 193 194 195

def log_links(s):
    '''Add HTML links to a log string

    >>> log_links("abcdef")
    'abcdef'
196
    >>> log_links("[1234]abcdef")
197
    '[<a class="loglink pointer" onclick="db.call(\\'admin/showlog\\', {\\'file\\': \\'../..//mnt/result/tmp/out-001234/001234.vidjil.log\\', \\'format\\': \\'raw\\'})">1234</a>]abcdef'
198
    >>> log_links("abcdef(234)")
199
    'abcdef(<a class="loglink pointer" onclick="db.call(\\'patient/info\\', {\\'id\\': \\'234\\'})">234</a>)'
200
    >>> log_links("abcdef(234)abcdef c11")
201
    'abcdef(234)abcdef <a class="loglink pointer" href="?patient=234&config=11">c11</a>'
202 203 204 205 206 207 208 209 210 211
    '''

    ### Parses the input string

    m_patient = log_patient.search(s)
    patient = m_patient.group(1) if m_patient else None

    m_config = log_config.search(s)
    config = m_config.group(1) if m_config else None

212 213 214
    m_task = log_task.search(s)
    task = int(m_task.group(1)) if m_task else None

215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
    ### Rules

    url = ''  # href link
    call = '' # call to db

    if patient and config:
        url = "?patient=%s&config=%s" % (patient, config)
        (start, end) = m_config.span()
        start += 1

    elif patient:
        call = "patient/info"
        args = {'id': patient}
        (start, end) = m_patient.span()
        start += 1
        end -= 1

232
    if task:
233
        call = "admin/showlog"
234
        args = {'file': '../../' + defs.DIR_OUT_VIDJIL_ID % task + defs.BASENAME_OUT_VIDJIL_ID % task + '.vidjil.log', 'format': 'raw'}
235 236 237 238
        (start, end) = m_task.span()
        start += 1
        end -= 1

239 240 241 242 243 244 245 246 247
    ### Build final string

    link = ''
    if url:
        link = 'href="%s"' % url
    if call:
        link = '''onclick="db.call('%s', %s)"''' % (call, str(args))

    if link:
248
        s = '%s<a class="loglink pointer" %s>%s</a>%s' % (s[:start], link, s[start:end], s[end:])
249 250

    return s