36 def __init__(self, ref="", **kwargs): |
38 def __init__(self, ref="", **kwargs): |
37 if len(utils.dottedref.split_ref(ref)) > 1: |
39 if len(utils.dottedref.split_ref(ref)) > 1: |
38 raise exceptions.InvalidRef("Invalid reference for Base object %s!" % ref) |
40 raise exceptions.InvalidRef("Invalid reference for Base object %s!" % ref) |
39 self.ref = ref |
41 self.ref = ref |
40 container.ObjectContainer.__init__(self, ref) |
42 container.ObjectContainer.__init__(self, ref) |
41 for arg in kwargs.keys(): |
43 try: |
42 if kwargs.get(arg) != None: |
44 for arg in kwargs.keys(): |
43 setattr(self, arg, kwargs.get(arg)) |
45 if kwargs.get(arg) != None: |
44 |
46 setattr(self, arg, kwargs.get(arg)) |
|
47 except AttributeError,e: |
|
48 raise e |
|
49 |
45 def __repr__(self): |
50 def __repr__(self): |
46 dict = self._dict() |
51 dict = self._dict() |
47 return "%s(%s)" % (self.__class__.__name__, dict) |
52 return "%s(%s)" % (self.__class__.__name__, dict) |
48 |
53 |
|
54 # def __reduce_ex__(self, protocol_version): |
|
55 # tpl = super(Base, self).__reduce_ex__(protocol_version) |
|
56 # return tpl |
|
57 |
|
58 # def __getstate__(self): |
|
59 # state = self._dict(internals=True, ignore_empty=True) |
|
60 # # pop out the _name so that it wont appear as redundant data (ref is the same) |
|
61 # state.pop('_name', None) |
|
62 # state.pop('_parent', None) |
|
63 # return state |
|
64 # |
|
65 # def __setstate__(self, state): |
|
66 # super(Base, self).__setstate__(state) |
|
67 # self.ref = state.get('ref','') |
|
68 # for arg in state.keys(): |
|
69 # self.__dict__.setdefault(arg, state.get(arg)) |
|
70 |
49 def _get_mapper(self,modelname): |
71 def _get_mapper(self,modelname): |
50 """ |
72 """ |
51 Return a instance of appropriate mapper for given model. |
73 Return a instance of appropriate mapper for given model. |
52 """ |
74 """ |
53 return mapping.BaseMapper() |
75 return mapping.BaseMapper() |
443 @param path: path to configuration |
541 @param path: path to configuration |
444 @return: Boolean return value. |
542 @return: Boolean return value. |
445 """ |
543 """ |
446 # Changed from list_all_configurations to list_configurations |
544 # Changed from list_all_configurations to list_configurations |
447 # (list_all_configurations causes a insane performance problem with _traverse) |
545 # (list_all_configurations causes a insane performance problem with _traverse) |
448 return path in self.list_configurations() |
546 # |
449 |
547 try: |
450 def add_configuration(self, config): |
548 return self.storage.is_resource(path) |
|
549 except exceptions.NotSupportedException: |
|
550 return path in self.list_configurations() |
|
551 |
|
552 def add_configuration(self, config, overwrite_existing=False): |
451 """ |
553 """ |
452 Add a Configuration object to this project |
554 Add a Configuration object to this project |
453 """ |
555 @param config: The configuration object to add |
|
556 @param overwrite_existing: When this is set true any existing configuration is |
|
557 overwritten. |
|
558 """ |
454 if isinstance(config, Configuration): |
559 if isinstance(config, Configuration): |
455 if self.is_configuration(config.get_path()): |
560 if not overwrite_existing and self.is_configuration(config.get_path()): |
456 raise exceptions.AlreadyExists("%s" % config.get_path()) |
561 raise exceptions.AlreadyExists("%s" % config.get_path()) |
457 self._add(config) |
562 |
|
563 proxy = ConfigurationProxy(config.path) |
|
564 proxy._set_obj(config) |
|
565 self._add(proxy) |
|
566 #self._add(config) |
458 self.__add_loaded__(config.get_path(), config) |
567 self.__add_loaded__(config.get_path(), config) |
459 self.__loaded__(config.get_path()) |
568 self.__loaded__(config.get_path()) |
460 else: |
569 else: |
461 raise exceptions.IncorrectClassError("Only Configuration instance can be added to Project!") |
570 raise exceptions.IncorrectClassError("Only Configuration instance can be added to Project!") |
462 |
571 |
463 def create_configuration(self, path, namespace=""): |
572 def create_configuration(self, path, overwrite_existing=False, **kwargs): |
464 """ |
573 """ |
465 Create a Configuration object to this project |
574 Create a Configuration object to this project |
466 """ |
575 @param path: The path of the new configuration file |
467 config = self.get_configuration_class()(utils.resourceref.norm(path), namespace=namespace) |
576 @param overwrite_existing: When this is set true any existing configuration is |
468 self.add_configuration(config) |
577 overwritten. |
|
578 @param **kwargs: normal keyword arguments that are passed on to the newly |
|
579 created Configuration object. See Configuration object constructor description on what |
|
580 you can pass on here. |
|
581 """ |
|
582 config = self.get_configuration_class()(utils.resourceref.norm(path), **kwargs) |
|
583 self.add_configuration(config, overwrite_existing) |
469 return config |
584 return config |
470 |
585 |
471 def remove_configuration(self, path): |
586 def remove_configuration(self, path): |
472 """ |
587 """ |
473 Remove a Configuration by its reference |
588 Remove a Configuration by its reference |
576 # self.meta = {} |
701 # self.meta = {} |
577 # self.desc = "" |
702 # self.desc = "" |
578 super(CompositeConfiguration, self).__init__(ref, **kwargs) |
703 super(CompositeConfiguration, self).__init__(ref, **kwargs) |
579 self.container = True |
704 self.container = True |
580 |
705 |
|
706 def _configuration_class(self): |
|
707 return Configuration |
|
708 |
581 def add_configuration(self, config): |
709 def add_configuration(self, config): |
582 """ |
710 """ |
583 Add an existing Configuration to this configuration |
711 Add an existing Configuration to this configuration |
584 @param config: A Configuration instance: |
712 @param config: A Configuration instance: |
585 @return: None |
713 @return: None |
586 """ |
714 """ |
587 """ |
715 """ |
588 Merge the default view features from added config to this configs _default_view. |
716 Merge the default view features from added config to this configs _default_view. |
589 """ |
717 """ |
590 self._add(config) |
718 # if the Configuration has a separate resource path, add it automatically behind proxy |
591 |
719 if utils.resourceref.is_path(config.path) and isinstance(config, Configuration): |
592 def include_configuration(self, configref): |
720 proxy = ConfigurationProxy(config.path) |
|
721 proxy._set_obj(config) |
|
722 self._add(proxy) |
|
723 # Add the new configuration to the list of "modified/loaded" configurations |
|
724 try: |
|
725 prj = self.get_project() |
|
726 prj.__add_loaded__(config.get_full_path(), config) |
|
727 prj.__loaded__(config.get_full_path()) |
|
728 except exceptions.NotFound: |
|
729 # if the parent is not found this configuration is not (yet) a part of project and cant be stored |
|
730 pass |
|
731 else: |
|
732 self._add(config) |
|
733 |
|
734 def include_configuration(self, configref, policy=0): |
593 """ |
735 """ |
594 Add an existing Configuration to this configuration by its resource reference |
736 Add an existing Configuration to this configuration by its resource reference |
595 @param config: A Configuration instance: |
737 @param config: A Configuration instance: |
596 @return: None |
738 @return: None |
597 """ |
739 """ |
598 # add the configuration load proxy to this configuration instead |
740 # add the configuration load proxy to this configuration instead |
599 # adding the configuration directly |
741 # adding the configuration directly |
600 self._add(ConfigurationProxy(configref)) |
742 self._add(ConfigurationProxy(configref), policy) |
601 |
743 |
602 def create_configuration(self, path): |
744 def create_configuration(self, path): |
603 """ |
745 """ |
604 Create a new configuration by its name to the Configuration. |
746 Create a new configuration by its name to the Configuration. |
605 1. Create new Configuration object |
747 1. Create new Configuration object |
688 @raise IncorrectClassError: if the given class cannot be added to this object. |
815 @raise IncorrectClassError: if the given class cannot be added to this object. |
689 """ |
816 """ |
690 if isinstance(child, Configuration): |
817 if isinstance(child, Configuration): |
691 self.add_configuration(child) |
818 self.add_configuration(child) |
692 elif isinstance(child, ConfigurationProxy): |
819 elif isinstance(child, ConfigurationProxy): |
693 self.add_configuration(child) |
820 self._add(child) |
694 elif isinstance(child, Base): |
821 elif isinstance(child, Base): |
695 self._add(child) |
822 self._add(child) |
696 else: |
823 else: |
697 raise exceptions.IncorrectClassError("Cannot add %s to %s" % (child, self)) |
824 raise exceptions.IncorrectClassError("Cannot add %s to %s" % (child, self)) |
698 |
825 |
699 def layered_content(self, layers=None): |
826 def layered_resources(self, layers=None, empty_folders=False, folder=None, resource_type=None): |
700 """ |
827 """ |
701 fetch content from first to last and override content |
828 Fetch resource paths by layers so that if a resource with the same name |
702 if it is found from a later layer |
829 exists on multiple layers, the one on the latest layer is the active one. |
703 Create an array of the layers based on the layer indexes. |
830 @param layers: List of layer indices to specify the layer to use, None |
704 """ |
831 for all layers. |
|
832 @param empty_folders: If True, empty folders are returned also. |
|
833 @param folder: Name of a specific folder from which to get resources, or None. |
|
834 If None, resource_type must be specified. |
|
835 @param resource_type: Type of the resources to find. Must be one of |
|
836 ('confml', 'implml', 'content', 'doc') or None. |
|
837 If None, folder must be specified. |
|
838 @return: A container.DataContainer instance containing the resource paths. |
|
839 For example: {'foo.txt': ['layer1/content/foo.txt', |
|
840 'layer2/content/foo.txt'], |
|
841 'bar.txt': ['layer1/content/bar.txt']} |
|
842 """ |
|
843 MAPPING = {'confml': lambda layer: layer.confml_folder(), |
|
844 'implml': lambda layer: layer.implml_folder(), |
|
845 'content': lambda layer: layer.content_folder(), |
|
846 'doc': lambda layer: layer.doc_folder()} |
|
847 if resource_type is not None and resource_type not in MAPPING: |
|
848 raise ValueError("Invalid resource type %r, should be one of %r" % (resource_type, MAPPING.keys())) |
|
849 |
|
850 if folder and resource_type: |
|
851 raise ValueError('Only one of folder and resource_type must be specified!') |
|
852 if not folder and not resource_type: |
|
853 raise ValueError('Either folder or resource_type must be specified!') |
|
854 |
705 configuration_array = [] |
855 configuration_array = [] |
706 if layers == None: |
856 if layers == None: |
707 configuration_array = self.list_configurations() |
857 configuration_array = self.list_configurations() |
708 else: |
858 else: |
709 all = self.list_configurations() |
859 all = self.list_configurations() |
710 for i in layers: |
860 for i in layers: |
711 configuration_array.append(all[i]) |
861 configuration_array.append(all[i]) |
712 |
862 |
713 content = container.DataContainer() |
863 # Add the current configuration as the last one in the list, in case |
|
864 # the current configuration happens to be a layer root itself |
|
865 configuration_array.append('') |
|
866 |
|
867 # Set up the get_folder function based on the parameters |
|
868 if resource_type: |
|
869 get_folder = MAPPING[resource_type] |
|
870 else: |
|
871 def get_folder(layer): |
|
872 cpath = layer.get_current_path() |
|
873 return Folder(layer.storage, utils.resourceref.join_refs([cpath, folder])) |
|
874 |
|
875 result = container.DataContainer() |
714 for configuration_path in configuration_array: |
876 for configuration_path in configuration_array: |
715 content_folder = self.get_configuration(configuration_path).get_layer().content_folder() |
877 folder_obj = get_folder(self.get_configuration(configuration_path).get_layer()) |
716 content_path = content_folder.get_current_path() |
878 folder_path = folder_obj.get_current_path() |
717 for content_file in content_folder.list_resources("", True): |
879 for res_path in folder_obj.list_resources("", recurse=True, empty_folders=empty_folders): |
718 source_file = utils.resourceref.join_refs([content_path, content_file]) |
880 if res_path == '': continue # ZipStorage sometimes returns empty paths |
719 content.add_value(content_file, source_file) |
881 res_fullpath = utils.resourceref.join_refs([folder_path, res_path]) |
720 |
882 result.add_value(res_path, res_fullpath) |
721 return content |
883 return result |
722 |
884 |
723 |
885 def layered_confml(self, layers=None, empty_folders=False): |
|
886 return self.layered_resources(layers, empty_folders, resource_type='confml') |
|
887 |
|
888 def layered_implml(self, layers=None, empty_folders=False): |
|
889 return self.layered_resources(layers, empty_folders, resource_type='implml') |
|
890 |
|
891 def layered_content(self, layers=None, empty_folders=False): |
|
892 return self.layered_resources(layers, empty_folders, resource_type='content') |
|
893 |
|
894 def layered_doc(self, layers=None, empty_folders=False): |
|
895 return self.layered_resources(layers, empty_folders, resource_type='doc') |
|
896 |
|
897 |
|
898 |
724 class Configuration(CompositeConfiguration): |
899 class Configuration(CompositeConfiguration): |
725 """ |
900 """ |
726 A Configuration is a container that can hold several Layer objects. |
901 A Configuration is a container that can hold several Layer objects. |
727 """ |
902 """ |
728 |
903 |
729 def __init__(self, ref="", **kwargs): |
904 def __init__(self, ref="", **kwargs): |
730 self.path = kwargs.get('path') or ref |
905 self.path = kwargs.get('path') or ref |
731 self.namespace = kwargs.get('namespace', '') |
906 self.namespace = kwargs.get('namespace', '') |
732 self.name = utils.resourceref.to_objref(self.path) |
907 self.name = kwargs.get('name',utils.resourceref.to_objref(self.path)) |
733 super(Configuration, self).__init__(utils.resourceref.to_objref(self.path)) |
908 self.version = kwargs.get('version') |
|
909 super(Configuration, self).__init__(utils.resourceref.to_objref(self.path), **kwargs) |
734 self.container = True |
910 self.container = True |
735 |
911 |
|
912 def __reduce_ex__(self, protocol_version): |
|
913 """ |
|
914 Make the Configuration pickle a ConfigurationProxy object that would load this configuration |
|
915 """ |
|
916 proxy = ConfigurationProxy(self.path, store_interface = self.get_project()) |
|
917 tpl = proxy.__reduce_ex__(protocol_version) |
|
918 return tpl |
|
919 |
|
920 def __getstate__(self): |
|
921 return None |
|
922 |
736 def _default_object(self, name): |
923 def _default_object(self, name): |
737 return Feature(name) |
924 return self._default_class()(name) |
|
925 |
|
926 def _default_class(self): |
|
927 return self._feature_class() |
|
928 |
|
929 def _feature_class(self): |
|
930 return Feature |
|
931 |
|
932 def _view_class(self): |
|
933 return View |
738 |
934 |
739 def _supported_type(self, obj): |
935 def _supported_type(self, obj): |
740 if isinstance(obj, Configuration) \ |
936 if isinstance(obj, Configuration) \ |
741 or isinstance(obj, Feature) \ |
937 or isinstance(obj, Feature) \ |
742 or isinstance(obj, Data) \ |
938 or isinstance(obj, Data) \ |
781 def set_path(self, path): |
972 def set_path(self, path): |
782 """ |
973 """ |
783 Set the path of the configuration resource, and update the name and ref to correspond |
974 Set the path of the configuration resource, and update the name and ref to correspond |
784 """ |
975 """ |
785 self.path = path |
976 self.path = path |
786 #self.name = utils.resourceref.to_objref(self.path) |
|
787 self.set_ref(utils.resourceref.to_objref(self.path)) |
977 self.set_ref(utils.resourceref.to_objref(self.path)) |
788 |
978 |
789 #@property |
|
790 def get_full_path(self): |
979 def get_full_path(self): |
791 """ |
980 """ |
792 Return the path of the configuration resource |
981 Return the path of the configuration resource |
793 """ |
982 """ |
794 try: |
983 try: |
795 parentconfig = self._find_parent(type=Configuration) |
984 parentconfig = self._find_parent(type=Configuration) |
796 parent_path = utils.resourceref.get_path(parentconfig.get_path()) |
985 parent_path = utils.resourceref.get_path(parentconfig.get_path()) |
797 except exceptions.NotFound: |
986 except exceptions.NotFound: |
798 parent_path = "" |
987 parent_path = "" |
799 |
988 return utils.resourceref.join_refs([parent_path, self.path]) |
|
989 |
|
990 def get_path_for_parent(self, parent): |
|
991 """ |
|
992 Return the path to this configuration for a defined parent Configuration object. |
|
993 """ |
|
994 parent_path = "" |
|
995 try: |
|
996 parentconfig = self._find_parent(type=Configuration) |
|
997 if parent != parentconfig: |
|
998 parent_path = utils.resourceref.get_path(parentconfig.get_path_for_parent(parent)) |
|
999 except exceptions.NotFound: |
|
1000 pass |
800 return utils.resourceref.join_refs([parent_path, self.path]) |
1001 return utils.resourceref.join_refs([parent_path, self.path]) |
801 |
1002 |
802 def get_layer(self): |
1003 def get_layer(self): |
803 """ |
1004 """ |
804 Get the layer object where this Configuration is located. |
1005 Get the layer object where this Configuration is located. |
889 @param ref: The reference to the feature object. |
1089 @param ref: The reference to the feature object. |
890 @return: A Feature object |
1090 @return: A Feature object |
891 """ |
1091 """ |
892 return self._get(ref) |
1092 return self._get(ref) |
893 |
1093 |
|
1094 def create_feature(self, ref, **kwargs): |
|
1095 """ |
|
1096 Create a feature object to the configuration. |
|
1097 @param ref: The ref for the Feature object. |
|
1098 @param **kwargs: keyword arguments |
|
1099 e.g. to add fea2 under fea1 add_feature(fea2, 'fea1') |
|
1100 @return: the new feature object. |
|
1101 """ |
|
1102 fea = self._feature_class()(ref, **kwargs) |
|
1103 self._add(fea) |
|
1104 return fea |
|
1105 |
894 def add_feature(self, feature, namespace=""): |
1106 def add_feature(self, feature, namespace=""): |
895 """ |
1107 """ |
896 Add a feature object to the configuration. |
1108 Add a feature object to the configuration. |
897 @param feature: The Feature object to add. |
1109 @param feature: The Feature object to add. |
898 @param namespace: The sub namespace for the feature. |
1110 @param namespace: The sub namespace for the feature. |
899 e.g. to add fea2 under fea1 add_feature(fea2, 'fea1') |
1111 e.g. to add fea2 under fea1 add_feature(fea2, 'fea1') |
900 @return: None |
1112 @return: None |
901 """ |
1113 """ |
902 self._add_to_path(namespace, feature) |
1114 if namespace and self._has(namespace): |
|
1115 # Add the feature directly with an existing feature's add_feature functionality |
|
1116 self.get_feature(namespace).add_feature(feature) |
|
1117 else: |
|
1118 self._add_to_path(namespace, feature) |
903 |
1119 |
904 def remove_feature(self, ref): |
1120 def remove_feature(self, ref): |
905 """ |
1121 """ |
906 remove feature by its reference |
1122 remove feature by its reference |
907 @param ref: |
1123 @param ref: |
925 return [fea.fqr for fea in self._traverse(type=Feature)] |
1141 return [fea.fqr for fea in self._traverse(type=Feature)] |
926 |
1142 |
927 def add_data(self, data, policy=container.REPLACE): |
1143 def add_data(self, data, policy=container.REPLACE): |
928 """ |
1144 """ |
929 Add a data object to this configuration object. |
1145 Add a data object to this configuration object. |
930 @param data: The Data object to add. |
1146 @param data: The Data object or list of Data objects to add. |
931 @return: None |
1147 @return: None |
932 """ |
1148 """ |
933 if not self._has(data.attr): |
1149 data_objs = utils.get_list(data) |
934 self._add(DataContainer(data.attr, container=True)) |
1150 |
935 (namespace, name) = utils.dottedref.psplit_ref(data.get_fearef()) |
1151 if policy == container.PREPEND: |
936 self._get(data.attr)._add_to_path(namespace, data, policy) |
1152 data_objs = reversed(data_objs) |
|
1153 policy_first = container.PREPEND |
|
1154 policy_rest = container.PREPEND |
|
1155 else: |
|
1156 policy_first = policy |
|
1157 policy_rest = container.APPEND |
|
1158 |
|
1159 for i, data_obj in enumerate(data_objs): |
|
1160 if not self._has(data_obj.attr): |
|
1161 self._add(DataContainer(data_obj.attr, container=True)) |
|
1162 (namespace, name) = utils.dottedref.psplit_ref(data_obj.get_fearef()) |
|
1163 |
|
1164 if i == 0: p = policy_first |
|
1165 else: p = policy_rest |
|
1166 self._get(data_obj.attr)._add_to_path(namespace, data_obj, p) |
937 |
1167 |
938 def get_data(self, ref): |
1168 def get_data(self, ref): |
939 """ |
1169 """ |
940 Get a data object by its reference. |
1170 Get a data object by its reference. |
941 @param ref: The reference to the data object. |
1171 @param ref: The reference to the data object. |
1099 raise e |
1343 raise e |
1100 # raise exceptions.NotFound("Default View is not found! No root configuration?") |
1344 # raise exceptions.NotFound("Default View is not found! No root configuration?") |
1101 |
1345 |
1102 def _create_default_view(self): |
1346 def _create_default_view(self): |
1103 # Rebuild the default view for this Configuration |
1347 # Rebuild the default view for this Configuration |
1104 self._default_view = View("_default_view", data=True) |
1348 default_view = View("?default_view", data=True) |
1105 self._default_view._parent= self |
1349 #self._default_view._parent= self |
|
1350 self._add(default_view) |
1106 # First add all features of the configuration to the view. |
1351 # First add all features of the configuration to the view. |
1107 # Then add all data elements under the features |
1352 # Then add all data elements under the features |
1108 for child in self._traverse(type=Feature): |
1353 for child in self._traverse(type=Feature): |
1109 self._default_view.add_feature(child, child.namespace) |
1354 # TODO print "Adding : %s -> %s" % (child.namespace, child) |
|
1355 default_view.add_feature(child, child.namespace) |
1110 for child in self._traverse(type=Data): |
1356 for child in self._traverse(type=Data): |
1111 #parent_config = child._find_parent_or_default(type=Configuration) |
1357 #parent_config = child._find_parent_or_default(type=Configuration) |
1112 #print "Adding data %s: fqr: %s from file %s." % (child.get_value(), child.fqr, parent_config.get_path()) |
1358 #print "Adding data %s: fqr: %s from file %s." % (child.get_value(), child.fqr, parent_config.get_path()) |
1113 try: |
1359 try: |
1114 fea = self._default_view.get_feature(child.fqr) |
1360 fea = default_view.get_feature(child.fqr) |
1115 fea.add_data(child) |
1361 fea.add_data(child) |
1116 except exceptions.NotFound, e: |
1362 except exceptions.NotFound, e: |
1117 data_parent_config = child._find_parent_or_default(type=Configuration) |
1363 data_parent_config = child._find_parent_or_default(type=Configuration) |
1118 logging.getLogger('cone').info("Warning: Feature '%s' for data in %s not found." % (child.fqr, data_parent_config.get_path())) |
1364 logging.getLogger('cone').info("Warning: Feature '%s' for data in %s not found." % (child.fqr, data_parent_config.get_path())) |
1119 |
1365 |
1175 """ |
1427 """ |
1176 A Group class. Group is used in View to group up other Group/Feature objects. |
1428 A Group class. Group is used in View to group up other Group/Feature objects. |
1177 """ |
1429 """ |
1178 def __init__(self, ref="", **kwargs): |
1430 def __init__(self, ref="", **kwargs): |
1179 super(Group, self).__init__(ref, **kwargs) |
1431 super(Group, self).__init__(ref, **kwargs) |
1180 self.name = ref |
1432 self.name = kwargs.get('name', ref) |
1181 self.support_data = kwargs.get("data", False) |
1433 self.support_data = kwargs.get("data", False) |
1182 |
1434 |
1183 def _supported_type(self, obj): |
1435 def _supported_type(self, obj): |
1184 if isinstance(obj, (Group, \ |
1436 if isinstance(obj, (Group, \ |
1185 Base, \ |
1437 Base, \ |
1186 _FeatureProxy, \ |
1438 _FeatureProxy, \ |
1187 FeatureLink)): |
1439 FeatureLink, \ |
|
1440 ConfigurationProxy)): |
1188 return True |
1441 return True |
1189 else: |
1442 else: |
1190 return False |
1443 return False |
1191 |
1444 |
1192 def _default_object(self, name): |
1445 def _default_object(self, name): |
1193 return Group(name) |
1446 return self._group_class()(name) |
1194 |
1447 |
1195 def get_name(self): |
1448 def _group_class(self): |
1196 """ |
1449 return Group |
1197 Return the name of the configuration |
1450 |
1198 """ |
1451 def _featurelink_class(self): |
1199 return self.name |
1452 return FeatureLink |
1200 |
|
1201 def set_name(self, name): |
|
1202 """ |
|
1203 Set the name |
|
1204 """ |
|
1205 self.name |
|
1206 |
1453 |
1207 def add(self, child, policy=container.REPLACE): |
1454 def add(self, child, policy=container.REPLACE): |
1208 """ |
1455 """ |
1209 A generic add function to add child objects. The function is intended to act as |
1456 A generic add function to add child objects. The function is intended to act as |
1210 proxy function that call the correct add function based on the child objects class. |
1457 proxy function that call the correct add function based on the child objects class. |
1211 |
1458 |
1212 Example: obj.add(Feature("test")), actually obj.add_feature(Feature("test")) |
1459 Example: obj.add(Feature("test")), actually obj.add_feature(Feature("test")) |
1213 @param child: the child object to add |
1460 @param child: the child object to add |
1214 @raise IncorrectClassError: if the given class cannot be added to this object. |
1461 @raise IncorrectClassError: if the given class cannot be added to this object. |
1215 """ |
1462 """ |
1216 if isinstance(child, (Group, \ |
1463 if self._supported_type(child): |
1217 Base, \ |
|
1218 _FeatureProxy, \ |
|
1219 FeatureLink)): |
|
1220 self._add(child) |
1464 self._add(child) |
1221 else: |
1465 else: |
1222 raise exceptions.IncorrectClassError("Cannot add %s to %s" % (child, self)) |
1466 raise exceptions.IncorrectClassError("Cannot add %s to %s" % (child, self)) |
1223 |
1467 |
1224 def get_name(self): |
1468 def get_name(self): |
1258 try: |
1517 try: |
1259 return self._get(ref) |
1518 return self._get(ref) |
1260 except exceptions.NotFound: |
1519 except exceptions.NotFound: |
1261 raise exceptions.NotFound("Feature '%s' not found." % ref) |
1520 raise exceptions.NotFound("Feature '%s' not found." % ref) |
1262 |
1521 |
1263 def get_features(self, ref, **kwargs): |
1522 def get_features(self, refs, **kwargs): |
1264 """ |
1523 """ |
1265 Get a list of features that match the ref. |
1524 Get a list of features that match the ref. |
|
1525 |
|
1526 @param refs: The paths (refs) to the given feature or xpath like expression. The refs |
|
1527 argument can be a single reference or a list of references to features. |
|
1528 @return: A list of features. |
|
1529 |
|
1530 NOTE! the invalid references will not raise an exception. |
|
1531 |
1266 Example1: get_features('foo.bar') would be the same as get_feature('foo.bar'), but this returns |
1532 Example1: get_features('foo.bar') would be the same as get_feature('foo.bar'), but this returns |
1267 always a list [<Feature>]. |
1533 always a list [<Feature>]. |
1268 Example2: get_features('foo.*') would try to retrieve a list of all foo children. |
1534 Example2: get_features('foo.*') would try to retrieve a list of all foo children. |
1269 Example3: get_features('foo.*', type='') would try to retrieve a list of all foo children, |
1535 Example3: get_features('foo.*', type='') would try to retrieve a list of all foo children, |
1270 that have a defined type. |
1536 that have a defined type. |
1271 @param path: The path (ref) to the given feature or xpath like expression |
1537 Example4: get_features(['foo','bar.set1']) would try to retrieve a foo and then bar.set1. |
|
1538 |
|
1539 """ |
|
1540 |
|
1541 if utils.is_list(refs): |
|
1542 features = [] |
|
1543 for ref in refs: |
|
1544 features += self.get_matching_features(ref, **kwargs) |
|
1545 return features |
|
1546 else: |
|
1547 return self.get_matching_features(refs, **kwargs) |
|
1548 |
|
1549 def get_matching_features(self, ref, **kwargs): |
|
1550 """ |
|
1551 Get a list of features that match the ref. |
|
1552 |
|
1553 @param refs: The paths (refs) to the given feature or xpath like expression. The refs |
|
1554 argument can be a single reference or a list of references to features. |
1272 @return: A list of features. |
1555 @return: A list of features. |
1273 """ |
1556 |
1274 (startref, last) = utils.dottedref.psplit_ref(ref) |
1557 NOTE! the invalid references will not raise an exception but return an empty list. |
1275 startelem = self._get(startref) |
1558 |
1276 if last == '**': |
1559 Example1: get_features('foo.bar') would be the same as get_feature('foo.bar'), but this returns |
1277 return [fea for fea in startelem._traverse(**kwargs)] |
1560 always a list [<Feature>]. |
1278 elif last == '*': |
1561 Example2: get_features('foo.*') would try to retrieve a list of all foo children. |
1279 return [fea for fea in startelem._objects(**kwargs)] |
1562 Example3: get_features('foo.*', type='') would try to retrieve a list of all foo children, |
1280 else: |
1563 that have a defined type. |
1281 return [self._get(ref)] |
1564 |
1282 |
1565 """ |
|
1566 try: |
|
1567 (startref, last) = utils.dottedref.psplit_ref(ref) |
|
1568 startelem = self._get(startref) |
|
1569 kwargs['type'] = _FeatureProxy |
|
1570 if last == '**': |
|
1571 return [fea for fea in startelem._traverse(**kwargs)] |
|
1572 elif last == '*': |
|
1573 return [fea for fea in startelem._objects(**kwargs)] |
|
1574 elif ref != "": |
|
1575 return [self._get(ref)] |
|
1576 else: |
|
1577 return [] |
|
1578 except exceptions.NotFound: |
|
1579 return [] |
|
1580 |
1283 def list_features(self): |
1581 def list_features(self): |
1284 """ |
1582 """ |
1285 Return a array of all Feature children references under this object. |
1583 Return a array of all Feature children references under this object. |
1286 """ |
1584 """ |
1287 return [fea.get_ref() for fea in self._objects(type=(_FeatureProxy))] |
1585 return [fea.get_ref() for fea in self._objects(type=(_FeatureProxy))] |
1399 def set_name(self, name): |
1723 def set_name(self, name): |
1400 """ |
1724 """ |
1401 Set the name |
1725 Set the name |
1402 """ |
1726 """ |
1403 self.name = name |
1727 self.name = name |
|
1728 |
|
1729 def get_relevant(self): |
|
1730 """ |
|
1731 Return the relevant attribute of the feature |
|
1732 """ |
|
1733 return self.relevant |
|
1734 |
|
1735 def set_relevant(self, relevant): |
|
1736 """ |
|
1737 Set the relevant attribute |
|
1738 """ |
|
1739 self.relevant = relevant |
|
1740 |
|
1741 def get_constraint(self): |
|
1742 """ |
|
1743 Return the constraint attribute of the feature |
|
1744 """ |
|
1745 return self.constraint |
|
1746 |
|
1747 def set_constraint(self, constraint): |
|
1748 """ |
|
1749 Set the constraint attribute |
|
1750 """ |
|
1751 self.constraint = constraint |
1404 |
1752 |
1405 def get_type(self): |
1753 def get_type(self): |
1406 return self.type |
1754 return self.type |
1407 |
1755 |
1408 def set_type(self, type): |
1756 def set_type(self, type): |
1409 self.type = type |
1757 self.type = type |
1410 |
1758 |
|
1759 def create_feature(self, ref, **kwargs): |
|
1760 """ |
|
1761 Create a feature object to the configuration. |
|
1762 @param ref: The ref for the Feature object. |
|
1763 @param **kwargs: keyword arguments |
|
1764 e.g. to add fea2 under fea1 add_feature(fea2, 'fea1') |
|
1765 @return: the new feature object. |
|
1766 """ |
|
1767 fea = self._feature_class()(ref, **kwargs) |
|
1768 self.add_feature(fea) |
|
1769 return fea |
|
1770 |
1411 def add_feature(self, feature, path=""): |
1771 def add_feature(self, feature, path=""): |
1412 """ |
1772 """ |
1413 @param feature: The Feature object to add |
1773 @param feature: The Feature object to add |
1414 """ |
1774 """ |
1415 configuration = self.find_parent(type=Configuration) |
1775 self._add_to_path(path, feature) |
1416 if configuration: |
|
1417 feapath = utils.dottedref.join_refs([self._path(configuration), path]) |
|
1418 configuration.add_feature(feature, feapath) |
|
1419 else: |
|
1420 self._add_to_path(path, feature) |
|
1421 |
1776 |
1422 def get_feature(self, path): |
1777 def get_feature(self, path): |
1423 """ |
1778 """ |
1424 @param path: The path (ref) to the given feature |
1779 @param path: The path (ref) to the given feature |
1425 """ |
1780 """ |
1489 Return a array of all Option children references under this object. |
1839 Return a array of all Option children references under this object. |
1490 """ |
1840 """ |
1491 # Return option refs without the leading 'opt_' |
1841 # Return option refs without the leading 'opt_' |
1492 return [opt.ref[4:] for opt in self._objects(type=Option)] |
1842 return [opt.ref[4:] for opt in self._objects(type=Option)] |
1493 |
1843 |
|
1844 def add_property(self, property): |
|
1845 """ |
|
1846 @param property: property object to add |
|
1847 """ |
|
1848 if not isinstance(property, Property): |
|
1849 raise TypeError("%r is not an instance of Property!" % property) |
|
1850 self._add(property) |
|
1851 |
|
1852 def create_property(self, **kwargs): |
|
1853 """ |
|
1854 @param name=str: property name |
|
1855 @param value=str: property value |
|
1856 @param unit=str: property unit, e.g. kB |
|
1857 """ |
|
1858 self._add(Property(**kwargs)) |
|
1859 |
|
1860 |
|
1861 def get_property(self, ref): |
|
1862 """ |
|
1863 @param ref: The ref of the property |
|
1864 """ |
|
1865 obj = self._get(Property.to_propertyref(ref)) |
|
1866 |
|
1867 if not isinstance(obj, Property): |
|
1868 raise TypeError('Object %r is not an instance of Property (%r instead)' % (Property.to_propertyref(ref), type(obj))) |
|
1869 return obj |
|
1870 |
|
1871 def remove_property(self, ref): |
|
1872 """ |
|
1873 remove a given property from this feature by ref. |
|
1874 @param ref: |
|
1875 """ |
|
1876 obj = self._get(Property.to_propertyref(ref)) |
|
1877 if not isinstance(obj, Property): |
|
1878 raise TypeError('Trying to remove property with ref %r, but object with ref %r is not an instance of Property (%s instead)' % (ref, Property.to_propertyref(ref), type(obj))) |
|
1879 self._remove(Property.to_propertyref(ref)) |
|
1880 |
|
1881 def list_properties(self): |
|
1882 """ |
|
1883 Return a array of all Feature properties under this object. |
|
1884 """ |
|
1885 |
|
1886 return [Property.to_normref(property.ref) for property in self._objects(type=Property)] |
|
1887 |
1494 def get_value(self, attr=None): |
1888 def get_value(self, attr=None): |
1495 """ |
1889 """ |
1496 Get the current value of the feature |
1890 Get the current value of the feature. |
1497 @param attr: The attribute name of the data. E.g. attr='data', attr='rfs' |
1891 @param attr: The attribute name of the data. E.g. attr='data', attr='rfs' |
1498 """ |
1892 """ |
1499 # Do not allow getting of setting of sequence values directly with Feature object |
1893 return self.convert_data_to_value(self.dataproxy._get_datas(attr=attr), cast=True, attr=attr) |
1500 if not self.is_sequence(): |
|
1501 return self.get_value_cast(self.dataproxy._get_value(attr), attr) |
|
1502 else: |
|
1503 """ get the feature specific data from sequence => a column of data table """ |
|
1504 coldata = [] |
|
1505 feasequence = self.get_sequence_parent() |
|
1506 feapath = self._path(feasequence) |
|
1507 for row in feasequence.data: |
|
1508 feadata = row.get_feature(feapath) |
|
1509 coldata.append(feadata.value) |
|
1510 return coldata |
|
1511 |
1894 |
1512 def set_value(self, value, attr=None): |
1895 def set_value(self, value, attr=None): |
1513 """ |
1896 """ |
1514 Set the current value for this feature. Set the value on the topmost layer. |
1897 Set the current value for this feature. Set the value on the topmost layer. |
1515 @param value: the value to set |
1898 @param value: the value to set |
1516 """ |
1899 """ |
1517 # Do not allow setting of setting of sequence values directly with Feature object |
1900 data_objs = self.convert_value_to_data(value, attr) |
1518 if not self.is_sequence(): |
1901 |
1519 value = self.set_value_cast(value, attr) |
1902 # Set the created data objects to the dataproxy and the |
1520 self.dataproxy._set_value(value, attr) |
1903 # last configuration, overriding any existing elements |
1521 |
1904 self.dataproxy._set_datas(data_objs, attr) |
|
1905 last_config = self.get_root_configuration().get_last_configuration() |
|
1906 last_config.add_data(data_objs, container.REPLACE) |
|
1907 |
|
1908 def convert_data_to_value(self, data_objects, cast=True, attr=None): |
|
1909 """ |
|
1910 Convert the given list of Data objects into a suitable value |
|
1911 for this setting. |
|
1912 @param data_objects: The Data object list. |
|
1913 @param cast: If True, the value should be cast to its correct Python type |
|
1914 (e.g. int), if False, the value should remain in the string form |
|
1915 it was in the data objects. |
|
1916 @param attr: The attribute name of the data. E.g. attr='data', attr='rfs' |
|
1917 @return: The converted value. |
|
1918 """ |
|
1919 if not data_objects: return None |
|
1920 |
|
1921 data_obj = data_objects[-1] |
|
1922 if data_obj.map: |
|
1923 value = self._resolve_name_id_mapped_value(data_obj.map, cast_value=cast) |
|
1924 else: |
|
1925 value = data_obj.value |
|
1926 if cast: value = self.get_value_cast(value, attr) |
|
1927 return value |
|
1928 |
|
1929 def convert_value_to_data(self, value, attr=None): |
|
1930 """ |
|
1931 Convert the given value to a list of Data objects that can be placed |
|
1932 in the configuration's last layer's data section (DataContainer object). |
|
1933 @param value: The value to convert. |
|
1934 @param attr: The attribute name of the data. E.g. attr='data', attr='rfs' |
|
1935 @return: The converted Data objects. |
|
1936 """ |
|
1937 value = self.set_value_cast(value, attr) |
|
1938 return [Data(fqr=self.fqr, value=value, attr=attr)] |
|
1939 |
1522 def del_value(self, attr=None): |
1940 def del_value(self, attr=None): |
1523 """ |
1941 """ |
1524 Delete the topmost value for this feature. |
1942 Delete the topmost value for this feature. |
1525 """ |
1943 """ |
1526 if not self.is_sequence(): |
1944 self.dataproxy._del_value(attr) |
1527 self.dataproxy._del_value(attr) |
|
1528 |
1945 |
1529 def get_value_cast(self, value, attr=None): |
1946 def get_value_cast(self, value, attr=None): |
1530 """ |
1947 """ |
1531 A function to perform the value type casting in get operation |
1948 A function to perform the value type casting in get operation |
1532 @param value: the value to cast |
1949 @param value: the value to cast |
1628 self.dataproxy = self.get_default_view().get_feature(self.get_fullfqr()) |
2038 self.dataproxy = self.get_default_view().get_feature(self.get_fullfqr()) |
1629 return self._dataproxy |
2039 return self._dataproxy |
1630 def setdataproxy(self, value): self._dataproxy = value |
2040 def setdataproxy(self, value): self._dataproxy = value |
1631 def deldataproxy(self): self._dataproxy = None |
2041 def deldataproxy(self): self._dataproxy = None |
1632 dataproxy = property(getdataproxy, setdataproxy, deldataproxy) |
2042 dataproxy = property(getdataproxy, setdataproxy, deldataproxy) |
1633 value = property(get_value, set_value, del_value) |
2043 """ Use custom OProperty to enable overriding value methods in subclasses """ |
|
2044 value = utils.OProperty(get_value, set_value, del_value) |
|
2045 |
|
2046 def get_column_value(self, attr=None): |
|
2047 """ |
|
2048 Get the value of the featuresequence column |
|
2049 @param ref: the reference to the column |
|
2050 @param attr: The attribute name of the data. E.g. attr='data', attr='rfs' |
|
2051 """ |
|
2052 """ get the feature specific data from sequence => a column of data table """ |
|
2053 seq_parent = self.get_sequence_parent() |
|
2054 if seq_parent._has_empty_sequence_marker(): |
|
2055 return [] |
|
2056 |
|
2057 coldata = [] |
|
2058 colref = self.path(seq_parent) |
|
2059 for row in seq_parent.data: |
|
2060 feadata = row.get_feature(colref) |
|
2061 coldata.append(feadata.get_value(attr)) |
|
2062 return coldata |
|
2063 |
|
2064 def get_column_original_value(self, attr=None): |
|
2065 """ |
|
2066 Get the value of the featuresequence column |
|
2067 @param feasequence: the feature sequence object |
|
2068 @param ref: the reference to the column |
|
2069 @param attr: The attribute name of the data. E.g. attr='data', attr='rfs' |
|
2070 """ |
|
2071 """ get the feature specific data from sequence => a column of data table """ |
|
2072 seq_parent = self.get_sequence_parent() |
|
2073 if seq_parent._has_empty_sequence_marker(): |
|
2074 return [] |
|
2075 |
|
2076 coldata = [] |
|
2077 colref = self.path(seq_parent) |
|
2078 for row in seq_parent.data: |
|
2079 feadata = row.get_feature(colref) |
|
2080 coldata.append(feadata.get_original_value(attr)) |
|
2081 return coldata |
|
2082 |
|
2083 def set_column_value(self, value, attr=None): |
|
2084 """ |
|
2085 Get the value of the featuresequence column |
|
2086 @param feasequence: the feature sequence object |
|
2087 @param ref: the reference to the column |
|
2088 @param value: the value to set. This must be a list instance. |
|
2089 @param attr: The attribute name of the data. E.g. attr='data', attr='rfs' |
|
2090 """ |
|
2091 seq_parent = self.get_sequence_parent() |
|
2092 colref = self.path(seq_parent) |
|
2093 |
|
2094 if not isinstance(value,list): |
|
2095 raise exceptions.ConeException("The value for feature sequence '%s' column '%s' must be a list instance. Got %r" % (self.get_sequence_parent().fqr, colref, value)) |
|
2096 |
|
2097 # Handle the special case where the sequence is marked as empty |
|
2098 # with the empty sequence marker (single empty data element) |
|
2099 if seq_parent._has_empty_sequence_marker(): |
|
2100 seqrows = [] |
|
2101 else: |
|
2102 seqrows = seq_parent.data |
|
2103 |
|
2104 if len(seqrows) < len(value): |
|
2105 raise exceptions.ConeException("Too many values for feature sequence '%s' column '%s'. Sequence holds only %d rows. Got %d data values in %r" % (self.get_sequence_parent().fqr, colref, len(seqrows), len(value), value)) |
|
2106 for i in range(0, len(value)): |
|
2107 feadata = seqrows[i].get_feature(colref) |
|
2108 feadata.set_value(value[i]) |
|
2109 |
|
2110 def add_sequence_feature(self, feature, path=""): |
|
2111 """ |
|
2112 Override of the add_feature function in sequence to set the sequence childs to act |
|
2113 as columns of the feature sequence |
|
2114 @param feature: The Feature object to add |
|
2115 @param path: path to feature if it not added directly under parent_fea |
|
2116 """ |
|
2117 # modify all possible children of feature |
|
2118 for fea in feature._traverse(type=Feature): |
|
2119 to_sequence_feature(fea) |
|
2120 |
|
2121 # Finally modify and add this feature to parent_feat |
|
2122 to_sequence_feature(feature) |
|
2123 self._add_to_path(path, feature) |
|
2124 |
|
2125 def _resolve_name_id_mapped_value(self, mapping_string, cast_value=True): |
|
2126 """ |
|
2127 Resolve the name-ID mapped value based on the given mapping string. |
|
2128 @param mapping_string: The name-ID mapping string in the data element, e.g. |
|
2129 "FooFeature/FooSequence[@key='123']" |
|
2130 @param cast_value: If True, the resolved value will be cast to the corresponding |
|
2131 Python type, otherwise the raw string representation of the value in the |
|
2132 data element will be returned. |
|
2133 @return: The resolved value. |
|
2134 """ |
|
2135 def fail(msg): raise exceptions.NameIdMappingError(msg) |
|
2136 |
|
2137 pattern = r"^([\w/]+)\[@key='(.*)'\]$" |
|
2138 m = re.match(pattern, mapping_string) |
|
2139 if m is None: fail("Malformed mapping expression: %s" % mapping_string) |
|
2140 |
|
2141 source_seq_ref = m.group(1).replace('/', '.') |
|
2142 mapping_key = m.group(2) |
|
2143 |
|
2144 dview = self.get_root_configuration().get_default_view() |
|
2145 |
|
2146 try: |
|
2147 source_seq = dview.get_feature(source_seq_ref) |
|
2148 except exceptions.NotFound: |
|
2149 fail("Mapping source sequence '%s' does not exist" % source_seq_ref) |
|
2150 |
|
2151 if source_seq.type != 'sequence': |
|
2152 fail("Mapping source setting '%s' is not a sequence setting" % source_seq_ref) |
|
2153 if not source_seq.mapKey or not source_seq.mapValue: |
|
2154 fail("Source sequence '%s' must have both mapKey and mapValue specified" % source_seq_ref) |
|
2155 |
|
2156 def get_subsetting(ref): |
|
2157 """ |
|
2158 Return the sub-setting by the given mapKey or mapValue ref from the |
|
2159 source sequence. |
|
2160 @param ref: The reference in the format it is in the ConfML file. |
|
2161 E.g. 'SubSetting', 'FileSubSetting/localPath', 'FileSubSetting/targetPath' |
|
2162 """ |
|
2163 subsetting = source_seq.get_feature(ref.replace('/', '.')) |
|
2164 # Use localPath for file and folder settings by default |
|
2165 if subsetting.type in ('file', 'folder'): |
|
2166 subsetting = subsetting.get_feature('localPath') |
|
2167 return subsetting |
|
2168 |
|
2169 try: |
|
2170 key_subsetting = get_subsetting(source_seq.mapKey) |
|
2171 except exceptions.NotFound: |
|
2172 fail("Invalid mapKey in source sequence '%s': no sub-setting with ref '%s'" % (source_seq_ref, source_seq.mapKey)) |
|
2173 |
|
2174 |
|
2175 # Get possible override for mapValue from options |
|
2176 value_subsetting_ref = source_seq.mapValue |
|
2177 value_subsetting_ref_overridden = False |
|
2178 for opt in self._objects(type=Option): |
|
2179 if not opt.map or not opt.map_value: continue |
|
2180 if opt.map.replace('/', '.') == source_seq_ref: |
|
2181 value_subsetting_ref = opt.map_value |
|
2182 value_subsetting_ref_overridden = True |
|
2183 |
|
2184 try: |
|
2185 value_subsetting = get_subsetting(value_subsetting_ref) |
|
2186 except exceptions.NotFound: |
|
2187 if value_subsetting_ref_overridden: |
|
2188 fail("Invalid mapValue override in option: sub-setting '%s' does not exist under source sequence '%s'" % (value_subsetting_ref, source_seq_ref)) |
|
2189 else: |
|
2190 fail("Invalid mapValue in source sequence '%s': no sub-setting with ref '%s'" % (source_seq_ref, value_subsetting_ref)) |
|
2191 |
|
2192 key_list = key_subsetting.get_original_value() |
|
2193 if mapping_key not in key_list: |
|
2194 fail("No item-setting in source sequence '%s' matches key '%s'" % (source_seq_ref, mapping_key)) |
|
2195 |
|
2196 if cast_value: value_list = value_subsetting.get_value() |
|
2197 else: value_list = value_subsetting.get_original_value() |
|
2198 return value_list[key_list.index(mapping_key)] |
|
2199 |
1634 |
2200 |
1635 class FeatureSequence(Feature): |
2201 class FeatureSequence(Feature): |
1636 POLICY_REPLACE = 0 |
2202 POLICY_REPLACE = 0 |
1637 POLICY_APPEND = 1 |
2203 POLICY_APPEND = 1 |
1638 POLICY_PREPEND = 2 |
2204 POLICY_PREPEND = 2 |
1705 fea._index = utils.get_list(self.dataproxy._get(self.dataelem_name)).index(rowproxy) |
2276 fea._index = utils.get_list(self.dataproxy._get(self.dataelem_name)).index(rowproxy) |
1706 # Create a the subfeatures / columns for the parent feature and |
2277 # Create a the subfeatures / columns for the parent feature and |
1707 # add a data element under each feature. |
2278 # add a data element under each feature. |
1708 for feaname in self.list_all_features(): |
2279 for feaname in self.list_all_features(): |
1709 (pathto_fea, fearef) = utils.dottedref.psplit_ref(feaname) |
2280 (pathto_fea, fearef) = utils.dottedref.psplit_ref(feaname) |
1710 rowproxy.add_feature(FeatureSequenceSub(fearef), pathto_fea) |
2281 subfea = self.get_feature(feaname) |
|
2282 cellfea = FeatureSequenceSub(fearef) |
|
2283 cellfea.set_value_cast = subfea.set_value_cast |
|
2284 cellfea.get_value_cast = subfea.get_value_cast |
|
2285 cellfea.convert_data_to_value = subfea.convert_data_to_value |
|
2286 cellfea.convert_value_to_data = subfea.convert_value_to_data |
|
2287 rowproxy.add_feature(cellfea, pathto_fea) |
1711 subproxy = rowproxy.get_feature(feaname) |
2288 subproxy = rowproxy.get_feature(feaname) |
1712 subproxy._obj._parent = subproxy._parent |
2289 subproxy._obj._parent = subproxy._parent |
1713 if not dataobj._has(feaname): |
2290 if create_sub_data_objs and not dataobj._has(feaname): |
1714 dataobj._add_to_path(pathto_fea, Data(ref=fearef)) |
2291 dataobj._add_to_path(pathto_fea, Data(ref=fearef)) |
1715 subproxy._add_data(dataobj._get(feaname)) |
2292 subproxy._add_data(dataobj._get(feaname)) |
1716 |
2293 return dataobj |
|
2294 |
|
2295 def _has_empty_sequence_marker(self): |
|
2296 """ |
|
2297 Return True if the sequence setting has the empty sequence marker (a single |
|
2298 empty data element), which denotes that the sequence is set to empty. |
|
2299 """ |
|
2300 datatable = self.get_data() |
|
2301 if len(datatable) == 1: |
|
2302 data_elem = datatable[0].get_datas()[0] |
|
2303 if len(data_elem._order) == 0: |
|
2304 return True |
|
2305 return False |
|
2306 |
1717 def add(self, child, policy=container.REPLACE): |
2307 def add(self, child, policy=container.REPLACE): |
1718 """ |
2308 """ |
1719 A generic add function to add child objects. The function is intended to act as |
2309 A generic add function to add child objects. The function is intended to act as |
1720 proxy function that call the correct add function based on the child objects class. |
2310 proxy function that call the correct add function based on the child objects class. |
1721 |
2311 |
1729 self._add(child) |
2319 self._add(child) |
1730 elif isinstance(child, Base): |
2320 elif isinstance(child, Base): |
1731 self._add(child) |
2321 self._add(child) |
1732 else: |
2322 else: |
1733 raise exceptions.IncorrectClassError("Cannot add %s to %s" % (child, self)) |
2323 raise exceptions.IncorrectClassError("Cannot add %s to %s" % (child, self)) |
|
2324 |
|
2325 def add_feature(self, feature, path=""): |
|
2326 """ |
|
2327 Override of the add_feature function in sequence to set the sequence childs to act |
|
2328 as columns of the feature sequence |
|
2329 @param feature: The Feature object to add |
|
2330 """ |
|
2331 add_sequence_feature(self, feature, path) |
1734 |
2332 |
1735 def add_sequence(self, data=None, policy=POLICY_APPEND): |
2333 def add_sequence(self, data=None, policy=POLICY_APPEND): |
1736 """ |
2334 """ |
1737 Add a feature data row for a new data in this sequence |
2335 Add a feature data row for a new data in this sequence |
1738 """ |
2336 """ |
1739 self._add_datarow(None, policy) |
2337 if self._has_empty_sequence_marker(): |
|
2338 # We currently have the empty sequence marker (single empty data |
|
2339 # element), so this one that we are adding should replace it |
|
2340 policy = self.POLICY_REPLACE |
|
2341 |
|
2342 datarow = self._add_datarow(None, policy) |
|
2343 # add the new data sequence/row to the last configuration layer |
|
2344 last_config = self.get_root_configuration().get_last_configuration() |
|
2345 |
|
2346 container_policy = {self.POLICY_REPLACE: container.REPLACE, |
|
2347 self.POLICY_APPEND: container.APPEND, |
|
2348 self.POLICY_PREPEND: container.PREPEND}[policy] |
|
2349 last_config.add_data(datarow, container_policy) |
|
2350 |
1740 # set the initial data if it is given |
2351 # set the initial data if it is given |
1741 rowproxy = utils.get_list(self.dataproxy._get(self.dataelem_name))[-1] |
2352 rowproxy = utils.get_list(self.dataproxy._get(self.dataelem_name))[-1] |
1742 if data != None: |
2353 if data != None: |
1743 for index in range(len(data)): |
2354 for index in range(len(data)): |
1744 rowproxy[index].set_value(data[index]) |
2355 if data[index] != None: |
1745 # add the new data sequence/row to the last configuration layer |
2356 rowproxy[index].set_value(data[index]) |
1746 dataobj = rowproxy._get_data() |
|
1747 last_config = self.get_root_configuration().get_last_configuration() |
|
1748 last_config.add_data(dataobj, container.APPEND) |
|
1749 return dataobj |
|
1750 |
2357 |
1751 def set_template(self, data=None): |
2358 def set_template(self, data=None): |
1752 """ |
2359 """ |
1753 Set the template of the feature sequence |
2360 Set the template of the feature sequence |
1754 """ |
2361 """ |
1755 # If template data is not existing, create it |
2362 if data is None: |
1756 if self._templatedata == None: |
2363 self._templatedata = None |
1757 self._set_template_data(Data(ref=self.ref, template=True)) |
2364 return |
1758 # Add the template data to parent config |
2365 |
1759 pconfig = self.find_parent(type=Configuration) |
2366 if not isinstance(data, list): |
1760 pconfig.add_data(self._templatedata) |
2367 raise TypeError('data must be a list (got %r)' % data) |
1761 |
2368 |
1762 if data != None: |
2369 # Create the new template data object |
1763 templdatas = self._templatedata._objects() |
2370 templatedata = Data(fqr=self.fqr, template=True) |
1764 for index in range(len(data)): |
2371 |
1765 templdatas[index].set_value(data[index]) |
2372 # Add all sub-objects to the data object |
|
2373 def add_data_objects(feature, data_obj, value_list): |
|
2374 refs = feature.list_features() |
|
2375 if len(refs) != len(value_list): |
|
2376 raise ValueError("Data value list is invalid") |
|
2377 for i, ref in enumerate(refs): |
|
2378 value = value_list[i] |
|
2379 subfea = feature.get_feature(ref) |
|
2380 if isinstance(value, list): |
|
2381 subdata = Data(ref=ref) |
|
2382 data_obj.add(subdata) |
|
2383 add_data_objects(feature.get_feature(ref), subdata, value) |
|
2384 else: |
|
2385 if value is not None: |
|
2386 subdata = Data(ref=ref, value=subfea.set_value_cast(value)) |
|
2387 data_obj.add(subdata) |
|
2388 add_data_objects(self, templatedata, data) |
|
2389 |
|
2390 self._set_template_data(templatedata) |
|
2391 |
|
2392 # Remove any existing template data |
|
2393 pconfig = self.find_parent(type=Configuration) |
|
2394 dataobjs = pconfig._traverse(type=Data, filters=[lambda x: x.template and x.fqr == self.fqr]) |
|
2395 if dataobjs: |
|
2396 for dataobj in dataobjs: |
|
2397 dataobj._parent._remove(dataobj.get_fullref()) |
|
2398 |
|
2399 # Add the template data to the parent config (beginning of the data section) |
|
2400 pconfig.add_data(self._templatedata, policy=container.PREPEND) |
1766 |
2401 |
1767 def get_template(self): |
2402 def get_template(self): |
1768 """ |
2403 """ |
1769 Add a feature data row for a new data in this sequence |
2404 Add a feature data row for a new data in this sequence |
1770 """ |
2405 """ |
1771 #self._set_template(None) |
2406 #self._set_template(None) |
1772 # set the initial data if it is given |
2407 # set the initial data if it is given |
1773 if self._templatedata: |
2408 if self._templatedata: |
1774 return [data.get_value() for data in self._templatedata._objects()] |
2409 def get_data_items(feature, data_obj): |
|
2410 refs = feature.list_features() |
|
2411 if refs: |
|
2412 result = [] |
|
2413 for ref in refs: |
|
2414 if data_obj._has(ref): |
|
2415 result.append(get_data_items(feature.get_feature(ref), data_obj._get(ref))) |
|
2416 else: |
|
2417 result.append(None) |
|
2418 return result |
|
2419 else: |
|
2420 return data_obj.value |
|
2421 return get_data_items(self, self._templatedata) |
1775 else: |
2422 else: |
1776 return None |
2423 return None |
1777 |
2424 |
1778 def get_data(self): |
2425 def get_data(self): |
1779 """ |
2426 """ |
1794 self._set_template_data(data) |
2441 self._set_template_data(data) |
1795 else: |
2442 else: |
1796 # Get the data index |
2443 # Get the data index |
1797 self._add_datarow(data, self._get_policy(data)) |
2444 self._add_datarow(data, self._get_policy(data)) |
1798 return |
2445 return |
1799 |
|
1800 def get_map_key(self): |
|
1801 """ |
|
1802 Returns the setting that corresponds to mapKey attribute of this sequence feature. |
|
1803 """ |
|
1804 if self.mapKey != None: |
|
1805 mapkey = self.get_feature(self.mapKey) |
|
1806 return mapkey |
|
1807 else: |
|
1808 return None |
|
1809 |
|
1810 def get_map_key_value(self,key): |
|
1811 """ |
|
1812 Returns the setting that corresponds to mapKey attribute of this sequence feature. |
|
1813 """ |
|
1814 value = None |
|
1815 if self.mapKey != None and self.mapValue != None: |
|
1816 data = self.get_data() |
|
1817 for item in data: |
|
1818 kv = item.get_feature(self.mapKey).get_value() |
|
1819 if kv == key: |
|
1820 value = item.get_feature(self.mapValue).get_value() |
|
1821 return value |
|
1822 |
|
1823 def get_map_value(self): |
|
1824 """ |
|
1825 Returns the setting that corresponds to mapValue attribute of this sequence feature. |
|
1826 """ |
|
1827 if self.mapValue != None: |
|
1828 mapvalue = self.get_feature(self.mapValue) |
|
1829 return mapvalue |
|
1830 else: |
|
1831 return None |
|
1832 |
2446 |
1833 def get_value(self, attr=None): |
2447 def get_value(self, attr=None): |
1834 """ |
2448 """ |
1835 Helper function to get the topmost data value from the default view. |
2449 Helper function to get the topmost data value from the default view. |
1836 """ |
2450 """ |
|
2451 if self._has_empty_sequence_marker(): |
|
2452 return [] |
|
2453 |
1837 datatable = self.get_data() |
2454 datatable = self.get_data() |
1838 rettable = [] |
2455 rettable = [] |
1839 for row in datatable: |
2456 for row in datatable: |
1840 rowvalues = row.value |
2457 rowvalues = row.value |
1841 rettable.append(rowvalues) |
2458 rettable.append(rowvalues) |
1842 return rettable |
2459 return rettable |
1843 |
2460 |
|
2461 def get_original_value(self, attr=None): |
|
2462 """ |
|
2463 Get the current value of the feature |
|
2464 @param attr: The attribute name of the data. E.g. attr='data', attr='rfs' |
|
2465 """ |
|
2466 if self._has_empty_sequence_marker(): |
|
2467 return [] |
|
2468 |
|
2469 datatable = self.get_data() |
|
2470 rettable = [] |
|
2471 for row in datatable: |
|
2472 rowvalues = row.get_original_value() |
|
2473 rettable.append(rowvalues) |
|
2474 return rettable |
|
2475 |
1844 def set_value(self, value, attr=None): |
2476 def set_value(self, value, attr=None): |
1845 """ |
2477 """ |
1846 Set the current value for this feature. Set the value on the topmost layer. |
2478 Set the current value for this feature. Set the value on the topmost layer. |
1847 @param value: the value to set. The value must be a two dimensional array (e.g. matrix) |
2479 @param value: the value to set. The value must be a two dimensional array (e.g. matrix) |
1848 """ |
2480 """ |
1849 # sets the first data element to replace policy |
2481 if value: |
1850 try: |
2482 # Add the first item with replace policy |
1851 self.add_sequence(value.pop(0), self.POLICY_REPLACE) |
2483 self.add_sequence(value[0], self.POLICY_REPLACE) |
1852 # ignore the index error of an empty list |
2484 for row in value[1:]: |
1853 except IndexError: |
2485 self.add_sequence(row) |
1854 pass |
2486 else: |
1855 for row in value: |
2487 # Setting the sequence to empty, so add one empty item-setting |
1856 self.add_sequence(row) |
2488 # to signify that |
|
2489 self.add_sequence(None, self.POLICY_REPLACE) |
|
2490 |
|
2491 # Strip all sub-elements from the data element just created, |
|
2492 # since the ConfML spec says that an empty sequence is denoted |
|
2493 # by a single empty data element |
|
2494 data_elem = self.get_data()[0].get_datas()[0] |
|
2495 for r in list(data_elem._order): |
|
2496 data_elem._remove(r) |
1857 |
2497 |
1858 def is_sequence(self): |
2498 def is_sequence(self): |
1859 """ Return always true from a sequence object """ |
2499 """ Return always true from a sequence object """ |
1860 return True |
2500 return True |
1861 |
2501 |
|
2502 def is_sequence_root(self): |
|
2503 """ Return true if this feature is a sequence object it self """ |
|
2504 return True |
|
2505 |
|
2506 def get_column_features(self): |
|
2507 """ Return a list of sequence subfeature, which are the columns of the sequence """ |
|
2508 columns = [] |
|
2509 for subref in self.list_features(): |
|
2510 columns.append(self.get_feature(subref)) |
|
2511 return columns |
|
2512 |
1862 def get_sequence_parent(self): |
2513 def get_sequence_parent(self): |
1863 """ Return this object as a sequence parent """ |
2514 """ Return this object as a sequence parent """ |
1864 return self |
2515 return self |
1865 |
2516 |
1866 value = property(get_value, set_value) |
2517 value = property(get_value, set_value) |
1867 data = property(get_data) |
2518 data = property(get_data) |
1868 |
2519 |
|
2520 |
|
2521 def add_sequence_feature(parent_feature, feature, path=""): |
|
2522 """ |
|
2523 Override of the add_feature function in sequence to set the sequence childs to act |
|
2524 as columns of the feature sequence |
|
2525 @param parent_feature: The parent feature where the feature object is added |
|
2526 @param feature: The Feature object to add |
|
2527 @param path: path to feature if it not added directly under parent_fea |
|
2528 """ |
|
2529 # modify all possible children of feature |
|
2530 for fea in feature._traverse(type=Feature): |
|
2531 to_sequence_feature(fea) |
|
2532 |
|
2533 # Finally modify and add this feature to parent_feat |
|
2534 to_sequence_feature(feature) |
|
2535 parent_feature._add_to_path(path, feature) |
|
2536 |
|
2537 def to_sequence_feature(feature): |
|
2538 """ |
|
2539 modify a Feature object to sequence feature that will return column like data from a sequence. |
|
2540 @param feature: The Feature object for which is modified. |
|
2541 """ |
|
2542 feature.get_value = feature.get_column_value |
|
2543 feature.get_original_value = feature.get_column_original_value |
|
2544 feature.set_value = feature.set_column_value |
|
2545 feature.add_feature = feature.add_sequence_feature |
|
2546 |
|
2547 def get_column_value(feasequence, ref, attr=None): |
|
2548 """ |
|
2549 Get the value of the featuresequence column |
|
2550 @param feasequence: the feature sequence object |
|
2551 @param ref: the reference to the column |
|
2552 @param attr: The attribute name of the data. E.g. attr='data', attr='rfs' |
|
2553 """ |
|
2554 """ get the feature specific data from sequence => a column of data table """ |
|
2555 coldata = [] |
|
2556 for row in feasequence.data: |
|
2557 feadata = row.get_feature(ref) |
|
2558 coldata.append(feadata.get_value(attr)) |
|
2559 return coldata |
|
2560 |
|
2561 def get_column_original_value(feasequence, ref, attr=None): |
|
2562 """ |
|
2563 Get the value of the featuresequence column |
|
2564 @param feasequence: the feature sequence object |
|
2565 @param ref: the reference to the column |
|
2566 @param attr: The attribute name of the data. E.g. attr='data', attr='rfs' |
|
2567 """ |
|
2568 """ get the feature specific data from sequence => a column of data table """ |
|
2569 coldata = [] |
|
2570 for row in feasequence.data: |
|
2571 feadata = row.get_feature(ref) |
|
2572 coldata.append(feadata.get_original_value(attr)) |
|
2573 return coldata |
|
2574 |
|
2575 def set_column_value(feasequence, ref, value, attr=None): |
|
2576 """ |
|
2577 Get the value of the featuresequence column |
|
2578 @param feasequence: the feature sequence object |
|
2579 @param ref: the reference to the column |
|
2580 @param value: the value to set. This must be a list instance. |
|
2581 @param attr: The attribute name of the data. E.g. attr='data', attr='rfs' |
|
2582 """ |
|
2583 if not isinstance(value,list): |
|
2584 raise exceptions.ConeException("The value for feature sequence '%s' column '%s' must be a list instance. Got %r" % (feasequence.fqr, ref, value)) |
|
2585 seqrows = feasequence.data |
|
2586 if len(seqrows) < len(value): |
|
2587 raise exceptions.ConeException("Too many values for feature sequence '%s' column '%s'. Sequence holds only %d rows. Got %d data values in %r" % (feasequence.fqr, ref, len(seqrows), len(value), value)) |
|
2588 for i in range(0, len(value)): |
|
2589 feadata = seqrows[i].get_feature(ref) |
|
2590 feadata.set_value(value[i]) |
|
2591 |
1869 class FeatureSequenceCell(Feature): |
2592 class FeatureSequenceCell(Feature): |
1870 """ |
2593 """ |
1871 A Feature class. Feature is the base for all Configurable items in a Configuration. |
2594 A Feature class. Feature is the base for all Configurable items in a Configuration. |
1872 """ |
2595 """ |
1873 def __init__(self, ref="", **kwargs): |
2596 def __init__(self, ref="", **kwargs): |
1874 super(Feature, self).__init__(ref) |
2597 super(FeatureSequenceCell, self).__init__(ref) |
1875 self.name = kwargs.get('name', ref) |
2598 self.name = kwargs.get('name', ref) |
1876 self.type = 'seqcell' |
2599 self.type = 'seqcell' |
1877 |
2600 |
1878 def get_value(self, attr=None): |
2601 def get_value(self, attr=None): |
1879 """ |
2602 """ |
1913 """ |
2641 """ |
1914 Set the current value for this sequence row. |
2642 Set the current value for this sequence row. |
1915 @param value: the value row to set |
2643 @param value: the value row to set |
1916 """ |
2644 """ |
1917 if utils.is_list(value): |
2645 if utils.is_list(value): |
1918 for subindex in range(0, len(value)): |
2646 for subindex in range(0, len(value)): |
1919 self.dataproxy[subindex].get_data().set_value(value[subindex]) |
2647 self.dataproxy[subindex].get_data().set_value(value[subindex]) |
1920 else: |
2648 else: |
1921 self.dataproxy.get_data().set_value(value) |
2649 data_objs = self.convert_value_to_data(value) |
|
2650 data_object_where_to_add = self._parent._get_data() |
|
2651 |
|
2652 self.dataproxy._set_datas(data_objs, attr) |
|
2653 data_object_where_to_add._add(data_objs, container.REPLACE) |
1922 |
2654 |
1923 def get_value(self, attr=None): |
2655 def get_value(self, attr=None): |
1924 """ |
2656 """ |
1925 Set the current value for this feature. Set the value on the topmost layer. |
2657 Set the current value for this feature. Set the value on the topmost layer. |
1926 @param value: the value to set |
2658 @param value: the value to set |
1927 """ |
2659 """ |
1928 # dataproxy = self.get_default_view().get_feature(self.get_fullfqr()) |
2660 # Handle empty sequences |
|
2661 if self.get_sequence_parent()._has_empty_sequence_marker(): |
|
2662 return [] |
|
2663 |
1929 # The sequence cell only updates the latest value in the proxy |
2664 # The sequence cell only updates the latest value in the proxy |
1930 childdatas = self.dataproxy._objects() |
2665 childdatas = self.dataproxy._objects() |
1931 if len(childdatas) > 0: |
2666 if len(childdatas) > 0: |
1932 return [subdata.value for subdata in childdatas] |
2667 return [subdata.value for subdata in childdatas] |
1933 else: |
2668 else: |
1934 return self.dataproxy._get_value(attr=attr) |
2669 return super(FeatureSequenceSub,self).get_value(attr) |
1935 |
2670 |
|
2671 def get_original_value(self, attr=None): |
|
2672 """ |
|
2673 Get the current value of the feature |
|
2674 @param attr: The attribute name of the data. E.g. attr='data', attr='rfs' |
|
2675 """ |
|
2676 # Handle empty sequences |
|
2677 if self.get_sequence_parent()._has_empty_sequence_marker(): |
|
2678 return [] |
|
2679 |
|
2680 childdatas = self.dataproxy._objects() |
|
2681 if len(childdatas) > 0: |
|
2682 return [subdata.get_original_value() for subdata in childdatas] |
|
2683 else: |
|
2684 return self.dataproxy._get_value(attr) |
|
2685 |
1936 value = property(get_value, set_value) |
2686 value = property(get_value, set_value) |
1937 |
2687 |
1938 |
2688 |
1939 class FeatureLink(Base): |
2689 class FeatureLink(Base): |
1940 """ |
2690 """ |
1941 A _FeatureProxy class. _FeatureProxy is the object that is added to View as a |
2691 A _FeatureProxy class. _FeatureProxy is the object that is added to View as a |
1942 link to the actual Feature object. |
2692 link to the actual Feature object. |
1943 """ |
2693 """ |
1944 def __init__(self, link="", **kwargs): |
2694 """ class variable for defining the override attributes""" |
|
2695 override_attributes = ['name'] |
|
2696 ref_prefix = 'link_' |
|
2697 PROXYREF_PREFIX = 'proxy_' |
|
2698 |
|
2699 def __init__(self, ref="", **kwargs): |
1945 # Store the fully qualified reference to this object |
2700 # Store the fully qualified reference to this object |
1946 self.link = link |
2701 self.link = kwargs.get('link', ref) |
1947 ref = link.replace('.', '_') |
2702 self.name = kwargs.get('name', None) |
1948 super(FeatureLink, self).__init__(ref) |
2703 ref = self.get_featurelink_ref(self.link) |
|
2704 # the reference of this particular object |
|
2705 super(FeatureLink, self).__init__(ref, **kwargs) |
1949 self._obj = None |
2706 self._obj = None |
1950 self._populated = False |
2707 self._populated = False |
|
2708 |
|
2709 def add(self, child, policy=container.REPLACE): |
|
2710 """ |
|
2711 Add an override to enable adding any override attribute to a featurelink object. |
|
2712 |
|
2713 A generic add function to add child objects. The function is intended to act as |
|
2714 proxy function that call the correct add function based on the child objects class. |
|
2715 |
|
2716 Example: obj.add(Feature("test")), actually obj.add_feature(Feature("test")) |
|
2717 @param child: the child object to add |
|
2718 @raise IncorrectClassError: if the given class cannot be added to this object. |
|
2719 """ |
|
2720 if isinstance(child, Base): |
|
2721 self._add(child, policy) |
|
2722 else: |
|
2723 raise exceptions.IncorrectClassError("Cannot add %s to %s" % (child, self)) |
|
2724 |
|
2725 def get_name(self): |
|
2726 """ |
|
2727 Return the name of the featurelink |
|
2728 """ |
|
2729 return self.name |
|
2730 |
|
2731 def set_name(self, name): |
|
2732 """ |
|
2733 Set the name |
|
2734 """ |
|
2735 self.name = name |
1951 |
2736 |
1952 @property |
2737 @property |
1953 def fqr(self): |
2738 def fqr(self): |
1954 return self.link |
2739 return self.link |
1955 |
2740 |
1960 subfeatures. |
2745 subfeatures. |
1961 """ |
2746 """ |
1962 try: |
2747 try: |
1963 if not self._populated: |
2748 if not self._populated: |
1964 feas = self.get_default_view().get_features(self.link) |
2749 feas = self.get_default_view().get_features(self.link) |
|
2750 # get the non wildcard part of ref |
|
2751 static_ref = utils.dottedref.get_static_ref(self.link) |
1965 # add the found features to the parent |
2752 # add the found features to the parent |
1966 for fea in feas: |
2753 for fea in feas: |
1967 self._get_parent().add_feature(fea._obj) |
2754 override_attrs = {} |
|
2755 # override the FeatureProxy object with exactly same reference |
|
2756 # (in feat/* case dont override the children features) |
|
2757 if fea.fqr == static_ref: |
|
2758 override_attrs = self.get_attributes() |
|
2759 feature = fea._obj |
|
2760 proxy_ref = self.get_featureproxy_ref(feature.fqr) |
|
2761 proxy = _FeatureProxy(proxy_ref, feature, **override_attrs) |
|
2762 self._get_parent()._add(proxy) |
|
2763 |
1968 except exceptions.NotFound, e: |
2764 except exceptions.NotFound, e: |
1969 parent_view = self._find_parent_or_default(type=View) |
2765 parent_view = self._find_parent_or_default(type=View) |
1970 view_name = parent_view.get_name() |
2766 view_name = parent_view.get_name() |
1971 logging.getLogger('cone').info("Warning: Feature '%s' in view '%s' not found." % (self.link, view_name)) |
2767 logging.getLogger('cone').info("Warning: Feature '%s' in view '%s' not found." % (self.link, view_name)) |
1972 |
2768 |
|
2769 def get_attributes(self): |
|
2770 """ |
|
2771 Returns a list of FeatureLink attributes that override settings of the original feature. |
|
2772 @return: a dictionary of attribute key : value pairs. |
|
2773 """ |
|
2774 attrs = {} |
|
2775 for attr in self.override_attributes: |
|
2776 # try to get the attribute from this object |
|
2777 # and set it to the attribute list if it not None |
|
2778 try: |
|
2779 value = getattr(self, attr) |
|
2780 if value != None: attrs[attr] = value |
|
2781 except AttributeError: |
|
2782 pass |
|
2783 return attrs |
|
2784 |
|
2785 @classmethod |
|
2786 def get_featurelink_ref(cls, ref): |
|
2787 """ |
|
2788 return a featurelink ref from a feature ref. |
|
2789 This is needed to make the featurelink object refs unique in a container |
|
2790 that has Features. |
|
2791 """ |
|
2792 return cls.ref_prefix + ref.replace('.', '_').replace('/','_') |
|
2793 |
|
2794 @classmethod |
|
2795 def get_featureproxy_ref(cls, ref): |
|
2796 """ |
|
2797 Return a ref for a given setting fqr to be used under a group. |
|
2798 This is needed to make the featureproxy object refs unique in a container |
|
2799 that has Features. |
|
2800 """ |
|
2801 return cls.PROXYREF_PREFIX + ref.replace('.', '_').replace('/','_') |
1973 |
2802 |
1974 class _FeatureProxy(container.ObjectProxyContainer, Base): |
2803 class _FeatureProxy(container.ObjectProxyContainer, Base): |
1975 """ |
2804 """ |
1976 A _FeatureProxy class. _FeatureProxy is the object that is added to View as a |
2805 A _FeatureProxy class. _FeatureProxy is the object that is added to View as a |
1977 link to the actual Feature object. |
2806 link to the actual Feature object. |
1978 """ |
2807 """ |
1979 def __init__(self, ref="", obj=None, **kwargs): |
2808 def __init__(self, ref="", obj=None, **kwargs): |
1980 super(_FeatureProxy, self).__init__(obj, ref) |
2809 container.ObjectProxyContainer.__init__(self, obj, ref) |
1981 Base.__init__(self, ref) |
2810 Base.__init__(self, ref, **kwargs) |
1982 self.support_data = False |
2811 self.support_data = False |
1983 |
2812 |
1984 def __getattr__(self, name): |
2813 def __getattr__(self, name): |
1985 """ |
2814 """ |
1986 First check if the requested attr is a children then |
2815 First check if the requested attr is a children then |
1987 direct all not found attribute calls to the sub object getattr |
2816 direct all not found attribute calls to the sub object getattr |
1988 """ |
2817 """ |
2059 """ |
2894 """ |
2060 Dummy implementation of populate |
2895 Dummy implementation of populate |
2061 """ |
2896 """ |
2062 pass |
2897 pass |
2063 |
2898 |
2064 |
2899 def has_attribute(self, name): |
|
2900 """ |
|
2901 Perform a check whether an attribute with given name is stored inside the |
|
2902 _FeatureProxy. The check does not extend to the proxied (_obj) insanses or |
|
2903 children of this proxy. |
|
2904 |
|
2905 @return: True when an attribute is a real attribute in this _FeatureProxy object. |
|
2906 """ |
|
2907 return self.__dict__.has_key(name) |
|
2908 |
|
2909 def get_option(self, ref): |
|
2910 """ |
|
2911 @param name: The option reference of the option (as returned by list_options()) |
|
2912 """ |
|
2913 real_ref = 'opt_' + ref |
|
2914 for op in self.options.values(): |
|
2915 if op.ref == real_ref: |
|
2916 return op |
|
2917 else: |
|
2918 |
|
2919 obj = self.get_proxied_obj()._get(real_ref) |
|
2920 if not isinstance(obj, Option): |
|
2921 raise TypeError('Object %r is not an instance of Option (%r instead)' % (real_ref, type(obj))) |
|
2922 return obj |
|
2923 |
|
2924 def list_options(self): |
|
2925 """ |
|
2926 Return a array of all Option children references under this object. |
|
2927 """ |
|
2928 opts = self.get_proxied_obj().list_options() |
|
2929 |
|
2930 for opt in self.options: |
|
2931 opts.append(self.options[opt].ref[4:]) |
|
2932 |
|
2933 return opts |
|
2934 |
|
2935 def get_property(self, ref): |
|
2936 """ |
|
2937 @param name: The property reference of the property (as returned by list_properties()) |
|
2938 """ |
|
2939 for prop in self.properties.values(): |
|
2940 if prop.ref == Property.to_propertyref(ref): |
|
2941 return prop |
|
2942 else: |
|
2943 obj = self.get_proxied_obj()._get(Property.to_propertyref(ref)) |
|
2944 return obj |
|
2945 |
|
2946 def list_properties(self): |
|
2947 """ |
|
2948 Return a array of all Property children references under this object. |
|
2949 """ |
|
2950 props = self.get_proxied_obj().list_properties() |
|
2951 |
|
2952 for pr in self.properties: |
|
2953 props.append(Property.to_normref(self.properties[pr].ref)) |
|
2954 |
|
2955 return props |
|
2956 |
|
2957 |
2065 class _FeatureDataProxy(_FeatureProxy): |
2958 class _FeatureDataProxy(_FeatureProxy): |
2066 """ |
2959 """ |
2067 A Feature class. Feature is the base for all Configurable items in a Configuration. |
2960 A Feature class. Feature is the base for all Configurable items in a Configuration. |
2068 """ |
2961 """ |
2069 DEFAULT_KEY = 'data' |
2962 DEFAULT_KEY = 'data' |
2083 |
2976 |
2084 def __getattr__(self, name): |
2977 def __getattr__(self, name): |
2085 """ |
2978 """ |
2086 """ |
2979 """ |
2087 if object.__getattribute__(self, '_obj') is not None: |
2980 if object.__getattribute__(self, '_obj') is not None: |
2088 self._obj.dataproxy = self |
2981 self.get_proxied_obj().dataproxy = self |
2089 |
2982 |
2090 if name in Feature.PROPERTIES: |
2983 if name in Feature.PROPERTIES: |
2091 return getattr(self._obj, name) |
2984 return getattr(self.get_proxied_obj(), name) |
2092 else: |
2985 else: |
2093 return super(_FeatureDataProxy, self).__getattr__(name) |
2986 return super(_FeatureDataProxy, self).__getattr__(name) |
2094 |
2987 |
2095 def __setattr__(self, name, value): |
2988 def __setattr__(self, name, value): |
2096 """ |
2989 """ |
2097 """ |
2990 """ |
2098 if object.__getattribute__(self, '_obj') is not None: |
2991 if object.__getattribute__(self, '_obj') is not None: |
2099 self._obj.dataproxy = self |
2992 self.get_proxied_obj().dataproxy = self |
2100 |
2993 |
2101 if name in Feature.PROPERTIES: |
2994 if name in Feature.PROPERTIES: |
2102 return setattr(self._obj, name, value) |
2995 return setattr(self.get_proxied_obj(), name, value) |
2103 else: |
2996 else: |
2104 super(_FeatureDataProxy, self).__setattr__(name, value) |
2997 super(_FeatureDataProxy, self).__setattr__(name, value) |
2105 |
2998 |
2106 def __delattr__(self, name): |
2999 def __delattr__(self, name): |
2107 """ |
3000 """ |
2108 """ |
3001 """ |
2109 if name in Feature.PROPERTIES: |
3002 if name in Feature.PROPERTIES: |
2110 return delattr(self._obj, name) |
3003 return delattr(self.get_proxied_obj(), name) |
2111 else: |
3004 else: |
2112 return super(_FeatureDataProxy, self).__delattr__(name) |
3005 return super(_FeatureDataProxy, self).__delattr__(name) |
2113 |
3006 |
2114 def _add_data(self, data): |
3007 def _add_data(self, data): |
2115 """ |
3008 """ |
2116 Add a data value. |
3009 Add a data value or a list of data values. |
2117 @param data: A Data object |
3010 @param data: A Data object |
2118 """ |
3011 """ |
|
3012 if isinstance(data, list): |
|
3013 for d in data: self._add_data(d) |
|
3014 return |
|
3015 |
2119 try: |
3016 try: |
2120 self.datas[data.attr].append(data) |
3017 self.datas[data.attr].append(data) |
2121 except KeyError: |
3018 except KeyError: |
2122 """ Create a list object for missing attribute """ |
3019 """ Create a list object for missing attribute """ |
2123 self.datas[data.attr] = [] |
3020 self.datas[data.attr] = [] |
2251 self.value = kwargs.get('value', None) |
3155 self.value = kwargs.get('value', None) |
2252 self.attr = kwargs.get('attr') or 'data' |
3156 self.attr = kwargs.get('attr') or 'data' |
2253 self.policy = kwargs.get('policy', '') |
3157 self.policy = kwargs.get('policy', '') |
2254 self.template = kwargs.get('template', False) |
3158 self.template = kwargs.get('template', False) |
2255 self.map = kwargs.get('map') |
3159 self.map = kwargs.get('map') |
|
3160 self.empty = kwargs.get('empty', False) |
|
3161 self.lineno = None |
|
3162 |
|
3163 def __setstate__(self, state): |
|
3164 super(Data, self).__setstate__(state) |
|
3165 self.value = state.get('value', None) |
|
3166 self.attr = state.get('attr', None) |
|
3167 self.policy = state.get('policy', '') |
|
3168 self.map = state.get('map', None) |
|
3169 self.template = state.get('template', False) |
|
3170 self.lineno = state.get('lineno', None) |
|
3171 self.fearef = state.get('fearef', None) |
2256 |
3172 |
2257 def get_fearef(self): |
3173 def get_fearef(self): |
2258 if self.fearef: |
3174 if self.fearef: |
2259 return self.fearef |
3175 return self.fearef |
2260 else: |
3176 else: |
2261 return self.fqr |
3177 return self.fqr |
2262 |
3178 |
2263 def get_value(self): |
3179 def get_value(self): |
2264 if self.map != None: |
3180 return self.value |
2265 ref = utils.resourceref.to_dref(self.get_map_ref()) |
|
2266 key = self.get_map_key_value() |
|
2267 dview = self.get_root_configuration().get_default_view() |
|
2268 fea = dview.get_feature(ref) |
|
2269 return fea.get_map_key_value(key) |
|
2270 else: |
|
2271 return self.value |
|
2272 |
3181 |
2273 def get_map(self): |
3182 def get_map(self): |
2274 return self.map |
3183 return self.map |
2275 |
3184 |
2276 def set_map(self, map): |
3185 def set_map(self, map): |
2277 self.map = map |
3186 self.map = map |
2278 if self.value: |
3187 if self.value: |
2279 #Either value or mapping can be defined. Not both. |
3188 #Either value or mapping can be defined. Not both. |
2280 self.value = None |
3189 self.value = None |
2281 |
3190 |
2282 def get_map_ref(self): |
|
2283 if self.map != None: |
|
2284 return utils.DataMapRef.get_feature_ref(self.map) |
|
2285 else: |
|
2286 return None |
|
2287 |
|
2288 def get_map_key_value(self): |
|
2289 if self.map != None: |
|
2290 return utils.DataMapRef.get_key_value(self.map) |
|
2291 else: |
|
2292 return None |
|
2293 |
|
2294 def set_value(self, value): |
3191 def set_value(self, value): |
2295 self.value = value |
3192 self.value = value |
2296 if self.map: |
3193 if self.map: |
2297 #Either value or mapping can be defined. Not both. |
3194 #Either value or mapping can be defined. Not both. |
2298 self.map = None |
3195 self.map = None |
2766 try: |
3739 try: |
2767 self.color_depth = ord(data[self._BMP_BITS_PER_PIXEL_OFFSET_]) |
3740 self.color_depth = ord(data[self._BMP_BITS_PER_PIXEL_OFFSET_]) |
2768 except Exception, e: |
3741 except Exception, e: |
2769 self.logger.warning("Invalid BMP-file: %s" % resource.get_path()) |
3742 self.logger.warning("Invalid BMP-file: %s" % resource.get_path()) |
2770 |
3743 |
|
3744 |
|
3745 class currentdir(object): |
|
3746 def __init__(self, storage, curdir): |
|
3747 self.storage = storage |
|
3748 # make sure that the curdir does not contain path prefix |
|
3749 self.curdir = curdir.lstrip('/') |
|
3750 |
|
3751 def __enter__(self): |
|
3752 self.storage.push(self.curdir) |
|
3753 |
|
3754 def __exit__(self, type, value, tb): |
|
3755 self.storage.pop() |
|
3756 |
|
3757 |
2771 class Folder(object): |
3758 class Folder(object): |
2772 """ |
3759 """ |
2773 A Folder object is a subfolder of a Storage, offering access to part of the Storages resources. |
3760 A Folder object is a subfolder of a Storage, offering access to part of the Storages resources. |
2774 """ |
3761 """ |
2775 def __init__(self, storage, path): |
3762 def __init__(self, storage, path, **kwargs): |
2776 """ |
3763 """ |
2777 Create a layer folder to the storage if it does not exist. |
3764 Create a layer folder to the storage if it does not exist. |
2778 """ |
3765 """ |
2779 #if not storage.is_folder(path): |
3766 self.curpath = path |
2780 # storage.create_folder(path) |
3767 self.storage = storage |
2781 self.storage = copy.copy(storage) |
3768 |
2782 self.storage.set_current_path(path) |
3769 def set_path(self, path): |
2783 |
3770 """ |
2784 def __getattr__(self, name): |
3771 """ |
2785 return getattr(self.storage, name) |
3772 self.curpath = path |
2786 |
3773 |
2787 class CompositeLayer(object): |
3774 def get_path(self): |
|
3775 """ |
|
3776 """ |
|
3777 return self.curpath |
|
3778 |
|
3779 def set_current_path(self, path): |
|
3780 """ |
|
3781 @param path: the current path under the Storage. |
|
3782 """ |
|
3783 self.curpath = utils.resourceref.remove_end_slash(utils.resourceref.remove_begin_slash(path)) |
|
3784 |
|
3785 def get_current_path(self): |
|
3786 """ |
|
3787 get the current path under the Storage. |
|
3788 """ |
|
3789 return self.curpath |
|
3790 |
|
3791 def close(self): |
|
3792 """ |
|
3793 Close the repository, which will save and close all open resources. |
|
3794 """ |
|
3795 self.storage.close() |
|
3796 |
|
3797 def save(self): |
|
3798 """ |
|
3799 Flush changes from all resources to the repository. |
|
3800 """ |
|
3801 return self.storage.save() |
|
3802 |
|
3803 def open_resource(self, path, mode="r"): |
|
3804 """ |
|
3805 Open the given resource and return a File object. |
|
3806 @param path : reference to the resource |
|
3807 @param mode : the mode in which to open. Can be one of r = read, w = write, a = append. |
|
3808 raises a NotResource exception if the ref item is not a resource. |
|
3809 """ |
|
3810 with currentdir(self.storage, self.curpath): |
|
3811 res = self.storage.open_resource(path, mode) |
|
3812 return res |
|
3813 |
|
3814 def delete_resource(self, path): |
|
3815 """ |
|
3816 Delete the given resource from storage |
|
3817 @param path: reference to the resource |
|
3818 raises a NotSupportedException exception if delete operation is not supported by the storage |
|
3819 """ |
|
3820 with currentdir(self.storage, self.curpath): |
|
3821 res = self.storage.delete_resource(path) |
|
3822 return res |
|
3823 |
|
3824 def close_resource(self, path): |
|
3825 """ |
|
3826 Close a given resource instance. Normally this is called by the Resource object |
|
3827 in its own close. |
|
3828 @param path the reference to the resource to close. |
|
3829 """ |
|
3830 with currentdir(self.storage, self.curpath): |
|
3831 res = self.storage.close_resource(path) |
|
3832 return res |
|
3833 |
|
3834 def is_resource(self, path): |
|
3835 """ |
|
3836 Return true if the ref is a resource |
|
3837 @param ref : reference to path where resources are searched |
|
3838 """ |
|
3839 with currentdir(self.storage, self.curpath): |
|
3840 res = self.storage.is_resource(path) |
|
3841 return res |
|
3842 |
|
3843 def list_resources(self, path, **kwargs): |
|
3844 """ |
|
3845 find the resources under certain ref/path |
|
3846 @param ref : reference to path where resources are searched |
|
3847 @param recurse : defines whether to return resources directly under the path or does the listing recurse to subfolders. |
|
3848 Default value is False. Set to True to enable recursion. |
|
3849 """ |
|
3850 with currentdir(self.storage, self.curpath): |
|
3851 res = self.storage.list_resources(path, **kwargs) |
|
3852 return res |
|
3853 |
|
3854 def import_resources(self, paths, storage): |
|
3855 """ |
|
3856 import resources from a list of resources to this storage |
|
3857 @param paths : a list of Resourse objects. |
|
3858 @param storage : the external storage from which files are imported. |
|
3859 """ |
|
3860 with currentdir(self.storage, self.curpath): |
|
3861 res = self.storage.import_resources(paths, storage) |
|
3862 return res |
|
3863 |
|
3864 def export_resources(self, paths, storage): |
|
3865 """ |
|
3866 export resources from this storage based on a list of reference to this storage |
|
3867 @param path : a list of resource paths in this storage (references). |
|
3868 @param storage : the external storage where to export. |
|
3869 """ |
|
3870 with currentdir(self.storage, self.curpath): |
|
3871 res = self.storage.export_resources(paths, storage) |
|
3872 return res |
|
3873 |
|
3874 def save_resource(self, path): |
|
3875 """ |
|
3876 Flush the changes of a given resource instance. Normally this is called by the Resource object |
|
3877 in its own save. |
|
3878 @param ref the reference to the resource to close. |
|
3879 """ |
|
3880 with currentdir(self.storage, self.curpath): |
|
3881 res = self.storage.save_resource(path) |
|
3882 return res |
|
3883 |
|
3884 def create_folder(self, path): |
|
3885 """ |
|
3886 Create a folder entry to a path |
|
3887 @param path : path to the folder |
|
3888 """ |
|
3889 with currentdir(self.storage, self.curpath): |
|
3890 res = self.storage.create_folder(path) |
|
3891 return res |
|
3892 |
|
3893 def delete_folder(self, path): |
|
3894 """ |
|
3895 Delete a folder entry from a path. The path must be empty. |
|
3896 @param path : path to the folder |
|
3897 """ |
|
3898 with currentdir(self.storage, self.curpath): |
|
3899 res = self.storage.delete_folder(path) |
|
3900 return res |
|
3901 |
|
3902 def is_folder(self, path): |
|
3903 """ |
|
3904 Check if the given path is an existing folder in the storage |
|
3905 @param path : path to the folder |
|
3906 """ |
|
3907 with currentdir(self.storage, self.curpath): |
|
3908 res = self.storage.is_folder(path) |
|
3909 return res |
|
3910 |
|
3911 def get_mode(self, mode_str): |
|
3912 return self.storage.get_mode() |
|
3913 |
|
3914 def unload(self, path, object): |
|
3915 """ |
|
3916 Dump a given object to the storage |
|
3917 @param object: The object to dump to the storage, which is expected to be an instance |
|
3918 of Base class. |
|
3919 @param path: The reference where to store the object |
|
3920 @param object: The object instance to dump |
|
3921 @raise StorageException: if the given object cannot be dumped to this storage |
|
3922 """ |
|
3923 with currentdir(self.storage, self.curpath): |
|
3924 res = self.storage.unload(path, object) |
|
3925 return res |
|
3926 |
|
3927 def load(self, path): |
|
3928 """ |
|
3929 Load an object from a reference. |
|
3930 @param path: The reference where to load the object |
|
3931 @raise StorageException: if the given object cannot be loaded as an object from this storage |
|
3932 """ |
|
3933 with currentdir(self.storage, self.curpath): |
|
3934 res = self.storage.load(path) |
|
3935 return res |
|
3936 |
|
3937 path = property(get_path, set_path) |
|
3938 |
|
3939 |
|
3940 class CompositeLayer(Folder): |
2788 """ |
3941 """ |
2789 A base class for composite Configuration objects. |
3942 A base class for composite Configuration objects. |
2790 """ |
3943 """ |
2791 def __init__(self, path="", **kwargs): |
3944 def __init__(self, storage, path="", **kwargs): |
|
3945 super(CompositeLayer, self).__init__(storage, path, **kwargs) |
2792 self.layers = kwargs.get('layers', []) |
3946 self.layers = kwargs.get('layers', []) |
2793 self.path = path |
3947 self.path = path |
2794 |
3948 |
2795 def add_layer(self, layer): |
3949 def add_layer(self, layer): |
2796 self.layers.append(layer) |
3950 self.layers.append(layer) |
2848 for layerpath in self.list_layers(): |
4002 for layerpath in self.list_layers(): |
2849 for respath in self.get_layer(layerpath).list_doc(): |
4003 for respath in self.get_layer(layerpath).list_doc(): |
2850 lres.append(utils.resourceref.join_refs([layerpath, respath])) |
4004 lres.append(utils.resourceref.join_refs([layerpath, respath])) |
2851 return lres |
4005 return lres |
2852 |
4006 |
2853 def list_all_resources(self, empty_folders=False): |
4007 def list_all_resources(self, **kwargs): |
2854 """ |
4008 """ |
2855 Returns a list of all layer related resource paths with full path in the storage. |
4009 Returns a list of all layer related resource paths with full path in the storage. |
2856 """ |
4010 """ |
2857 lres = [] |
4011 lres = [] |
2858 for layerpath in self.list_layers(): |
4012 for layerpath in self.list_layers(): |
2859 sublayer = self.get_layer(layerpath) |
4013 sublayer = self.get_layer(layerpath) |
2860 for respath in sublayer.list_all_resources(empty_folders): |
4014 for respath in sublayer.list_all_resources(**kwargs): |
2861 lres.append(utils.resourceref.join_refs([layerpath, respath])) |
4015 lres.append(utils.resourceref.join_refs([layerpath, respath])) |
2862 |
|
2863 return lres |
4016 return lres |
2864 |
4017 |
|
4018 def list_all_related(self, **kwargs): |
|
4019 """ |
|
4020 Returns a list of all (non confml) layer related resource paths with full path in the storage. |
|
4021 """ |
|
4022 lres = [] |
|
4023 for layerpath in self.list_layers(): |
|
4024 sublayer = self.get_layer(layerpath) |
|
4025 for respath in sublayer.list_all_related(**kwargs): |
|
4026 lres.append(utils.resourceref.join_refs([layerpath, respath])) |
|
4027 |
|
4028 return lres |
|
4029 |
2865 class Layer(CompositeLayer): |
4030 class Layer(CompositeLayer): |
2866 """ |
4031 """ |
2867 A Layer object is a subfolder of a Storage, offering access to part of the Storages resources. |
4032 A Layer object is a subfolder of a Storage, offering access to part of the Storages resources. |
2868 """ |
4033 """ |
2869 def __init__(self, storage, path, **kwargs): |
4034 def __init__(self, storage, path, **kwargs): |
2892 self.predefined[pretag] = kwargs.get(pretag, prevalue) |
4055 self.predefined[pretag] = kwargs.get(pretag, prevalue) |
2893 |
4056 |
2894 def __getattr__(self, name): |
4057 def __getattr__(self, name): |
2895 return getattr(self.storage, name) |
4058 return getattr(self.storage, name) |
2896 |
4059 |
|
4060 def __getstate__(self): |
|
4061 state = {} |
|
4062 state['predefined'] = self.predefined |
|
4063 state['path'] = self.path |
|
4064 state['layers'] = self.layers |
|
4065 return state |
|
4066 |
|
4067 def __setstate__(self, state): |
|
4068 state = {} |
|
4069 self.predefined = state.get('predefined',{}) |
|
4070 self.path = state.get('path','') |
|
4071 self.layers = state.get('layers',[]) |
|
4072 |
|
4073 return state |
|
4074 |
2897 def list_confml(self): |
4075 def list_confml(self): |
2898 """ |
4076 """ |
2899 @return: array of confml file references. |
4077 @return: array of confml file references. |
2900 """ |
4078 """ |
2901 res = self.storage.list_resources(self.predefined['confml_path'], True) |
4079 res = self.list_resources(self.predefined['confml_path'], recurse=True) |
2902 res += super(Layer, self).list_confml() |
4080 res += super(Layer, self).list_confml() |
2903 return res |
4081 return res |
2904 |
4082 |
2905 def list_implml(self): |
4083 def list_implml(self): |
2906 """ |
4084 """ |
2907 @return: array of implml file references. |
4085 @return: array of implml file references. |
2908 """ |
4086 """ |
2909 res = self.storage.list_resources(self.predefined['implml_path'], True) |
4087 res = self.list_resources(self.predefined['implml_path'], recurse=True) |
2910 res += super(Layer, self).list_implml() |
4088 res += super(Layer, self).list_implml() |
2911 return res |
4089 return res |
2912 |
4090 |
2913 def list_content(self): |
4091 def list_content(self): |
2914 """ |
4092 """ |
2915 @return: array of content file references. |
4093 @return: array of content file references. |
2916 """ |
4094 """ |
2917 res = self.storage.list_resources(self.predefined['content_path'], True) |
4095 res = self.list_resources(self.predefined['content_path'], recurse=True) |
2918 res += super(Layer, self).list_content() |
4096 res += super(Layer, self).list_content() |
2919 return res |
4097 return res |
2920 |
4098 |
2921 def list_doc(self): |
4099 def list_doc(self): |
2922 """ |
4100 """ |
2923 @return: array of document file references. |
4101 @return: array of document file references. |
2924 """ |
4102 """ |
2925 res = self.storage.list_resources(self.predefined['doc_path'], True) |
4103 res = self.list_resources(self.predefined['doc_path'], recurse=True) |
2926 res += super(Layer, self).list_doc() |
4104 res += super(Layer, self).list_doc() |
2927 return res |
4105 return res |
2928 |
4106 |
2929 def confml_folder(self): |
4107 def confml_folder(self): |
2930 cpath = self.storage.get_current_path() |
4108 cpath = self.get_current_path() |
2931 spath = self.predefined['confml_path'] |
4109 spath = self.predefined['confml_path'] |
2932 return Folder(self.storage, utils.resourceref.join_refs([cpath, spath])) |
4110 return Folder(self.storage, utils.resourceref.join_refs([cpath, spath])) |
2933 |
4111 |
2934 def implml_folder(self): |
4112 def implml_folder(self): |
2935 cpath = self.storage.get_current_path() |
4113 cpath = self.get_current_path() |
2936 spath = self.predefined['implml_path'] |
4114 spath = self.predefined['implml_path'] |
2937 return Folder(self.storage, utils.resourceref.join_refs([cpath, spath])) |
4115 return Folder(self.storage, utils.resourceref.join_refs([cpath, spath])) |
2938 |
4116 |
2939 def content_folder(self): |
4117 def content_folder(self): |
2940 cpath = self.storage.get_current_path() |
4118 cpath = self.get_current_path() |
2941 spath = self.predefined['content_path'] |
4119 spath = self.predefined['content_path'] |
2942 return Folder(self.storage, utils.resourceref.join_refs([cpath, spath])) |
4120 return Folder(self.storage, utils.resourceref.join_refs([cpath, spath])) |
2943 |
4121 |
2944 def doc_folder(self): |
4122 def doc_folder(self): |
2945 cpath = self.storage.get_current_path() |
4123 cpath = self.get_current_path() |
2946 spath = self.predefined['doc_path'] |
4124 spath = self.predefined['doc_path'] |
2947 return Folder(self.storage, utils.resourceref.join_refs([cpath, spath])) |
4125 return Folder(self.storage, utils.resourceref.join_refs([cpath, spath])) |
2948 |
4126 |
2949 def list_all_resources(self, empty_folders=False): |
4127 def list_all_resources(self, **kwargs): |
2950 """ |
4128 """ |
2951 Returns a list of all layer related resource paths with full path in the storage. |
4129 Returns a list of all layer related resource paths with full path in the storage. |
2952 """ |
4130 """ |
2953 lres = [] |
4131 lres = [] |
2954 mypath = self.get_current_path() |
|
2955 |
|
2956 for folderpath in sorted(self.predefined.values()): |
4132 for folderpath in sorted(self.predefined.values()): |
2957 lres += self.storage.list_resources(folderpath, recurse=True, empty_folders=empty_folders) |
4133 lres += self.list_resources(folderpath, recurse=True) |
2958 |
4134 |
2959 lres += super(Layer, self).list_all_resources(empty_folders) |
4135 lres += super(Layer, self).list_all_resources() |
2960 |
|
2961 return lres |
4136 return lres |
2962 |
4137 |
2963 def list_all_related(self, empty_folders=False): |
4138 def list_all_related(self, **kwargs): |
2964 """ |
4139 """ |
2965 Returns a list of all (non confml) layer related resource paths with full path in the storage. |
4140 Returns a list of all (non confml) layer related resource paths with full path in the storage. |
2966 """ |
4141 """ |
|
4142 |
2967 lres = [] |
4143 lres = [] |
|
4144 exclude_filters = kwargs.get('exclude_filters', {}) |
|
4145 kwargs['recurse'] = True |
2968 predef = self.predefined.copy() |
4146 predef = self.predefined.copy() |
2969 del predef['confml_path'] |
4147 del predef['confml_path'] |
2970 mypath = self.get_current_path() |
|
2971 for folderpath in sorted(predef.values()): |
4148 for folderpath in sorted(predef.values()): |
2972 lres += self.storage.list_resources(folderpath, recurse=True, empty_folders=empty_folders) |
4149 filter = exclude_filters.get(folderpath, None) |
2973 lres += super(Layer, self).list_all_resources(empty_folders=empty_folders) |
4150 resources = self.list_resources(folderpath, **kwargs) |
|
4151 if filter: |
|
4152 lres += [res for res in resources if not re.search(filter, res, re.IGNORECASE)] |
|
4153 else: |
|
4154 lres += resources |
|
4155 lres += super(Layer, self).list_all_related(**kwargs) |
2974 |
4156 |
2975 return lres |
4157 return lres |
|
4158 |
|
4159 |
|
4160 class Include(Base, container.LoadLink): |
|
4161 """ |
|
4162 A common include element that automatically loads a resource |
|
4163 and its object under this include element. |
|
4164 """ |
|
4165 def __init__(self, ref="", **kwargs): |
|
4166 path = kwargs.get('path') or ref |
|
4167 store_interface = kwargs.get('store_interface',None) |
|
4168 ref = utils.resourceref.to_objref(path) |
|
4169 container.LoadLink.__init__(self, path, store_interface) |
|
4170 Base.__init__(self, ref) |
|
4171 |
|
4172 def get_store_interface(self): |
|
4173 if not self._storeint and self._parent: |
|
4174 try: |
|
4175 self._storeint = self._parent.get_store_interface() |
|
4176 except exceptions.NotFound: |
|
4177 # If project is not found, let the store interface be None |
|
4178 pass |
|
4179 return self._storeint |
2976 |
4180 |
2977 |
4181 |
2978 class Rule(object): |
4182 class Rule(object): |
2979 """ |
4183 """ |
2980 Base class for Rules in the system. |
4184 Base class for Rules in the system. |
3005 """ |
4209 """ |
3006 mapmodule = __import__('cone.public.mapping') |
4210 mapmodule = __import__('cone.public.mapping') |
3007 return mapmodule.public.mapping.BaseMapper() |
4211 return mapmodule.public.mapping.BaseMapper() |
3008 |
4212 |
3009 |
4213 |
3010 ################################################################## |
4214 class Problem(object): |
|
4215 SEVERITY_ERROR = "error" |
|
4216 SEVERITY_WARNING = "warning" |
|
4217 SEVERITY_INFO = "info" |
|
4218 |
|
4219 def __init__(self, msg, **kwargs): |
|
4220 self.msg = msg |
|
4221 self.type = kwargs.get('type', '') |
|
4222 self.line = kwargs.get('line', None) |
|
4223 self.file = kwargs.get('file', None) |
|
4224 self.severity = kwargs.get('severity', self.SEVERITY_ERROR) |
|
4225 self.traceback = kwargs.get('traceback', None) |
|
4226 # A slot for any problem specific data |
|
4227 self.problem_data = kwargs.get('problem_data', None) |
|
4228 |
|
4229 def log(self, logger, current_file=None): |
|
4230 """ |
|
4231 Log this problem with the given logger. |
|
4232 """ |
|
4233 file = self.file or current_file |
|
4234 if self.line is None: |
|
4235 msg = "(%s) %s" % (file, self.msg) |
|
4236 else: |
|
4237 msg = "(%s:%d) %s" % (file, self.line, self.msg) |
|
4238 |
|
4239 mapping = {self.SEVERITY_ERROR: logging.ERROR, |
|
4240 self.SEVERITY_WARNING: logging.WARNING, |
|
4241 self.SEVERITY_INFO: logging.INFO} |
|
4242 level = mapping.get(self.severity, logging.ERROR) |
|
4243 logger.log(level, msg) |
|
4244 |
|
4245 if self.traceback: |
|
4246 logger.debug(self.traceback) |
|
4247 |
|
4248 @classmethod |
|
4249 def from_exception(cls, ex): |
|
4250 """ |
|
4251 Create a Problem object from an exception instance. |
|
4252 |
|
4253 If the exception is a sub-class of ConeException, then it may contain |
|
4254 extra information (like a line number) for the problem. |
|
4255 """ |
|
4256 if isinstance(ex, exceptions.ConeException): |
|
4257 return Problem(msg = ex.problem_msg or unicode(ex), |
|
4258 type = ex.problem_type or '', |
|
4259 line = ex.problem_lineno, |
|
4260 severity = cls.SEVERITY_ERROR) |
|
4261 else: |
|
4262 return Problem(msg = unicode(ex), |
|
4263 severity = cls.SEVERITY_ERROR) |
|
4264 |
|
4265 def __repr__(self): |
|
4266 var_data = [] |
|
4267 for varname in ('msg', 'type', 'line', 'file', 'severity'): |
|
4268 var_data.append("%s=%r" % (varname, getattr(self, varname))) |
|
4269 return "%s(%s)" % (self.__class__.__name__, ', '.join(var_data)) |
|
4270 |
|
4271 def __eq__(self, other): |
|
4272 if not isinstance(other, Problem): |
|
4273 return False |
|
4274 for varname in ('msg', 'type', 'line', 'file', 'severity'): |
|
4275 self_val = getattr(self, varname) |
|
4276 other_val = getattr(other, varname) |
|
4277 if self_val != other_val: |
|
4278 return False |
|
4279 return True |
|
4280 |
|
4281 def __ne__(self, other): |
|
4282 return self == other |
|
4283 |
|
4284 def __lt__(self, other): |
|
4285 if not isinstance(other, Problem): |
|
4286 return False |
|
4287 return (self.file, self.line) < (other.file, other.line) |
|
4288 |
|
4289 def make_content_info(resource, data): |
|
4290 """ |
|
4291 Factory for ContentInfo |
|
4292 """ |
|
4293 cnt_inf = None |
|
4294 |
|
4295 if resource != None: |
|
4296 guessed_type = mimetypes.guess_type(resource.get_path()) |
|
4297 mimetype = None |
|
4298 mimesubtype = None |
|
4299 |
|
4300 if guessed_type != None: |
|
4301 mimetype, mimesubtype = guessed_type[0].split('/') |
|
4302 |
|
4303 if mimetype == 'image' and mimesubtype == 'x-ms-bmp': |
|
4304 cnt_inf = BmpImageContentInfo(resource, data) |
|
4305 else: |
|
4306 cnt_inf = ContentInfo(mimetype, mimesubtype) |
|
4307 return cnt_inf |
|
4308 |
|
4309 def open_storage(path, mode="r", **kwargs): |
|
4310 return Storage.open(path, mode="r", **kwargs) |
|
4311 |
3011 class NullHandler(logging.Handler): |
4312 class NullHandler(logging.Handler): |
3012 """ |
4313 """ |
3013 Default handler that does not do anything. |
4314 Default handler that does not do anything. |
3014 """ |
4315 """ |
3015 def emit(self, record): |
4316 def emit(self, record): |