Skip to content

Commit ffc0ced

Browse files
author
quantmind
committed
improved coverage by 1%, whoa! added reduce lua script for reducing timeseries into shorter series. Fixed bug in session with multiple queries to delete
1 parent 740268e commit ffc0ced

File tree

19 files changed

+199
-268
lines changed

19 files changed

+199
-268
lines changed

.coveragerc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
[run]
22
source = stdnet
3-
omit = stdnet/utils/fallbacks/*,stdnet/test/*,stdnet/contrib/searchengine/tests/*,stdnet/contrib/timeseries/tests/*,stdnet/contrib/tasks/tests/*
3+
omit = stdnet/utils/fallbacks/*

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ build/*
1010
.settings/*
1111
docs/build/*
1212
.coverage
13+
htmlcov/*
1314
.project
1415
.pydevproject
1516
MANIFEST

CHANGELOG.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Ver. 0.7.0 - Development
3939
using python 2.6.
4040
* Moved the contrib module to :mod:`stdnet.apps`.
4141
* Added :mod:`stdnet.utils.dates`.
42-
* **482 regression tests** with **80%** coverage.
42+
* **482 regression tests** with **82%** coverage.
4343

4444
.. _vers06:
4545

examples/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class SimpleModel(orm.StdModel):
1616
description = orm.CharField()
1717
somebytes = orm.ByteField()
1818
object = orm.PickleObjectField(required = False)
19+
cached_data = orm.ByteField(as_cache = True)
1920

2021
objects = CustomManager()
2122

stdnet/apps/columnts/lua/reduce.lua

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
local command = ARGV[1]
2+
local start = ARGV[2]
3+
local stop = ARGV[3]
4+
local points = math.max(ARGV[4] + 0, 2)
5+
local method = ARGV[5] -- One of 'mean', 'geometric', 'ma'
6+
local alpha = ARGV[6] + 0 -- paramether for moving avaerage reduction
7+
local num_fields = ARGV[7]
8+
local fields = table_slice(ARGV, 8, -1)
9+
local ts = columnts:new(KEYS[1])
10+
local time,values = unpack(ts:range(command, start, stop, fields))
11+
local N = # times
12+
if N < points then
13+
return {times,values}
14+
else
15+
local space = math.floor(N/points) -- spacing for reduction
16+
while N/space > points do
17+
space = space + 1
18+
end
19+
local rtime, reduced = {}, {}
20+
for field,value do
21+
local index, stop, fvalues = 1, 0, {}
22+
table.insert(reduced,field)
23+
table.insert(reduced,fvalues)
24+
while stop <= N do
25+
start = stop + 1
26+
stop = N - (points-index)*space
27+
rtime[index] = time[stop]
28+
if method == 'mean' then
29+
fvalues[index] = reduce_mean(value,start,stop)
30+
elseif method == 'geometric' then
31+
fvalues[index] = reduce_geo(value,start,stop)
32+
elseif method == 'ma' then
33+
fvalues[index] = reduce_ma(value,start,stop,alpha)
34+
else
35+
fvalues[index] = value[stop]
36+
end
37+
index = index + 1
38+
end
39+
end
40+
return {rtime, reduced}
41+
end
42+
43+

stdnet/backends/base.py

Lines changed: 17 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,6 @@
2525
session_result = namedtuple('session_result','meta results')
2626

2727

28-
def intid(id):
29-
try:
30-
return int(id)
31-
except ValueError:
32-
return id
33-
34-
3528
class BackendRequest(object):
3629
'''Signature class for Stdnet Request classes'''
3730
pass
@@ -42,7 +35,7 @@ class AsyncObject(UnicodeMixin):
4235
is :meth:`async_handle`. Avery time there is a result from the server,
4336
this method should be called.'''
4437
def async_handle(self, result, callback, *args, **kwargs):
45-
if isinstance(result,BackendRequest):
38+
if isinstance(result, BackendRequest):
4639
return result.add_callback(lambda res :\
4740
self.async_callback(callback, res, *args, **kwargs))
4841
else:
@@ -53,18 +46,7 @@ def async_callback(self, callback, result, *args, **kwargs):
5346
raise result
5447
else:
5548
return callback(result, *args, **kwargs)
56-
57-
58-
class Keys(object):
59-
60-
def __init__(self,id,timeout,pipeline):
61-
self.timeout = timeout
62-
self.value = None
63-
pipeline[id] = self
64-
65-
def add(self, value):
66-
self.value = value
67-
49+
6850

6951
class ServerOperation(object):
7052

@@ -187,19 +169,19 @@ def execute_query(self):
187169

188170
# VIRTUAL FUNCTIONS
189171

190-
def _has(self, val):
191-
raise NotImplementedError
172+
def _has(self, val): # pragma: no cover
173+
raise NotImplementedError()
192174

193-
def _items(self, slic):
194-
raise NotImplementedError
175+
def _items(self, slic): # pragma: no cover
176+
raise NotImplementedError()
195177

196-
def _build(self, **kwargs):
197-
raise NotImplementedError
178+
def _build(self, **kwargs): # pragma: no cover
179+
raise NotImplementedError()
198180

199-
def _execute_query(self):
181+
def _execute_query(self): # pragma: no cover
200182
'''Execute the query without fetching data from server. Must
201183
be implemented by data-server backends.'''
202-
raise NotImplementedError
184+
raise NotImplementedError()
203185

204186

205187
class BackendDataServer(object):
@@ -326,32 +308,32 @@ def basekey(self, meta, *args):
326308

327309
# PURE VIRTUAL METHODS
328310

329-
def setup_connection(self, address, **params):
311+
def setup_connection(self, address, **params): # pragma: no cover
330312
'''Callback during initialization. Implementation should override
331313
this function for customizing their handling of connection parameters. It
332314
must return a instance of the backend handler.'''
333315
raise NotImplementedError()
334316

335-
def execute_session(self, session, callback):
317+
def execute_session(self, session, callback): # pragma: no cover
336318
'''Execute a :class:`stdnet.orm.Session` in the backend server.'''
337319
raise NotImplementedError()
338320

339-
def model_keys(self, meta):
321+
def model_keys(self, meta): # pragma: no cover
340322
'''Return a list of database keys used by model *model*'''
341323
raise NotImplementedError()
342324

343-
def instance_keys(self, obj):
325+
def instance_keys(self, obj): # pragma: no cover
344326
'''Return a list of database keys used by instance *obj*'''
345327
raise NotImplementedError()
346328

347-
def as_cache(self):
329+
def as_cache(self): # pragma: no cover
348330
raise NotImplementedError('This backend cannot be used as cache')
349331

350-
def clear(self):
332+
def clear(self): # pragma: no cover
351333
"""Remove *all* values from the database at once."""
352334
raise NotImplementedError()
353335

354-
def flush(self, meta = None, pattern = None):
336+
def flush(self, meta = None, pattern = None): # pragma: no cover
355337
raise NotImplementedError()
356338

357339

stdnet/lib/redis/scripts.py

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010

1111
__all__ = ['RedisScript',
12-
'ScriptBuilder',
1312
'pairs_to_dict',
1413
'get_script',
1514
'registered_scripts',
@@ -240,33 +239,6 @@ def __call__(self, key, *args):
240239
return self.builder
241240

242241

243-
class ScriptBuilder(object):
244-
245-
def __init__(self, redis):
246-
self.redis = redis
247-
self.script = None
248-
self.lines = []
249-
250-
def __getattr__(self, name):
251-
return ScriptCommand(self, name)
252-
253-
def append(self, line):
254-
if self.script:
255-
raise ValueError('Script has been executed already. Run clear')
256-
self.lines.append(line)
257-
258-
def clear(self):
259-
self.script = None
260-
self.lines = []
261-
262-
def execute(self):
263-
if self.lines:
264-
lines = self.lines
265-
lines.append('return res')
266-
self.script = '\n'.join(lines)
267-
return self.redis.eval(self.script)
268-
269-
270242
class countpattern(RedisScript):
271243
script = '''\
272244
return table.getn(redis.call('keys',KEYS[1]))

stdnet/orm/base.py

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -35,22 +35,40 @@ def get_fields(bases, attrs):
3535
return fields
3636

3737

38+
def make_app_label(new_class, app_label = None):
39+
if app_label is None:
40+
model_module = sys.modules[new_class.__module__]
41+
try:
42+
bits = model_module.__name__.split('.')
43+
if bits[0] == 'stdnet' and bits[1] == 'orm':
44+
bits = bits[-1:]
45+
else:
46+
bits = bits[-2:]
47+
if bits[-1] == 'models':
48+
bits.pop()
49+
app_label = '.'.join(bits)
50+
except:
51+
app_label = ''
52+
return app_label
53+
54+
3855
class ModelMeta(object):
3956
'''A class for storing meta data of a :class:`Model` class.'''
4057
def __init__(self, model, app_label = None, modelkey = None,
4158
abstract = False):
4259
self.abstract = abstract
4360
self.model = model
4461
self.model._meta = self
45-
self.app_label = app_label
62+
self.app_label = make_app_label(model, app_label)
4663
self.name = model.__name__.lower()
4764
if not modelkey:
4865
if self.app_label:
4966
modelkey = '{0}.{1}'.format(self.app_label,self.name)
5067
else:
5168
modelkey = self.name
5269
self.modelkey = modelkey
53-
hashmodel(model)
70+
if not abstract:
71+
hashmodel(model)
5472

5573
def pkname(self):
5674
return 'id'
@@ -230,18 +248,6 @@ def is_valid(self, instance):
230248
data[name] = svalue
231249

232250
return len(errors) == 0
233-
234-
def flush(self):
235-
'''Fast method for clearing the whole table including related tables'''
236-
N = 0
237-
for rel in self.related.values():
238-
rmeta = rel._meta
239-
# This avoid circular reference
240-
if rmeta is not self:
241-
N += rmeta.flush()
242-
if self.cursor:
243-
N += self.cursor.flush(self)
244-
return N
245251

246252
def get_sorting(self, sortby, errorClass = None):
247253
s = None
@@ -269,7 +275,7 @@ def get_sorting(self, sortby, errorClass = None):
269275
It is not a scalar field.'.format(sortby))
270276

271277
def backend_fields(self, fields):
272-
'''Return a tuple containing a list
278+
'''Return a two elements tuple containing a list
273279
of fields names and a list of field attribute names.'''
274280
dfields = self.dfields
275281
processed = set()
@@ -313,35 +319,27 @@ def __new__(cls, name, bases, attrs):
313319

314320
@classmethod
315321
def make(cls, name, bases, attrs, meta):
316-
model = type.__new__(cls, name, bases, attrs)
317-
meta = ModelMeta(model)
318-
return model
322+
new_class = type.__new__(cls, name, bases, attrs)
323+
ModelMeta(new_class)
324+
return new_class
319325

320326

321327
class StdNetType(ModelType):
322328
is_base_class = True
323329
@classmethod
324330
def make(cls, name, bases, attrs, meta):
325331
if meta:
326-
kwargs = meta_options(**meta.__dict__)
332+
kwargs = meta_options(**meta.__dict__)
327333
else:
328-
kwargs = meta_options()
334+
kwargs = meta_options()
329335

330336
# remove and build field list
331-
fields = get_fields(bases, attrs)
337+
fields = get_fields(bases, attrs)
332338
# create the new class
333339
new_class = type.__new__(cls, name, bases, attrs)
334340
setup_managers(new_class)
335341
app_label = kwargs.pop('app_label')
336-
337-
if app_label is None:
338-
model_module = sys.modules[new_class.__module__]
339-
try:
340-
app_label = model_module.__name__.split('.')[-2]
341-
except:
342-
app_label = ''
343-
344-
meta = Metaclass(new_class,fields,app_label=app_label,**kwargs)
342+
Metaclass(new_class, fields, app_label=app_label, **kwargs)
345343
signals.class_prepared.send(sender=new_class)
346344
return new_class
347345

0 commit comments

Comments
 (0)