1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """
20 ExperimentalFeatures is responsible for reading and storing experimental features
21 configuration, to and from the configuration file.
22 It also holds a list of available experimental features.
23 All experimental features are instantiated when this file is loaded.
24
25 To add a new experimental feature, do as follows:
26 - Create a new file in timelinelib.features.experimental, defining a class
27 that inherits from ExperimentalFeature and calls the parent __init__()-
28 function with the two arguments DISPLAY_NAME and DESCRIPTION.
29 - Instantiate the new experimental feature class in this file like...
30 NAME = NewExperimentalFeatureClass()
31 - Add the instantiated object to the FEATURES list in this file.
32 - Implement the feature logic under the condition...
33 if NAME.enabled():
34 - If new methods are created that only are used by the new feature,
35 decorate these functions with @experimental_feature(NAME)
36 """
37
38
39 from timelinelib.features.experimental.experimentalfeaturecontainersize import ExperimentalFeatureContainerSize
40 from timelinelib.features.experimental.experimentalfeaturenegativejuliandays import ExperimentalFeatureNegativeJulianDays
41 from timelinelib.features.experimental.experimentalfeatureextendedcontainerstrategy import ExperimentalFeatureExtendedContainerStrategy
42
43
44 EXTENDED_CONTAINER_HEIGHT = ExperimentalFeatureContainerSize()
45 NEGATIVE_JULIAN_DAYS = ExperimentalFeatureNegativeJulianDays()
46 EXTENDED_CONTAINER_STRATEGY = ExperimentalFeatureExtendedContainerStrategy()
47 FEATURES = (EXTENDED_CONTAINER_HEIGHT, NEGATIVE_JULIAN_DAYS, EXTENDED_CONTAINER_STRATEGY)
48
49
52
53
55
57 """
58 Formats the configuration string for all experimental features,
59 which is a semicolon separated list of feature configurations.
60 features-configuration ::= (feature-configuration ';')*
61 feature-configuration ::= feature-name '=' ('True'|'False')
62 """
63 collector = []
64 for feature in FEATURES:
65 collector.append(feature.get_config())
66 return "".join(collector)
67
70
76
79
90
91
93 """
94 The syntax for decorators with arguments is a bit different - the decorator
95 with arguments should return a function that will take a function and return
96 another function. So it should really return a normal decorator.
97
98 Decorator used for methods, only used by an Experimental feature.
99 The purpose of the decorator is to simplify removal of the feature
100 code if it is decided not to implement the feature.
101 Example:
102 @experimental_feature(EVENT_DONE)
103 def foo()
104 pass
105 """
106 def deco(foo):
107 if feature not in FEATURES:
108 raise ExperimentalFeatureException("Feature '%s', not implemented" % feature.get_display_name())
109 return foo
110 return deco
111