4
import maskedarray as ma
5
import timeseries as ts
6
from timeseries import const as _c
12
'FameDb', 'set_option', 'license_expires', 'DBError'
16
return dict([(y, x) for x, y in d.iteritems()])
18
basis_map = { HBSUND:_c.FR_UND,
21
basis_revmap = reverse_dict(basis_map)
23
observed_map = { HOBUND:ts.check_observed("UNDEFINED"),
24
HOBBEG:ts.check_observed("BEGINNING"),
25
HOBEND:ts.check_observed("ENDING"),
26
HOBAVG:ts.check_observed("AVERAGED"),
27
HOBSUM:ts.check_observed("SUMMED"),
28
HOBANN:"ANNUALIZED", #ts.check_observed("ANNUALIZED"),
29
HOBFRM:"FORMULA", #ts.check_observed("FORMULA"),
30
HOBHI:ts.check_observed("MAXIMUM"),
31
HOBLO:ts.check_observed("MINIMUM")}
32
observed_revmap = reverse_dict(observed_map)
33
observed_revmap['HIGH'] = HOBHI
34
observed_revmap['LOW'] = HOBLO
36
def translate_basis(basis):
37
"translate user specified basis to FAME constant"
39
if isinstance(basis, str):
40
freq = ts.check_freq(basis)
42
return basis_revmap[freq]
44
raise ValueError("Basis must be " + \
45
"'DAILY', 'BUSINESS', or 'UNDEFINED'")
47
if basis in basis_map: return basis
48
elif basis == _c.FR_DAY: return HBSDAY
49
elif basis == _c.FR_BUS: return HBSBUS
50
elif basis == _c.FR_UND: return HBSUND
52
raise ValueError("Invalid Basis value")
54
def translate_observed(observed):
55
"translate user specified observed to FAME constant"
56
if isinstance(observed, str):
57
return observed_revmap[ts.check_observed(observed)]
58
elif observed in (observed_map):
61
raise ValueError("Invalid Observed value")
63
freq_map = { HDAILY:_c.FR_DAY,
92
freq_revmap = reverse_dict(freq_map)
93
freq_revmap[_c.FR_QTR] = HQTDEC
95
date_value_adjust = { _c.FR_ANNJAN:1849,
122
def fametype_fromdata(data):
123
"""determine fame type code from a data object"""
125
if isinstance(data, ts.DateArray) or isinstance(data, ts.Date):
126
return freq_revmap[data.freq]
127
elif hasattr(data, 'dtype'):
128
dtypeStr = str(data.dtype)
130
if dtypeStr[:5] == "float":
131
if int(dtypeStr[5:]) > 32: return HPRECN
133
elif dtypeStr[:3] == "int":
134
if int(dtypeStr[3:]) > 32: return HPRECN
136
elif dtypeStr[:4] == "uint":
137
if int(dtypeStr[4:]) >= 32: return HPRECN
139
elif dtypeStr[:2] == "|S" or dtypeStr == 'object':
141
elif dtypeStr == "bool":
144
raise ValueError("Unsupported dtype for fame database: %s", dtypeStr)
146
elif isinstance(data, str):
148
elif isinstance(data, (int, float)):
150
elif isinstance(data, bool):
152
elif isinstance(data, list):
155
raise ValueError("Unrecognized data type")
157
def fametype_tonumpy(fametype):
161
elif fametype == HNAMEL:
165
HNUMRC:numpy.float32,
167
HSTRNG:numpy.object_,
168
HPRECN:numpy.float64}
169
return typeMap[fametype]
171
class CaseInsensitiveDict(dict):
172
def __init__(self, data={}):
173
for i, v in data.iteritems():
176
def __getitem__(self, key):
177
if hasattr(key, 'upper'): key = key.upper()
178
return super(CaseInsensitiveDict, self).__getitem__(key)
180
def __setitem__(self, key, item):
181
if hasattr(key, 'upper'): key = key.upper()
182
super(CaseInsensitiveDict, self).__setitem__(key, item)
184
def _famedate_to_tsdate(fame_date, freq):
185
"convert integer fame date to a timeseries Date"
186
value = fame_date + date_value_adjust[freq]
187
return ts.Date(freq=freq, value=value)
190
def _fame_params_from_pyobj_scalar(pyobj):
194
'type':fametype_fromdata(pyobj),
198
def _fame_params_from_pyobj_tser(pyobj):
200
if hasattr(pyobj, "observed"):
201
fame_observed = observed_revmap[pyobj.observed]
202
if fame_observed == 0: fame_observed = HOBEND
204
fame_observed = HOBEND
208
'freq':freq_revmap[pyobj.freq],
209
'type':fametype_fromdata(pyobj._data),
211
'observed':fame_observed}
213
def _fame_params_from_pyobj_cser(pyobj):
214
if hasattr(pyobj, "_data"):
215
fame_data = pyobj._data
222
'type':fametype_fromdata(fame_data),
227
class DBError(Exception): pass
229
class FameDb(object):
230
"""Fame database object.
233
x = FameDb(conn_str, mode='r')
236
- `conn_str` (str) : valid connection string. Can be a physical path,
237
or channel specification, etc. See FAME documentation on cfmopdb for
238
valid connection strings.
239
- `mode` (str, *['r']*) : method of access to the database. Can be one
250
- For changes to be posted, you must explictly use the "post" or
251
"close" methods (changes are posted on close)."""
253
def __init__(self, conn_str, mode='r'):
270
raise ValueError, "Database access mode not supported."
273
self.dbkey = cf_open(conn_str, intmode)
277
start_date=None, end_date=None,
278
start_case=None, end_case=None, max_string_len=65):
280
"""read specified object(s) from database
283
- `name` (string or list of strings) : names of objects that will be
284
read from the database
286
- `start_date` (int, *[None]*) : Applies only when reading time series.
287
If specified, only data points on or after `start_date` will be read.
288
If None, data will be read from the first value of the series.
289
- `end_date` (int, *[None]*) : Applies only when reading time series.
290
If specified, only data points on or before `end_date` will be read.
291
If None, data will be read to the last value of the series.
292
- `start_case` (int, *[None]*) : Applies only when reading case series.
293
If specified, only data points on or after `start_case` will be read.
294
If None, data will be read starting from case index 1
295
- `end_case` (int, *[None]*) : Applies only when reading case series.
296
If specified, only data points on or before `end_case` will be read.
297
If None, data will be read to the last value of the series.
298
- `max_string_len` (int, *[65]*) : Applies only when readings strings
299
or series of strings. This is the maximum length of string that can
300
be read. Lower values result in less memory usage, so you should
301
specify this as low as is reasonable for your data.
304
if `name` is a list of strings:
305
case insensitive dictionary of the objects
306
if `name` is a single string:
307
object from database that is stored as `name`"""
310
if isinstance(name, str):
316
items = CaseInsensitiveDict()
318
#default to -1. This will get the entire range
319
_start_case = _end_case = -1
320
_start_date = _end_date = -1
323
if start_date is not None:
324
_start_date = start_date.value - date_value_adjust[start_date.freq]
325
range_freq = freq_revmap[start_date.freq]
327
if end_date is not None:
328
if start_date is not None and start_date.freq != end_date.freq:
329
raise ValueError("start_date and end_date must be same frequency")
330
_end_date = end_date.value - date_value_adjust[end_date.freq]
331
if range_freq is None:
332
range_freq = freq_revmap[end_date.freq]
334
if start_case is not None: _start_case = start_case
335
if end_case is not None: _end_case = end_case
337
if len(set([_start_case, _end_case, _start_date, _end_date, -1])) != 1:
342
for objName in names:
343
objName = objName.upper()
346
objFreq = self.obj_size(objName)['freq']
348
if objFreq == range_freq:
349
start_index, end_index = _start_date, _end_date
350
elif objFreq == HCASEX:
351
start_index, end_index = _start_case, _end_case
353
start_index, end_index = -1, -1
355
start_index, end_index = -1, -1
357
result = cf_read(self.dbkey, objName, start_index,
358
end_index, max_string_len)
360
if result['type'] == HBOOLN:
361
numpyType = numpy.bool_
363
numpyType = fametype_tonumpy(result['type'])
365
if result['type'] == HNAMEL:
366
pyObj = [x for x in result['data'][1:-1].split(", ") \
369
elif result['class'] == HSCALA:
370
if isinstance(result['data'], str):
374
pyObj = result['data']
376
if result['mask'][0]:
379
pyObj = result['data'][0]
380
if result['type'] >= 8: # date type
382
date_value_adjust[freq_map[result['type']]]
384
freq=freq_map[result['type']],
387
pyObj = numpyType(pyObj)
389
elif result['class'] == HSERIE:
392
vals = result['data']
393
mask = result['mask']
394
if not mask.any(): mask = ma.nomask
399
if result['type'] >= 8: # date type
400
valadj = date_value_adjust[freq_map[result['type']]]
401
if len(vals) > 0: vals += valadj
402
data = ts.DateArray(vals,
403
freq=freq_map[result['type']])
405
data = numpy.array(vals, dtype=numpyType)
407
if result['freq'] == HCASEX:
408
pyObj = ma.array(data, mask=mask)
410
observed = observed_map[result['observed']]
411
freq = freq_map[result['freq']]
414
start_date = ts.Date(
416
value=result['startindex']+date_value_adjust[freq])
420
pyObj = ts.time_series(data, freq=freq,
421
start_date=start_date,
422
observed=observed, mask=mask)
424
items[objName] = pyObj
427
return items.values()[0]
430
#..............................................................................
431
def write_dict(self, objdict,
432
overwrite=False, assume_exists=False,
433
start_date=None, end_date=None,
434
zero_represents=1, start_case=None, end_case=None):
435
"""for each key, value pair in the dictionary `objdict` write value to
436
the database as key, as appropriate type (calls FameDb.write on
437
each key, value pair)
440
- `objdict` (dict) : dictionary of objects to be written. Object names
441
for keys and objects to be written for values
442
- `overwrite` (boolean, *[False]*) : See documentation for write_tser and
444
- `assume_exists` (boolean, *[False]*) : See documentation for write_tser
446
- `start_date` (Date, *[None]*) : See documentation for write_tser
447
- `end_date` (Date, *[None]*) : See documentation for write_tser
448
- `zero_represents` (int, *[1]*) : See documentation for write_cser
449
- `start_case` (int, *[None]*) : See documentation for write_cser
450
- `end_case` (int, *[None]*) : See documentation for write_cser
452
for key, obj in objdict.iteritems():
454
overwrite=overwrite, assume_exists=assume_exists,
455
start_date=start_date, end_date=end_date,
456
zero_represents=zero_represents,
457
start_case=start_case, end_case=end_case)
458
#..............................................................................
459
def write_tser_dict(self, objdict,
460
overwrite=False, assume_exists=False,
461
start_date=None, end_date=None):
462
"""for each key, value pair in the dictionary `objdict` write value to
463
the database as key, as a time series (calls FameDb.write_tser on each key,
467
- `objdict` (dict) : dictionary of TimeSeries objects to be written. Object
468
names for keys and TimeSeries objects for values
469
- `overwrite` (boolean, *[False]*) : See documentation for write_tser
470
- `assume_exists` (boolean, *[False]*) : See documentation for write_tser
471
- `start_date` (Date, *[None]*) : See documentation for write_tser
472
- `end_date` (Date, *[None]*) : See documentation for write_tser
474
for key, obj in objdict.iteritems():
475
self.write_tser(key, obj, overwrite=overwrite,
476
assume_exists=assume_exists,
477
start_date=start_date, end_date=end_date)
478
#..............................................................................
479
def write_cser_dict(self, objdict,
480
overwrite=False, assume_exists=False,
481
zero_represents=1, start_case=None, end_case=None):
482
"""for each key, value pair in the dictionary `objdict` write value to
483
the database as key, as a case series (calls FameDb.write_tser on each key,
487
- `objdict` (dict) : dictionary of arrays to be written as Case Series.
488
Object names for keys and arrays for values
489
- `overwrite` (boolean, *[False]*) : See documentation for write_cser
490
- `assume_exists` (boolean, *[False]*) : See documentation for write_cser
491
- `zero_represents` (int, *[1]*) : See documentation for write_cser
492
- `start_case` (int, *[None]*) : See documentation for write_cser
493
- `end_case` (int, *[None]*) : See documentation for write_cser
495
for key, obj in objdict.iteritems():
496
self.write_cser(key, obj, overwrite=overwrite,
497
assume_exists=assume_exists,
498
zero_represents=zero_represents,
499
start_case=start_case, end_case=end_case)
500
#..............................................................................
501
def write_scalar_dict(self, objdict):
502
"""for each key, value pair in the dictionary `objdict` write value to
503
the database as key, as a scalar (calls FameDb.write_scalar on each key,
507
- `objdict` (dict) : dictionary of items to be written as scalars.
508
Object names for keys and scalar items for values
510
for key, obj in objdict.iteritems():
511
self.write_scalar(key, obj)
512
#..............................................................................
513
def write(self, name, pyobj,
514
overwrite=False, assume_exists=False,
515
start_date=None, end_date=None,
516
zero_represents=1, start_case=None, end_case=None):
517
"""wrapper for write_tser, write_cser, and write_scalar which chooses
518
appropriate method by inspecting `pyobj`
521
- `name` (string) : database key that the object will be written to
522
- `pyobj` (object) : any valid object that can be written by write_scalar,
523
write_tser, or write_cser
524
- `overwrite` (boolean, *[False]*) : See documentation for write_tser and
526
- `assume_exists` (boolean, *[False]*) : See documentation for write_tser
528
- `start_date` (Date, *[None]*) : See documentation for write_tser
529
- `end_date` (Date, *[None]*) : See documentation for write_tser
530
- `zero_represents` (int, *[1]*) : See documentation for write_cser
531
- `start_case` (int, *[None]*) : See documentation for write_cser
532
- `end_case` (int, *[None]*) : See documentation for write_cser
534
if isinstance(pyobj, ts.TimeSeries):
535
self.write_tser(name, pyobj, overwrite=overwrite,
536
assume_exists=assume_exists,
537
start_date=start_date, end_date=end_date)
538
elif isinstance(pyobj, numpy.ndarray) and pyobj.ndim == 1:
539
self.write_cser(name, pyobj, overwrite=overwrite,
540
assume_exists=assume_exists,
541
zero_represents=zero_represents,
542
start_case=start_case, end_case=end_case)
544
self.write_scalar(name, pyobj)
545
#..............................................................................
546
def write_tser(self, name, tser,
547
overwrite=False, assume_exists=False,
548
start_date=None, end_date=None):
549
"""write `tser` to the database as `name` as a time series.
552
- `name` (string) : database key that the object will be written to
553
- `tser` (TimeSeries) : TimeSeries object to be written. Cannot have missing dates.
554
Use fill_missing_dates first on your series if you suspect this is the situation.
555
TimeSeries must be 1-dimensional
556
- `overwrite (boolean, *[False]*) : If True, if `name` exists in the database it
557
will be overwritten. If False, data will be added to series that already exist
558
(data in `tser` will be given priority over pre-existing data in the db where
560
- `assume_exists` (boolean, *[False]*) : If True, an error will be
561
raised if the series does not exist. If False, the series will be
562
created if it does not exist already.
563
- `start_date` (Date, *[None]*) : If None, data will be written from the start of
564
`tser`. If specified, only data points on or after start_date will be written.
565
- `end_date` (Date, *[None]*) : If None, data will be written until the end of
566
`tser`. If specified, only data points on or before end_date will be written.
569
if not isinstance(tser, ts.TimeSeries):
570
raise ValueError("tser is not a valid time series")
571
elif tser.has_missing_dates():
572
raise ValueError("tser must not have any missing dates")
574
raise ValueError("FAME db only supports 1-dimensional time series")
576
exists = self.obj_exists(name)
578
if assume_exists and not exists:
579
raise DBError("%s does not exist" % name)
581
if overwrite or not exists: create = True
584
fame_params = _fame_params_from_pyobj_tser(tser)
586
fame_cls = fame_params['cls']
587
fame_type = fame_params['type']
588
fame_freq = fame_params['freq']
589
fame_basis = fame_params['basis']
590
fame_observed = fame_params['observed']
593
if exists: self.delete_obj(name)
594
cf_create(self.dbkey, name, fame_cls, fame_freq, fame_type, fame_basis, fame_observed)
596
def get_boundary_date(bdate, attr):
597
if bdate is not None:
598
if bdate.freq != tser.freq:
599
raise ValueError(attr+" frequency must be same as tser frequency")
600
if tser.start_date > bdate or tser.end_date < bdate:
601
raise ValueError(attr+" outside range of series")
604
return getattr(tser, attr)
606
start_date = get_boundary_date(start_date, "start_date")
607
end_date = get_boundary_date(end_date, "end_date")
609
if start_date is not None:
611
towrite = tser[start_date:end_date+1]
613
start_index = start_date.value
614
end_index = end_date.value
616
# convert integer types to floats since FAME does not have an integer type
617
newType = fametype_tonumpy(fame_type)
620
fame_data = towrite._data - date_value_adjust[towrite._data.freq]
621
elif newType != tser._data.dtype:
622
fame_data = towrite._data.astype(newType)
624
fame_data = towrite._data
626
if towrite._mask is ma.nomask:
627
fame_mask = numpy.zeros(towrite._data.shape, dtype=numpy.bool_)
629
fame_mask = towrite._mask
631
start_index -= date_value_adjust[towrite.freq]
632
end_index -= date_value_adjust[towrite.freq]
634
cfame.write_series(self.dbkey, name, fame_data, fame_mask, start_index, end_index, fame_type, fame_freq)
635
#..............................................................................
636
def write_cser(self, name, cser,
637
overwrite=False, assume_exists=False,
638
zero_represents=1, start_case=None, end_case=None):
639
"""write `cser` to the database as `name` as a case series.
642
- `name` (string) : database key that the object will be written to
643
- `cser` (ndarray) : 1-dimensional ndarray (or subclass of ndarray) object to be
644
written. If `cser` is a MaskedArray, then masked values will be written as ND.
645
- `overwrite (boolean, *[False]*) : If True, if `name` exists in the database it
646
will be overwritten. If False, data will be added to series that already exist
647
(data in `cser` will be given priority over pre-existing data in the db where
649
- `assume_exists` (boolean, *[False]*) : If True, an error will be
650
raised if the series does not exist. If False, the series will be
651
created if it does not exist already.
652
- `zero_represents` (int, *[1]*) : the case index for FAME that index zero in
654
- `start_case` (int, *[None]*) : If None, data will be written from the start of
655
`cser`. If specified, only data points on or after start_case will be written.
656
- `end_case` (int, *[None]*) : If None, data will be written until the end of
657
`cser`. If specified, only data points on or before end_case will be written.
660
if not isinstance(cser, numpy.ndarray):
661
raise ValueError("cser is not a valid ndarray")
663
raise ValueError("FAME db only supports 1-dimensional arrays")
665
exists = self.obj_exists(name)
666
if assume_exists and not exists:
667
raise DBError("%s does not exist" % name)
669
if overwrite or not exists: create = True
672
fame_params = _fame_params_from_pyobj_cser(cser)
674
fame_cls = fame_params['cls']
675
fame_type = fame_params['type']
676
fame_freq = fame_params['freq']
677
fame_basis = fame_params['basis']
678
fame_observed = fame_params['observed']
680
if hasattr(cser, "_data"):
681
fame_data = cser._data
682
if cser._mask is ma.nomask:
683
fame_mask = numpy.zeros(fame_data.shape, dtype=numpy.bool_)
685
fame_mask = cser._mask
688
fame_mask = numpy.zeros(fame_data.shape, dtype=numpy.bool_)
691
if exists: self.delete_obj(name)
692
cf_create(self.dbkey, name, fame_cls, fame_freq, fame_type, fame_basis, fame_observed)
694
def get_boundary_case(bcase, attr):
695
if bcase is not None:
696
idx = bcase - zero_represents
697
if idx < 0 or idx > cser.size:
698
raise ValueError("%s outside range of series" % attr)
704
if attr == 'start_case':
705
return zero_represents
706
elif attr == 'end_case':
707
return zero_represents + cser.size - 1
709
raise ValueError("unexpected argument: %s " % attr)
711
start_case = get_boundary_case(start_case, "start_case")
712
end_case = get_boundary_case(end_case, "end_case")
714
if start_case is not None:
715
# convert integer types to floats since FAME does not have an integer type
716
s = start_case - zero_represents
717
e = end_case - zero_represents
719
fame_data = fame_data[s:e+1]
720
fame_mask = fame_mask[s:e+1]
721
newType = fametype_tonumpy(fame_type)
724
fame_data = fame_data - date_value_adjust[fame_data.freq]
725
elif newType != fame_data.dtype:
726
fame_data = fame_data.astype(newType)
728
cfame.write_series(self.dbkey, name, fame_data, fame_mask, start_case, end_case, fame_type, fame_freq)
729
#..............................................................................
730
def write_scalar(self, name, scalar):
731
"""write `scalar` to the database as `name` as a scalar object. If an
732
object already exists in the database named as `name` then it is
733
over-written, otherwise it is created.
736
- `name` (string) : database key that the object will be written to
737
- `scalar` : one of the following: string, numpy scalar, int, float,
738
list of strings (for name lists), Date, boolean"""
740
fame_params = _fame_params_from_pyobj_scalar(scalar)
741
fame_type = fame_params['type']
743
if isinstance(scalar, ts.Date):
744
fame_data = numpy.int32(scalar.value - date_value_adjust[scalar.freq])
745
elif hasattr(scalar, "dtype"):
746
if scalar.ndim != 0: raise ValueError("received non-scalar data")
747
newType = fametype_tonumpy(fame_type)
748
if newType != scalar.dtype: fame_data = scalar.astype(newType)
749
else: fame_data = scalar
750
elif fame_type == HSTRNG:
752
elif fame_type == HPRECN:
753
fame_data = numpy.float64(scalar)
754
elif fame_type == HBOOLN:
755
fame_data = numpy.int32(scalar)
756
elif fame_type == HNAMEL:
757
fame_data = "{" + ", ".join(scalar) + "}"
759
raise ValueError("Unrecognized data type")
761
if self.obj_exists(name): self.delete_obj(name)
762
cf_create(self.dbkey, name,
766
fame_params['basis'],
767
fame_params['observed'])
769
# convert integer types to floats since FAME does not have an integer type
770
newType = fametype_tonumpy(fame_type)
771
if hasattr(fame_data, 'dtype') and newType != fame_data.dtype:
772
fame_data = fame_data.astype(newType)
774
if fame_type == HNAMEL:
775
cf_write_namelist(self.dbkey, name, fame_data)
777
cf_write_scalar(self.dbkey, name, fame_data, fame_type)
778
#..............................................................................
779
def delete_obj(self, name, must_exist=True):
780
"""Deletes the specified object(s) from the database
783
- `name` (string of list of strings) : name of object(s) to delete from
785
- `must_exist` (boolean, *[True]*) : If True, an error will be raised if
786
you try to delete an object that does not exists. If False, deletion
787
will only be attempted for objects that actually exist, and other
788
entries will be ignored.
790
if isinstance(name, str): name = [name]
791
[cf_delete_obj(self.dbkey, n) for n in name if must_exist or self.obj_exists(n)]
793
def _create_obj(self, name, cls, type, freq=None, basis=None, observed=None):
794
"""create object in database with specified attributes as `name`.
796
You must use the fame constants defined in mapping.py for each of the
797
parameters. Generally speaking, it is easier to use initialize_obj
798
with a prototype object.
801
if cls not in (HSERIE, HSCALA):
802
raise ValueError("unrecognized object class: "+str(cls))
808
raise ValueError("freq must be specified for series")
810
if freq in (HUNDFX, HCASEX):
814
if basis is None: basis = HBSDAY
815
if observed is None: observed = HOBEND
817
cf_create(self.dbkey, name, cls, freq, type, basis, observed)
819
def initialize_obj(self, name, pyobj):
820
"""initialize object of appropriate type in database based on the
821
python object `pyobj` as `name`. Does not write any data to the
822
database, simply initializes the object in the database."""
823
if isinstance(pyobj, ts.TimeSeries):
824
param_func = _fame_params_from_pyobj_tser
825
elif isinstance(pyobj, numpy.ndarray):
826
param_func = _fame_params_from_pyobj_cser
828
param_func = _fame_params_from_pyobj_scalar
830
fame_params = param_func(pyobj)
831
cf_create(self.dbkey, name,
835
fame_params['basis'],
836
fame_params['observed'])
838
def rename_obj(self, name, new_name):
839
"""rename fame object in database"""
840
cf_rename_obj(self.dbkey, name, new_name)
842
def copy_obj(self, target_db, source_name, target_name=None):
843
"""copy fame object to another destination"""
844
if target_name is None: target_name = source_name
845
cf_copy(self.dbkey, target_db.dbkey, source_name, target_name)
846
#..............................................................................
847
def set_obj_desc(self, name, desc):
848
"set 'description' attribute of object in database"
849
cf_set_obj_desc(self.dbkey, name, desc)
851
def set_obj_doc(self, name, doc):
852
"set 'documentation' attribute of object in database"
853
cf_set_obj_doc(self.dbkey, name, doc)
855
def set_obj_basis(self, name, basis):
856
"set 'basis' attribute of object in database"
857
basis = translate_basis(basis)
858
cf_set_obj_basis(self.dbkey, name, basis)
860
def set_obj_observed(self, name, observed):
861
"set 'observed' attribute of object in database"
862
observed = translate_observed(observed)
863
cf_set_obj_observed(self.dbkey, name, observed)
864
#..............................................................................
865
def _whats(self, name):
866
"""Preforms a fame "whats" command on the provided name
868
Note: Returns FAME constants which are not directly interpretable
869
in the context of the timeseries module. For this reason, it is
870
recommended that you use the obj_* methods to retrieve the desired
871
information about an object.
873
return cf_whats(self.dbkey, name)
875
def __ser_date(self, name, date_type):
876
"""helper method for start_date and end_date"""
877
obj_sz = self.obj_size(name)
878
fame_freq = obj_sz['freq']
879
if fame_freq == 0: return None
882
ts_freq = freq_map[obj_sz['freq']]
884
raise DBError("unsupported FAME frequency: %i", fame_freq)
886
if obj_sz[date_type+'_year'] == -1: return None
888
annDate = ts.Date(freq='A', year=obj_sz[date_type+'_year'])
889
return annDate.asfreq(ts_freq, relation='BEFORE') + (obj_sz[date_type+'_period'] - 1)
891
def obj_size(self, name):
892
"""basic information about the size of an object in a database"""
893
return cf_obj_size(self.dbkey, name)
895
def obj_desc(self, name):
896
"""get desc attribute for an object"""
897
return self._whats(name)['desc']
899
def obj_doc(self, name):
900
"""get doc attribute for an object"""
901
return self._whats(name)['doc']
903
def obj_exists(self, name):
904
return cf_exists(self.dbkey, name)
906
def obj_freq(self, name):
907
"""get frequency of a FAME time series object in the database"""
908
obj_sz = self.obj_size(name)
909
fame_freq = obj_sz['freq']
910
if fame_freq == 0: return None
911
return freq_map[obj_sz['freq']]
913
def obj_basis(self, name):
914
"""get basis attribute of a FAME time series object in the database"""
915
return self._whats(name)['basis']
917
def obj_observed(self, name):
918
"""get observed attribute of a FAME time series object in the database"""
919
return observed_map[self._whats(name)['observ']]
921
def obj_start_date(self, name):
922
"""get start_date of a FAME time series object"""
923
return self.__ser_date(name, 'start')
925
def obj_end_date(self, name):
926
"""get end_date of a FAME time series object"""
927
return self.__ser_date(name, 'end')
929
def obj_created(self, name):
930
"get 'created' attribute of object in database"
931
fame_date = cf_get_obj_attr(self.dbkey, name, "CREATED")
932
return _famedate_to_tsdate(fame_date, _c.FR_SEC)
934
def obj_modified(self, name):
935
"get 'modified' attribute of object in database"
936
fame_date = cf_get_obj_attr(self.dbkey, name, "MODIFIED")
937
return _famedate_to_tsdate(fame_date, _c.FR_SEC)
938
#..............................................................................
940
"get 'description' attribute of database"
941
return cf_get_db_attr(self.dbkey, "DESC")
944
"get 'doc' attribute of database"
945
return cf_get_db_attr(self.dbkey, "DOC")
947
def db_created(self):
948
"get 'created' attribute of database"
949
fame_date = cf_get_db_attr(self.dbkey, "CREATED")
950
return _famedate_to_tsdate(fame_date, _c.FR_SEC)
952
def db_modified(self):
953
"get 'modified' attribute of database"
954
fame_date = cf_get_db_attr(self.dbkey, "MODIFIED")
955
return _famedate_to_tsdate(fame_date, _c.FR_SEC)
957
def db_is_open(self):
958
"returns True if database is open. False otherwise"
959
return cf_get_db_attr(self.dbkey, "ISOPEN")
961
def set_db_desc(self, desc):
962
"set description attribute of database"
963
cf_set_db_desc(self.dbkey, desc)
965
def set_db_doc(self, doc):
966
"set doc attribute of database"
967
cf_set_db_doc(self.dbkey, doc)
968
#..............................................................................
969
def wildlist(self, exp, wildonly=False):
970
"""performs a wildlist lookup on the database, using Fame syntax
971
("?" and "^"), returns a normal python list of strings"""
972
res = cf_wildlist(self.dbkey, exp)
975
exp = exp.replace("?", "(.*)")
976
exp = exp.replace("^", "(.)")
977
exp = exp.replace("$","\$")
978
regex = re.compile(exp)
979
res = ["".join(regex.match(res[i]).groups()) \
980
for i in range(len(res))]
982
#..............................................................................
984
"""Closes the database. Changes will be posted."""
985
if self.db_is_open():
992
"""Discard any changes made to the database since it was last opened or posted."""
993
cf_restore(self.dbkey)
997
"""wrapper for cfame functions that acquires and releases a resource lock.
998
This is needed because the Fame C api is not thread safe."""
1000
fameLock = thread.allocate_lock()
1002
def __init__ (self, func):
1004
self.__doc__ = getattr(func, "__doc__", str(func))
1005
self.__name__ = getattr(func, "__name__", str(func))
1007
def __call__ (self, *args, **kwargs):
1008
"Execute the call behavior."
1009
tmp = self.fameLock.acquire()
1011
result = self.f(*args, **kwargs)
1012
self.fameLock.release()
1014
self.fameLock.release()
1019
cf_open = cFameCall(cfame.open)
1020
cf_set_option = cFameCall(cfame.set_option)
1021
cf_close = cFameCall(cfame.close)
1022
cf_post = cFameCall(cfame.post)
1023
cf_restore = cFameCall(cfame.restore)
1024
cf_obj_size = cFameCall(cfame.obj_size)
1025
cf_whats = cFameCall(cfame.whats)
1026
cf_delete_obj = cFameCall(cfame.delete_obj)
1027
cf_create = cFameCall(cfame.create)
1028
cf_read = cFameCall(cfame.read)
1029
cf_write_scalar = cFameCall(cfame.write_scalar)
1030
cf_write_series = cFameCall(cfame.write_series)
1031
cf_write_namelist = cFameCall(cfame.write_namelist)
1032
cf_wildlist = cFameCall(cfame.wildlist)
1033
cf_exists = cFameCall(cfame.exists)
1034
cf_get_db_attr = cFameCall(cfame.get_db_attr)
1035
cf_get_obj_attr = cFameCall(cfame.get_obj_attr)
1036
cf_copy = cFameCall(cfame.copy)
1037
cf_rename_obj = cFameCall(cfame.rename_obj)
1038
cf_license_expires = cFameCall(cfame.license_expires)
1039
cf_set_db_desc = cFameCall(cfame.set_db_desc)
1040
cf_set_db_doc = cFameCall(cfame.set_db_doc)
1041
cf_set_obj_desc = cFameCall(cfame.set_obj_desc)
1042
cf_set_obj_doc = cFameCall(cfame.set_obj_doc)
1043
cf_set_obj_basis = cFameCall(cfame.set_obj_basis)
1044
cf_set_obj_observed = cFameCall(cfame.set_obj_observed)
1047
set_option = cf_set_option
1048
set_option.__doc__ = \
1049
"""Set an option in the C HLI. See the FAME documentation for cfmsopt for a
1050
listing of allowable option settings.
1053
- option (str) : name of the option to set
1054
- setting (str) : value of the option to set
1057
set_option("DBSIZE", "LARGE")
1060
def license_expires():
1061
"""get date that license expires on"""
1062
fame_date = cf_license_expires()
1063
adj_val = date_value_adjust[_c.FR_DAY]
1064
return ts.Date(freq=_c.FR_DAY, value=fame_date+adj_val)