1#!/usr/bin/env python3
2
3"""Implement the get_constant accessor function for reading algorithm constants.
4The actual constants are stored in settings.CONSTANTS_MODULE (alg/constants.py).
5"""
6
7import runpy
8
9from chart.project import settings
10from chart.common.decorators import memoized_noargs
11
12
13@memoized_noargs
14def all_constants():
15 return runpy.run_path(settings.CONSTANTS_FILE)['data']
16
17
18def get_constant(name, sid=None, scid=None, sensing_time=None):
19 """Retrieve constant `name`.
20 If `scid` is specified and the constant has different values for different
21 scid, return the correct value.
22 If `time` is specified and the constant has different values for different time
23 ranges, retrieve the value for `time` (not implemented).
24 """
25 constants = all_constants()
26
27 if sid is not None:
28 scid = sid.scid
29
30 if name not in constants:
31 raise ValueError('Constant {name} not found'.format(name=name))
32
33 if 'value' in constants[name]:
34 if 'values' in constants[name]:
35 raise ValueError('Constant {name} has both value and values set'.format(name=name))
36
37 return constants[name]['value']
38
39 if 'values' not in constants[name]:
40 raise ValueError('Constant {name} has neither value nor values set'.format(name=name))
41
42 potentials = constants[name]['values']
43
44 for potential in reversed(potentials):
45 if 'value' not in potential:
46 raise ValueError('Value missing for constant {name}'.format(name=name))
47
48 if 'scid' in potential and potential['scid'] != scid:
49 continue
50
51 if 'sensing_start' in potential and sensing_time is None:
52 raise ValueError('Cannot retrieve constant {name} without specifying time'.format(
53 name=name))
54
55 if 'sensing_start' in potential and sensing_time < potential['sensing_start']:
56 continue
57
58 return potential['value']
59
60 raise ValueError('Cannot find suitable constant {name} time {time} scid {scid}'.format(
61 name=name, time=sensing_time, scid=scid))
62
63
64def get_constant_description(name):
65 """Retrieve the description for constant `name`."""
66 constant = all_constants()[name]
67 return constant.get('description')
68
69
70class Constant:
71# class Constant(int):
72 """Define constants inside algorithm code.
73
74 Initial implementation of a replacement to the original Constants mechanism, which
75 is unwealdy because it's hard to convert ordinary code to constant-using code, and because
76 the old code split the values into different files."""
77
78 def __init__(self, value, description=None):
79 self._value = value
80 self.description = description
81
82 # def __new__(cls, value, description=None):
83 # if isinstance(value, int):
84 # return int.__new__(cls, value)
85
86 # elif isinstance(value, dict):
87 # pass
88
89 def hello(self):
90 return 'Hello {h}'.format(h=self)
91
92 def value(self, sid=None, sensing_time=None):
93 return self._value