source: peerreviewplugin/trunk/codereview/tracgenericclass/util.py

Last change on this file was 18253, checked in by Cinc-th, 2 years ago

PeerReviewPlugin: replace req.args.get() by req.args.getlist() when asking for lists. Fixes a problem where not all selected files and users were added to a review.

File size: 9.0 KB
Line 
1# -*- coding: utf-8 -*-
2#
3# Copyright (C) 2010-2015 Roberto Longobardi
4# Copyright (C) 2016-2021 Cinc
5#
6# This file is part of the Test Manager plugin for Trac.
7#
8# This software is licensed as described in the file COPYING, which
9# you should have received as part of this distribution. The terms
10# are also available at:
11#   https://trac-hacks.org/wiki/TestManagerForTracPluginLicense
12#
13# Author: Roberto Longobardi <otrebor.dev@gmail.com>
14#
15
16import os
17import shutil
18import sys
19import traceback
20
21from trac.core import *
22
23
24def formatExceptionInfo(maxTBlevel=5):
25    cla, exc, trbk = sys.exc_info()
26    excName = cla.__name__
27
28    try:
29        excArgs = exc.__dict__["args"]
30    except KeyError:
31        excArgs = "<no args>"
32
33    excTb = traceback.format_tb(trbk, maxTBlevel)
34
35    tracestring = ""
36    for step in excTb:
37        tracestring += step + "\n"
38
39    return "Error name: %s\nArgs: %s\nTraceback:\n%s" % (excName, excArgs, tracestring)
40
41
42def to_any_timestamp(date_obj):
43    from trac.util.datefmt import to_utimestamp
44    return to_utimestamp(date_obj)
45
46
47def from_any_timestamp(ts):
48    from trac.util.datefmt import from_utimestamp
49    return from_utimestamp(ts)
50
51
52def to_list(params):
53    result = []
54
55    for i in params:
56        if isinstance(i, list):
57            for v in i:
58                result.append(v)
59        else:
60            result.append(i)
61
62    return tuple(result)
63
64
65def get_dictionary_from_string(str):
66    result = {}
67
68    sub = str.partition('{')[2].rpartition('}')[0]
69    tokens = sub.split(",")
70
71    for tok in tokens:
72        name = remove_quotes(tok.partition(':')[0])
73        value = remove_quotes(tok.partition(':')[2])
74
75        result[name] = value
76
77    return result
78
79
80def get_string_from_dictionary(dictionary, values=None):
81    if values is None:
82        values = dictionary
83
84    result = '{'
85    for i, k in enumerate(dictionary):
86        # TODO: send a patch for the following line
87        # result += "'"+k+"':'"+values[k]+"'"  # old code not working for int values
88        result += "'%s':'%s'" % (k, values[k])
89        if i < len(dictionary)-1:
90            result += ","
91
92    result += '}'
93
94    return result
95
96
97def remove_quotes(str, quote='\''):
98    return str.partition(quote)[2].rpartition(quote)[0]
99
100
101def compatible_domain_functions(domain, function_name_list):
102    return lambda x: x, lambda x: x, lambda x: x, lambda x: x
103
104
105def get_timestamp_db_type():
106    return 'int64'
107
108
109def db_insert_or_ignore(env, tablename, propname, value, db=None):
110    if db_get_config_property(env, tablename, propname) is None:
111        db_set_config_property(env, tablename, propname, value)
112
113
114def db_get_config_property(env, tablename, propname, db=None):
115    sql = "SELECT value FROM %s WHERE propname=%%s" % tablename
116    row = None
117    with env.db_query as db:
118        cursor = db.cursor()
119        try:
120            cursor.execute(sql, (propname,))
121            row = cursor.fetchone()
122        except:
123            pass
124
125    if not row or len(row) == 0:
126        return None
127
128    return row[0]
129
130
131def db_set_config_property(env, tablename, propname, value):
132    with env.db_transaction as db:
133        cursor = db.cursor()
134
135        sql = "SELECT COUNT(*) FROM %s WHERE propname = %%s" % tablename
136        cursor.execute(sql, (propname,))
137
138        row = cursor.fetchone()
139        if row is not None and int(row[0]) > 0:
140            cursor.execute("""
141                           UPDATE %s
142                               SET value = %%s
143                               WHERE propname = %%s
144                           """ % tablename, (str(value), propname))
145        else:
146            cursor.execute("""
147                           INSERT INTO %s (propname,value)
148                               VALUES (%%s,%%s)
149                           """ % tablename, (propname, str(value)))
150
151    return True
152
153
154def list_available_tables(dburi, cursor):
155    if dburi.startswith('sqlite:'):
156        query = """
157            SELECT name FROM sqlite_master
158            WHERE type='table' AND NOT name='sqlite_sequence'
159            """
160    elif dburi.startswith('postgres:'):
161        query = """
162            SELECT tablename FROM pg_tables
163            WHERE schemaname = ANY (current_schemas(false))
164            """
165    elif dburi.startswith('mysql:'):
166        query = "SHOW TABLES"
167    else:
168        raise TracError('Unsupported %s database' % dburi.split(':')[0])
169    cursor.execute(query)
170
171    return sorted([row[0] for row in cursor])
172
173
174def fix_base_location(req):
175    return req.href('/').rstrip('/')
176
177
178## {{{ http://code.activestate.com/recipes/550804/ (r2)
179# The list of symbols that are included by default in the generated
180# function's environment
181SAFE_SYMBOLS = ["list", "dict", "tuple", "set", "long", "float", "object",
182                "bool", "callable", "True", "False", "dir",
183                "frozenset", "getattr", "hasattr", "abs", "cmp", "complex",
184                "divmod", "id", "pow", "round", "slice", "vars",
185                "hash", "hex", "int", "isinstance", "issubclass", "len",
186                "map", "filter", "max", "min", "oct", "chr", "ord", "range",
187                "reduce", "repr", "str", "type", "zip", "xrange", "None",
188                "Exception", "KeyboardInterrupt"]
189# Also add the standard exceptions
190__bi = __builtins__
191if type(__bi) is not dict:
192    __bi = __bi.__dict__
193for k in __bi:
194    if k.endswith("Error") or k.endswith("Warning"):
195        SAFE_SYMBOLS.append(k)
196del __bi
197
198
199def createFunctionFromString(sourceCode, args="", additional_symbols=dict()):
200    """
201    Create a python function from the given source code
202
203    \param sourceCode A python string containing the core of the
204    function. Might include the return statement (or not), definition of
205    local functions, classes, etc. Indentation matters !
206
207    \param args The string representing the arguments to put in the function's
208    prototype, such as "a, b", or "a=12, b",
209    or "a=12, b=dict(akey=42, another=5)"
210
211    \param additional_symbols A dictionary variable name =>
212    variable/funcion/object to include in the generated function's
213    closure
214
215    The sourceCode will be executed in a restricted environment,
216    containing only the python builtins that are harmless (such as map,
217    hasattr, etc.). To allow the function to access other modules or
218    functions or objects, use the additional_symbols parameter. For
219    example, to allow the source code to access the re and sys modules,
220    as well as a global function F named afunction in the sourceCode and
221    an object OoO named ooo in the sourceCode, specify:
222        additional_symbols = dict(re=re, sys=sys, afunction=F, ooo=OoO)
223
224    \return A python function implementing the source code. It can be
225    recursive: the (internal) name of the function being defined is:
226    __TheFunction__. Its docstring is the initial sourceCode string.
227
228    Tests show that the resulting function does not have any calling
229    time overhead (-3% to +3%, probably due to system preemption aleas)
230    compared to normal python function calls.
231    """
232    # Include the sourcecode as the code of a function __TheFunction__:
233    s = "def __TheFunction__(%s):\n" % args
234    s += "\t" + "\n\t".join(sourceCode.split('\n')) + "\n"
235
236    # Byte-compilation (optional)
237    byteCode = compile(s, "<string>", 'exec')
238
239    # Setup the local and global dictionaries of the execution
240    # environment for __TheFunction__
241    bis   = dict() # builtins
242    globs = dict()
243    locs  = dict()
244
245    # Setup a standard-compatible python environment
246    bis["locals"]  = lambda: locs
247    bis["globals"] = lambda: globs
248    globs["__builtins__"] = bis
249    globs["__name__"] = "SUBENV"
250    globs["__doc__"] = sourceCode
251
252    # Determine how the __builtins__ dictionary should be accessed
253    if type(__builtins__) is dict:
254        bi_dict = __builtins__
255    else:
256        bi_dict = __builtins__.__dict__
257
258    # Include the safe symbols
259    for k in SAFE_SYMBOLS:
260        # try from current locals
261        try:
262            locs[k] = locals()[k]
263            continue
264        except KeyError:
265            pass
266        # Try from globals
267        try:
268            globs[k] = globals()[k]
269            continue
270        except KeyError:
271            pass
272        # Try from builtins
273        try:
274            bis[k] = bi_dict[k]
275        except KeyError:
276            # Symbol not available anywhere: silently ignored
277            pass
278
279    # Include the symbols added by the caller, in the globals dictionary
280    globs.update(additional_symbols)
281
282    # Finally execute the def __TheFunction__ statement:
283    eval(byteCode, globs, locs)
284    # As a result, the function is defined as the item __TheFunction__
285    # in the locals dictionary
286    fct = locs["__TheFunction__"]
287    # Attach the function to the globals so that it can be recursive
288    del locs["__TheFunction__"]
289    globs["__TheFunction__"] = fct
290    # Attach the actual source code to the docstring
291    fct.__doc__ = sourceCode
292    return fct
293## end of http://code.activestate.com/recipes/550804/ }}}
294
295# Example:
296#
297# import sys, re
298#
299# f = createFunction("print a\nprint b", "a=3, b=4",
300#                    additional_symbols = dict(re=re, sys=sys,
301#                                              afunction=F, ooo=OoO))
302# f()
303# f(12)
304# f(b=7, a=8)
305# f(9, 10)
Note: See TracBrowser for help on using the repository browser.