Package Gnumed :: Package timelinelib :: Package features :: Package experimental :: Module experimentalfeatures |
[frames] | no frames]

# Source Code for Module Gnumed.timelinelib.features.experimental.experimentalfeatures

      1  # Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018  Rickard Lindberg, Roger Lindberg
      2  #
      3  # This file is part of Timeline.
      4  #
      5  # Timeline is free software: you can redistribute it and/or modify
      6  # it under the terms of the GNU General Public License as published by
      7  # the Free Software Foundation, either version 3 of the License, or
      8  # (at your option) any later version.
      9  #
     10  # Timeline is distributed in the hope that it will be useful,
     11  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  # GNU General Public License for more details.
     14  #
     15  # You should have received a copy of the GNU General Public License
     16  # along with Timeline.  If not, see <http://www.gnu.org/licenses/>.
     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
     50 -class ExperimentalFeatureException(Exception):
     51      pass
     52
     53
     54 -class ExperimentalFeatures(object):
     55
     56 -    def __str__(self):
     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
     68 -    def get_all_features(self):
     69          return FEATURES
     70
     71 -    def set_active_state_on_all_features_from_config_string(self, cfg_string):
     72          for item in cfg_string.split(";"):
     73              if "=" in item:
     74                  name, value = item.split("=")
     75                  self.set_active_state_on_feature_by_name(name.strip(), value.strip() == "True")
     76
     77 -    def set_active_state_on_feature_by_index(self, feature_index, value):
     78          FEATURES[feature_index].set_active(value)
     79
     80 -    def set_active_state_on_feature_by_name(self, name, value):
     81          for feature in FEATURES:
     82              if isinstance(name, str):
     83                  name = name.decode("utf-8")
     84              if feature.get_config_name() == name:
     85                  feature.set_active(value)
     86                  return
     87              elif feature.get_display_name() == name:
     88                  feature.set_active(value)
     89                  return
     90
     91
     92 -def experimental_feature(feature):
     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