| 1 |
import datetime |
|---|
| 2 |
from time import time |
|---|
| 3 |
|
|---|
| 4 |
from django.utils.hashcompat import md5_constructor |
|---|
| 5 |
|
|---|
| 6 |
try: |
|---|
| 7 |
import decimal |
|---|
| 8 |
except ImportError: |
|---|
| 9 |
from django.utils import _decimal as decimal # for Python 2.3 |
|---|
| 10 |
|
|---|
| 11 |
class CursorDebugWrapper(object): |
|---|
| 12 |
def __init__(self, cursor, db): |
|---|
| 13 |
self.cursor = cursor |
|---|
| 14 |
self.db = db # Instance of a BaseDatabaseWrapper subclass |
|---|
| 15 |
|
|---|
| 16 |
def execute(self, sql, params=()): |
|---|
| 17 |
start = time() |
|---|
| 18 |
try: |
|---|
| 19 |
return self.cursor.execute(sql, params) |
|---|
| 20 |
finally: |
|---|
| 21 |
stop = time() |
|---|
| 22 |
sql = self.db.ops.last_executed_query(self.cursor, sql, params) |
|---|
| 23 |
self.db.queries.append({ |
|---|
| 24 |
'sql': sql, |
|---|
| 25 |
'time': "%.3f" % (stop - start), |
|---|
| 26 |
}) |
|---|
| 27 |
|
|---|
| 28 |
def executemany(self, sql, param_list): |
|---|
| 29 |
start = time() |
|---|
| 30 |
try: |
|---|
| 31 |
return self.cursor.executemany(sql, param_list) |
|---|
| 32 |
finally: |
|---|
| 33 |
stop = time() |
|---|
| 34 |
self.db.queries.append({ |
|---|
| 35 |
'sql': '%s times: %s' % (len(param_list), sql), |
|---|
| 36 |
'time': "%.3f" % (stop - start), |
|---|
| 37 |
}) |
|---|
| 38 |
|
|---|
| 39 |
def __getattr__(self, attr): |
|---|
| 40 |
if attr in self.__dict__: |
|---|
| 41 |
return self.__dict__[attr] |
|---|
| 42 |
else: |
|---|
| 43 |
return getattr(self.cursor, attr) |
|---|
| 44 |
|
|---|
| 45 |
def __iter__(self): |
|---|
| 46 |
return iter(self.cursor) |
|---|
| 47 |
|
|---|
| 48 |
############################################### |
|---|
| 49 |
# Converters from database (string) to Python # |
|---|
| 50 |
############################################### |
|---|
| 51 |
|
|---|
| 52 |
def typecast_date(s): |
|---|
| 53 |
return s and datetime.date(*map(int, s.split('-'))) or None # returns None if s is null |
|---|
| 54 |
|
|---|
| 55 |
def typecast_time(s): # does NOT store time zone information |
|---|
| 56 |
if not s: return None |
|---|
| 57 |
hour, minutes, seconds = s.split(':') |
|---|
| 58 |
if '.' in seconds: # check whether seconds have a fractional part |
|---|
| 59 |
seconds, microseconds = seconds.split('.') |
|---|
| 60 |
else: |
|---|
| 61 |
microseconds = '0' |
|---|
| 62 |
return datetime.time(int(hour), int(minutes), int(seconds), int(float('.'+microseconds) * 1000000)) |
|---|
| 63 |
|
|---|
| 64 |
def typecast_timestamp(s): # does NOT store time zone information |
|---|
| 65 |
# "2005-07-29 15:48:00.590358-05" |
|---|
| 66 |
# "2005-07-29 09:56:00-05" |
|---|
| 67 |
if not s: return None |
|---|
| 68 |
if not ' ' in s: return typecast_date(s) |
|---|
| 69 |
d, t = s.split() |
|---|
| 70 |
# Extract timezone information, if it exists. Currently we just throw |
|---|
| 71 |
# it away, but in the future we may make use of it. |
|---|
| 72 |
if '-' in t: |
|---|
| 73 |
t, tz = t.split('-', 1) |
|---|
| 74 |
tz = '-' + tz |
|---|
| 75 |
elif '+' in t: |
|---|
| 76 |
t, tz = t.split('+', 1) |
|---|
| 77 |
tz = '+' + tz |
|---|
| 78 |
else: |
|---|
| 79 |
tz = '' |
|---|
| 80 |
dates = d.split('-') |
|---|
| 81 |
times = t.split(':') |
|---|
| 82 |
seconds = times[2] |
|---|
| 83 |
if '.' in seconds: # check whether seconds have a fractional part |
|---|
| 84 |
seconds, microseconds = seconds.split('.') |
|---|
| 85 |
else: |
|---|
| 86 |
microseconds = '0' |
|---|
| 87 |
return datetime.datetime(int(dates[0]), int(dates[1]), int(dates[2]), |
|---|
| 88 |
int(times[0]), int(times[1]), int(seconds), int(float('.'+microseconds) * 1000000)) |
|---|
| 89 |
|
|---|
| 90 |
def typecast_boolean(s): |
|---|
| 91 |
if s is None: return None |
|---|
| 92 |
if not s: return False |
|---|
| 93 |
return str(s)[0].lower() == 't' |
|---|
| 94 |
|
|---|
| 95 |
def typecast_decimal(s): |
|---|
| 96 |
if s is None or s == '': |
|---|
| 97 |
return None |
|---|
| 98 |
return decimal.Decimal(s) |
|---|
| 99 |
|
|---|
| 100 |
############################################### |
|---|
| 101 |
# Converters from Python to database (string) # |
|---|
| 102 |
############################################### |
|---|
| 103 |
|
|---|
| 104 |
def rev_typecast_boolean(obj, d): |
|---|
| 105 |
return obj and '1' or '0' |
|---|
| 106 |
|
|---|
| 107 |
def rev_typecast_decimal(d): |
|---|
| 108 |
if d is None: |
|---|
| 109 |
return None |
|---|
| 110 |
return str(d) |
|---|
| 111 |
|
|---|
| 112 |
def truncate_name(name, length=None): |
|---|
| 113 |
"""Shortens a string to a repeatable mangled version with the given length. |
|---|
| 114 |
""" |
|---|
| 115 |
if length is None or len(name) <= length: |
|---|
| 116 |
return name |
|---|
| 117 |
|
|---|
| 118 |
hash = md5_constructor(name).hexdigest()[:4] |
|---|
| 119 |
|
|---|
| 120 |
return '%s%s' % (name[:length-4], hash) |
|---|
| 121 |
|
|---|
| 122 |
def format_number(value, max_digits, decimal_places): |
|---|
| 123 |
""" |
|---|
| 124 |
Formats a number into a string with the requisite number of digits and |
|---|
| 125 |
decimal places. |
|---|
| 126 |
""" |
|---|
| 127 |
if isinstance(value, decimal.Decimal): |
|---|
| 128 |
context = decimal.getcontext().copy() |
|---|
| 129 |
context.prec = max_digits |
|---|
| 130 |
return u'%s' % str(value.quantize(decimal.Decimal(".1") ** decimal_places, context=context)) |
|---|
| 131 |
else: |
|---|
| 132 |
return u"%.*f" % (decimal_places, value) |
|---|