def _adaptWFDataForItemsAndMeetings(self): """We use PM default WFs, no more meetingcommunes(item)_workflow... Adapt: - workflow_history for items and meetings; - takenOverByInfos for items.""" logger.info('Updating WF history items and meetings to use new WF id...') wfTool = api.portal.get_tool('portal_workflow') catalog = api.portal.get_tool('portal_catalog') for cfg in self.tool.objectValues('MeetingConfig'): # this will call especially part where we duplicate WF and apply WFAdaptations cfg.registerPortalTypes() itemWFId = cfg.getItemWorkflow() for brain in catalog(portal_type=(cfg.getItemTypeName(), cfg.getMeetingTypeName())): itemOrMeeting = brain.getObject() itemOrMeetingWFId = wfTool.getWorkflowsFor(itemOrMeeting)[0].getId() if itemOrMeetingWFId not in itemOrMeeting.workflow_history: wf_history_key = self._get_wh_key(itemOrMeeting) itemOrMeeting.workflow_history[itemOrMeetingWFId] = \ tuple(itemOrMeeting.workflow_history[wf_history_key]) del itemOrMeeting.workflow_history[wf_history_key] # do this so change is persisted itemOrMeeting.workflow_history = itemOrMeeting.workflow_history else: # already migrated break if itemOrMeeting.__class__.__name__ == 'MeetingItem': takenOverByInfos = itemOrMeeting.takenOverByInfos.copy() newTakenOverByInfos = PersistentMapping() for k, v in takenOverByInfos.items(): wf_name, state = k.split('__wfstate__') newTakenOverByInfos['{0}__wfstate__{1}'.format(itemWFId, state)] = v if sorted(newTakenOverByInfos.keys()) != sorted(takenOverByInfos.keys()): itemOrMeeting.takenOverByInfos = newTakenOverByInfos logger.info('Done.')
def test_persistent_mapping(self): value = PersistentMapping({'foo': 'bar'}) self.assertEquals({u'foo': u'bar'}, json_compatible(value)) self.assertEquals('{"foo": "bar"}', json.dumps(json_compatible(value))) self.assertIsInstance(json_compatible(value.keys()[0]), unicode, 'Dict keys should be converted recursively.') self.assertIsInstance(json_compatible(value.values()[0]), unicode, 'Dict values should be converted recursively.')
def upgrade_carousel_tiles_custom_url(context): # Get covers covers = context.portal_catalog(portal_type='collective.cover.content') logger.info('About to update %s covers' % len(covers)) for cover in covers: obj = cover.getObject() tile_ids = obj.list_tiles(types=[ u'collective.cover.carousel', u'collective.cover.list' ]) for tile_id in tile_ids: tile = obj.get_tile(tile_id) old_data = ITileDataManager(tile).get() uuids = old_data['uuids'] if isinstance(uuids, PersistentMapping): # This tile is fixed, carry on logger.info( 'Tile %s at %s was already updated' % (tile_id, cover.getPath()) ) continue if not uuids: # This tile did not have data, so ignore logger.info( 'Tile %s at %s did not have any data' % (tile_id, cover.getPath()) ) continue new_data = PersistentMapping() order = 0 for uuid in uuids: if uuid not in new_data.keys(): entry = PersistentMapping() entry[u'order'] = unicode(order) new_data[uuid] = entry order += 1 old_data['uuids'] = new_data ITileDataManager(tile).set(old_data) logger.info( 'Tile %s at %s updated' % (tile_id, cover.getPath()) ) logger.info('Done')
def checkBasicOps(self): from persistent.mapping import PersistentMapping m = PersistentMapping({'x': 1}, a=2, b=3) m['name'] = 'bob' self.assertEqual(m['name'], "bob") self.assertEqual(m.get('name', 42), "bob") self.assert_('name' in m) try: m['fred'] except KeyError: pass else: self.fail("expected KeyError") self.assert_('fred' not in m) self.assertEqual(m.get('fred'), None) self.assertEqual(m.get('fred', 42), 42) keys = m.keys() keys.sort() self.assertEqual(keys, ['a', 'b', 'name', 'x']) values = m.values() values.sort() self.assertEqual(values, [1, 2, 3, 'bob']) items = m.items() items.sort() self.assertEqual(items, [('a', 2), ('b', 3), ('name', 'bob'), ('x', 1)]) keys = list(m.iterkeys()) keys.sort() self.assertEqual(keys, ['a', 'b', 'name', 'x']) values = list(m.itervalues()) values.sort() self.assertEqual(values, [1, 2, 3, 'bob']) items = list(m.iteritems()) items.sort() self.assertEqual(items, [('a', 2), ('b', 3), ('name', 'bob'), ('x', 1)])
def checkBasicOps(self): from persistent.mapping import PersistentMapping m = PersistentMapping({"x": 1}, a=2, b=3) m["name"] = "bob" self.assertEqual(m["name"], "bob") self.assertEqual(m.get("name", 42), "bob") self.assert_("name" in m) try: m["fred"] except KeyError: pass else: self.fail("expected KeyError") self.assert_("fred" not in m) self.assertEqual(m.get("fred"), None) self.assertEqual(m.get("fred", 42), 42) keys = m.keys() keys.sort() self.assertEqual(keys, ["a", "b", "name", "x"]) values = m.values() values.sort() self.assertEqual(values, [1, 2, 3, "bob"]) items = m.items() items.sort() self.assertEqual(items, [("a", 2), ("b", 3), ("name", "bob"), ("x", 1)]) keys = list(m.iterkeys()) keys.sort() self.assertEqual(keys, ["a", "b", "name", "x"]) values = list(m.itervalues()) values.sort() self.assertEqual(values, [1, 2, 3, "bob"]) items = list(m.iteritems()) items.sort() self.assertEqual(items, [("a", 2), ("b", 3), ("name", "bob"), ("x", 1)])
class BibliographyTool(UniqueObject, Folder, ## ActionProviderBase, DuplicatesCriteriaManager): """Tool for managing import and export functionality as well as some resources of the BibliographyFolders and -Entries. """ implements(IBibliographyTool) __allow_access_to_unprotected_subobjects__ = 1 id = 'portal_bibliography' meta_type = 'Bibliography Tool' show_isbn_link = 0 allow_folder_intro = 0 bibfolders_translatable = 1 bibrefitems_translatable = 1 support_member_references = False default_idcooker_id = 'etal' use_pids_on_import = True cook_ids_on_bibref_creation = False cook_ids_after_bibref_edit = False synchronize_pdffile_attributes = False enable_duplicates_manager = True member_types = [] sort_members_on = '' select_members_attr = '' members_search_on_attr = '' infer_author_references_after_edit = True infer_author_references_after_import = True authorof_implies_owner = False authorof_implies_creator = False allow_pdfupload_portal_policy = True allow_pdfupload_for_types = REFERENCE_TYPES searchable_bibfolders = True preprint_servers = [] allow_additional_fields = False additional_fields = ['howpublished','recommendedby'] # just an example security = ClassSecurityInfo() security.declareObjectProtected(View) manage_options = ( (Folder.manage_options[0],) + DuplicatesCriteriaManager.manage_options + Folder.manage_options[2:] ) _properties = Folder._properties + ( {'id':'default_idcooker_id', 'type':'selection', 'select_variable':'listIdCookers', 'mode':'w', }, {'id':'cook_ids_on_bibref_creation', 'type':'boolean', 'mode':'w', }, {'id':'cook_ids_after_bibref_edit', 'type':'boolean', 'mode':'w', }, {'id':'use_pids_on_import', 'type':'boolean', 'mode':'w', }, {'id':'synchronize_pdffile_attributes', 'type':'boolean', 'mode':'w', }, {'id':'enable_duplicates_manager', 'type':'boolean', 'mode':'w', }, {'id':'allow_folder_intro', 'type':'boolean', 'mode':'w', }, {'id':'allow_pdfupload_portal_policy', 'type':'boolean', 'mode':'w', }, {'id':'allow_pdfupload_for_types', 'type':'multiple selection', 'select_variable':'getReferenceTypes', 'mode':'w', }, {'id':'bibfolders_translatable', 'type':'boolean', 'mode':'w', }, {'id':'bibrefitems_translatable', 'type':'boolean', 'mode':'w', }, {'id':'support_member_references', 'type':'boolean', 'mode':'w', }, {'id':'member_types', 'type':'multiple selection', 'select_variable':'getPortalTypeNames', 'mode':'w', }, {'id':'sort_members_on', 'type':'selection', 'select_variable':'getFieldIndexes', 'mode':'w', }, {'id':'select_members_attr', 'type':'selection', 'select_variable':'getMetaDataColumns', 'mode':'w', }, {'id':'members_search_on_attr', 'type':'selection', 'select_variable':'getTextIndexes', 'mode':'w', }, {'id':'infer_author_references_after_edit', 'type':'boolean', 'mode':'w', }, {'id':'infer_author_references_after_import', 'type':'boolean', 'mode':'w', }, {'id':'authorof_implies_owner', 'type':'boolean', 'mode':'w', }, {'id':'authorof_implies_creator', 'type':'boolean', 'mode':'w', }, {'id':'show_isbn_link', 'type':'boolean', 'mode':'w', }, {'id':'preprint_servers', 'type':'lines', 'mode':'w', }, {'id':'searchable_bibfolders', 'type':'boolean', 'mode':'w', }, {'id':'allow_additional_fields', 'type':'boolean', 'mode':'w', }, {'id':'additional_fields', 'type':'lines', 'mode':'w', }, ) _match_criteria = {} _default_criteria = ('bibliography type',) def __init__(self): self._setObject('IdCookers', IdCookerFolder('IdCookers', '')) DuplicatesCriteriaManager.__init__(self) # Add the local reference types registry self._reference_types = PersistentMapping() # Populate it initially with those types declared in config.py for ref_type in REFERENCE_TYPES: self._reference_types[ref_type] = None def isBibFolderTranslatable(self): """ return what is in bibfolders_translatable property this is only half of the truth!!! (ITranslatable) """ return self.bibfolders_translatable def isBibrefItemTranslatable(self): """ return what is in bibrefitems_translatable property this is only half of the truth!!! (ITranslatable) """ return self.bibrefitems_translatable security.declarePublic('getMemberTypes') def getMemberTypes(self, default=()): member_types = self.getProperty('member_types', default) if not isinstance(member_types, (list, tuple)): return (member_types,) else: return member_types security.declarePublic('getSortMembersOn') def getSortMembersOn(self, default='getId'): return self.getProperty('sort_members_on', default) security.declarePublic('getSelectMembersAttr') def getSelectMembersAttr(self, default='Title'): return self.getProperty('select_members_attr', default) security.declarePublic('getMembersSearchOnAttr') def getMembersSearchOnAttr(self, default='Title'): return self.getProperty('members_search_on_attr', default) security.declarePublic('getReferenceTypes') def getReferenceTypes(self, display=False): """ returns a list with the names (meta types) of the currently registered reference types of a BibliographyFolder """ if display: return DisplayList(tuple([ (key, key) for key in self.getReferenceTypes() ])) else: return self._reference_types.keys() security.declarePublic('getBibFolderTypes') def getBibFolderTypes(self): """ returns a list with the names (meta types) of the currently registered bibfolder types """ return BIBFOLDER_TYPES security.declareProtected(permissions.ManageReferenceTypes, 'registerReferenceType') def registerReferenceType(self, portal_type): """Add portal_type to the list that should be considered references for this plone instance. Do not fail on duplicates. """ # self._reference_types is a PersistentMapping self._reference_types[portal_type] = None security.declareProtected(permissions.ManageReferenceTypes, 'unregisterReferenceType') def unregisterReferenceType(self, portal_type): """Remove portal_type from the list that should be considered references for this plone instance. Do not fail if the type is not already registered. """ # self._reference_types is a PersistentMapping try: del self._reference_types[portal_type] except KeyError: pass security.declarePublic('getImportFormatNames') def getImportFormatNames(self, with_unavailables=False, with_disabled=False): """ returns a list with the names of the supported import formats """ parsers = component.getAllUtilitiesRegisteredFor(IBibliographyParser) return [parser.getFormatName() \ for parser in parsers if (parser.isAvailable() or with_unavailables) and (parser.isEnabled() or with_disabled) ] security.declarePublic('getImportFormatExtensions') def getImportFormatExtensions(self, with_unavailables=False, with_disabled=False): """ returns a list with the file name extensions of the supported import formats """ parsers = component.getAllUtilitiesRegisteredFor(IBibliographyParser) return [parser.getFormatExtension() \ for parser in parsers if (parser.isAvailable() or with_unavailables) and (self.isParserEnabled(parser.getFormatName()) or with_disabled)] def getImportFormatDescriptions(self, with_unavailables=False, with_disabled=False): """ returns a list with the description texts of the supported import formats """ parsers = component.getAllUtilitiesRegisteredFor(IBibliographyParser) return [parser.Description() \ for parser in parsers if (parser.isAvailable() or with_unavailables) and (parser.isEnabled() or with_disabled) ] security.declarePublic('getExportFormatNames') def getExportFormatNames(self, with_unavailables=False, with_disabled=False): """ returns a list with the names of the supported export formats """ utils = component.getAllUtilitiesRegisteredFor(IBibliographyRenderer) return [ renderer.__name__ for renderer in utils if (renderer.available or with_unavailables) and (self.isRendererEnabled(renderer.__name__) or with_disabled) ] security.declarePublic('getExportFormatExtensions') def getExportFormatExtensions(self, with_unavailables=False, with_disabled=False): """ returns a list with the file name extensions of the supported export formats """ utils = component.getAllUtilitiesRegisteredFor(IBibliographyRenderer) return [ renderer.target_format for renderer in utils if (renderer.available or with_unavailables) and (self.isRendererEnabled(renderer.__name__) or with_disabled) ] def getExportFormatDescriptions(self, with_unavailables=False, with_disabled=False): """ returns a list with the description texts of the supported export formats """ utils = component.getAllUtilitiesRegisteredFor(IBibliographyRenderer) return [ renderer.description for renderer in utils if (renderer.available or with_unavailables) and (self.isRendererEnabled(renderer.__name__) or with_disabled) ] security.declarePublic('getExportFormats') def getExportFormats(self, with_unavailables=False, with_disabled=False): """ returns a list of (name, extension, description) tuples of the supported export formats """ export_formats = zip( self.getExportFormatNames(with_unavailables=with_unavailables, with_disabled=with_disabled), self.getExportFormatExtensions(with_unavailables=with_unavailables, with_disabled=with_disabled), self.getExportFormatDescriptions(with_unavailables=with_unavailables, with_disabled=with_disabled)) export_formats.sort() return export_formats security.declarePublic('getImportFormats') def getImportFormats(self, with_unavailables=False, with_disabled=False): """ returns a list of (name, extension, description) tuples of the supported import formats """ supported_parsers = zip(self.getImportFormatNames(with_unavailables=with_unavailables, with_disabled=with_disabled), self.getImportFormatExtensions(with_unavailables=with_unavailables, with_disabled=with_disabled), self.getImportFormatDescriptions(with_unavailables=with_unavailables, with_disabled=with_disabled)) supported_parsers.sort() return supported_parsers security.declareProtected(View, 'render') def render(self, entry, format='', output_encoding=None, **kw): """ renders a BibliographyEntry object in the specified format """ renderer = self.getRenderer(format=format, **kw) if renderer: return renderer.render(entry, output_encoding=output_encoding, **kw) else: return None security.declareProtected(View, 'isParserEnabled') def isParserEnabled(self, name): """ Check cmfbibat propertysheet """ return self.getSheetProperty(name, 'parser_enabled') security.declareProtected(View, 'isRendererEnabled') def isRendererEnabled(self, name): """ Check cmfbibat propertysheet """ return self.getSheetProperty(name, 'renderer_enabled') security.declareProtected(View, 'getRenderer') def getRenderer(self, format, with_unavailables=False, with_disabled=False, **kw): """ returns the renderer for the specified format first looks for a renderer with the 'format' name next looks for a renderer with the 'format' extension """ utils = component.getAllUtilitiesRegisteredFor(IBibliographyRenderer) for renderer in utils: if (renderer.available or with_unavailables) and \ (renderer.enabled or with_disabled): if format.lower() == renderer.__name__.lower(): return renderer.__of__(self) if format.lower() == renderer.target_format.lower(): return renderer.__of__(self) return None security.declareProtected(View, 'getEntries') def getEntries(self, source, format, file_name=None, input_encoding='utf-8'): """ main routine to be called from BibliographyFolders returns a list with the parsed entries """ source = self.checkEncoding(source, input_encoding) format = self.checkFormat(source, format, file_name) parser = self.getParser(format) if parser: try: return parser.getEntries(source) except Exception, e: LOG.error('Import error while importing file (%s)' % e, exc_info=True) raise RuntimeError('An error occured (%s) - please check the log file for details' % e) else:
class BibliographyTool( UniqueObject, Folder, ## ActionProviderBase, DuplicatesCriteriaManager): """Tool for managing import and export functionality as well as some resources of the BibliographyFolders and -Entries. """ implements(IBibliographyTool) __allow_access_to_unprotected_subobjects__ = 1 id = 'portal_bibliography' meta_type = 'Bibliography Tool' show_isbn_link = 0 allow_folder_intro = 0 bibfolders_translatable = 1 bibrefitems_translatable = 1 support_member_references = False default_idcooker_id = 'etal' use_pids_on_import = True cook_ids_on_bibref_creation = False cook_ids_after_bibref_edit = False synchronize_pdffile_attributes = False enable_duplicates_manager = True member_types = [] sort_members_on = '' select_members_attr = '' members_search_on_attr = '' infer_author_references_after_edit = True infer_author_references_after_import = True authorof_implies_owner = False authorof_implies_creator = False allow_pdfupload_portal_policy = True allow_pdfupload_for_types = REFERENCE_TYPES searchable_bibfolders = True preprint_servers = [] allow_additional_fields = False additional_fields = ['howpublished', 'recommendedby'] # just an example security = ClassSecurityInfo() security.declareObjectProtected(View) manage_options = ((Folder.manage_options[0], ) + DuplicatesCriteriaManager.manage_options + Folder.manage_options[2:]) _properties = Folder._properties + ( { 'id': 'default_idcooker_id', 'type': 'selection', 'select_variable': 'listIdCookers', 'mode': 'w', }, { 'id': 'cook_ids_on_bibref_creation', 'type': 'boolean', 'mode': 'w', }, { 'id': 'cook_ids_after_bibref_edit', 'type': 'boolean', 'mode': 'w', }, { 'id': 'use_pids_on_import', 'type': 'boolean', 'mode': 'w', }, { 'id': 'synchronize_pdffile_attributes', 'type': 'boolean', 'mode': 'w', }, { 'id': 'enable_duplicates_manager', 'type': 'boolean', 'mode': 'w', }, { 'id': 'allow_folder_intro', 'type': 'boolean', 'mode': 'w', }, { 'id': 'allow_pdfupload_portal_policy', 'type': 'boolean', 'mode': 'w', }, { 'id': 'allow_pdfupload_for_types', 'type': 'multiple selection', 'select_variable': 'getReferenceTypes', 'mode': 'w', }, { 'id': 'bibfolders_translatable', 'type': 'boolean', 'mode': 'w', }, { 'id': 'bibrefitems_translatable', 'type': 'boolean', 'mode': 'w', }, { 'id': 'support_member_references', 'type': 'boolean', 'mode': 'w', }, { 'id': 'member_types', 'type': 'multiple selection', 'select_variable': 'getPortalTypeNames', 'mode': 'w', }, { 'id': 'sort_members_on', 'type': 'selection', 'select_variable': 'getFieldIndexes', 'mode': 'w', }, { 'id': 'select_members_attr', 'type': 'selection', 'select_variable': 'getMetaDataColumns', 'mode': 'w', }, { 'id': 'members_search_on_attr', 'type': 'selection', 'select_variable': 'getTextIndexes', 'mode': 'w', }, { 'id': 'infer_author_references_after_edit', 'type': 'boolean', 'mode': 'w', }, { 'id': 'infer_author_references_after_import', 'type': 'boolean', 'mode': 'w', }, { 'id': 'authorof_implies_owner', 'type': 'boolean', 'mode': 'w', }, { 'id': 'authorof_implies_creator', 'type': 'boolean', 'mode': 'w', }, { 'id': 'show_isbn_link', 'type': 'boolean', 'mode': 'w', }, { 'id': 'preprint_servers', 'type': 'lines', 'mode': 'w', }, { 'id': 'searchable_bibfolders', 'type': 'boolean', 'mode': 'w', }, { 'id': 'allow_additional_fields', 'type': 'boolean', 'mode': 'w', }, { 'id': 'additional_fields', 'type': 'lines', 'mode': 'w', }, ) _match_criteria = {} _default_criteria = ('bibliography type', ) def __init__(self): self._setObject('IdCookers', IdCookerFolder('IdCookers', '')) DuplicatesCriteriaManager.__init__(self) # Add the local reference types registry self._reference_types = PersistentMapping() # Populate it initially with those types declared in config.py for ref_type in REFERENCE_TYPES: self._reference_types[ref_type] = None def isBibFolderTranslatable(self): """ return what is in bibfolders_translatable property this is only half of the truth!!! (ITranslatable) """ return self.bibfolders_translatable def isBibrefItemTranslatable(self): """ return what is in bibrefitems_translatable property this is only half of the truth!!! (ITranslatable) """ return self.bibrefitems_translatable security.declarePublic('getMemberTypes') def getMemberTypes(self, default=()): member_types = self.getProperty('member_types', default) if not isinstance(member_types, (list, tuple)): return (member_types, ) else: return member_types security.declarePublic('getSortMembersOn') def getSortMembersOn(self, default='getId'): return self.getProperty('sort_members_on', default) security.declarePublic('getSelectMembersAttr') def getSelectMembersAttr(self, default='Title'): return self.getProperty('select_members_attr', default) security.declarePublic('getMembersSearchOnAttr') def getMembersSearchOnAttr(self, default='Title'): return self.getProperty('members_search_on_attr', default) security.declarePublic('getReferenceTypes') def getReferenceTypes(self, display=False): """ returns a list with the names (meta types) of the currently registered reference types of a BibliographyFolder """ if display: return DisplayList( tuple([(key, key) for key in self.getReferenceTypes()])) else: return self._reference_types.keys() security.declarePublic('getBibFolderTypes') def getBibFolderTypes(self): """ returns a list with the names (meta types) of the currently registered bibfolder types """ return BIBFOLDER_TYPES security.declareProtected(permissions.ManageReferenceTypes, 'registerReferenceType') def registerReferenceType(self, portal_type): """Add portal_type to the list that should be considered references for this plone instance. Do not fail on duplicates. """ # self._reference_types is a PersistentMapping self._reference_types[portal_type] = None security.declareProtected(permissions.ManageReferenceTypes, 'unregisterReferenceType') def unregisterReferenceType(self, portal_type): """Remove portal_type from the list that should be considered references for this plone instance. Do not fail if the type is not already registered. """ # self._reference_types is a PersistentMapping try: del self._reference_types[portal_type] except KeyError: pass security.declarePublic('getImportFormatNames') def getImportFormatNames(self, with_unavailables=False, with_disabled=False): """ returns a list with the names of the supported import formats """ parsers = component.getAllUtilitiesRegisteredFor(IBibliographyParser) return [parser.getFormatName() \ for parser in parsers if (parser.isAvailable() or with_unavailables) and (parser.isEnabled() or with_disabled) ] security.declarePublic('getImportFormatExtensions') def getImportFormatExtensions(self, with_unavailables=False, with_disabled=False): """ returns a list with the file name extensions of the supported import formats """ parsers = component.getAllUtilitiesRegisteredFor(IBibliographyParser) return [parser.getFormatExtension() \ for parser in parsers if (parser.isAvailable() or with_unavailables) and (self.isParserEnabled(parser.getFormatName()) or with_disabled)] def getImportFormatDescriptions(self, with_unavailables=False, with_disabled=False): """ returns a list with the description texts of the supported import formats """ parsers = component.getAllUtilitiesRegisteredFor(IBibliographyParser) return [parser.Description() \ for parser in parsers if (parser.isAvailable() or with_unavailables) and (parser.isEnabled() or with_disabled) ] security.declarePublic('getExportFormatNames') def getExportFormatNames(self, with_unavailables=False, with_disabled=False): """ returns a list with the names of the supported export formats """ utils = component.getAllUtilitiesRegisteredFor(IBibliographyRenderer) return [ renderer.__name__ for renderer in utils if (renderer.available or with_unavailables) and ( self.isRendererEnabled(renderer.__name__) or with_disabled) ] security.declarePublic('getExportFormatExtensions') def getExportFormatExtensions(self, with_unavailables=False, with_disabled=False): """ returns a list with the file name extensions of the supported export formats """ utils = component.getAllUtilitiesRegisteredFor(IBibliographyRenderer) return [ renderer.target_format for renderer in utils if (renderer.available or with_unavailables) and ( self.isRendererEnabled(renderer.__name__) or with_disabled) ] def getExportFormatDescriptions(self, with_unavailables=False, with_disabled=False): """ returns a list with the description texts of the supported export formats """ utils = component.getAllUtilitiesRegisteredFor(IBibliographyRenderer) return [ renderer.description for renderer in utils if (renderer.available or with_unavailables) and ( self.isRendererEnabled(renderer.__name__) or with_disabled) ] security.declarePublic('getExportFormats') def getExportFormats(self, with_unavailables=False, with_disabled=False): """ returns a list of (name, extension, description) tuples of the supported export formats """ export_formats = zip( self.getExportFormatNames(with_unavailables=with_unavailables, with_disabled=with_disabled), self.getExportFormatExtensions(with_unavailables=with_unavailables, with_disabled=with_disabled), self.getExportFormatDescriptions( with_unavailables=with_unavailables, with_disabled=with_disabled)) export_formats.sort() return export_formats security.declarePublic('getImportFormats') def getImportFormats(self, with_unavailables=False, with_disabled=False): """ returns a list of (name, extension, description) tuples of the supported import formats """ supported_parsers = zip( self.getImportFormatNames(with_unavailables=with_unavailables, with_disabled=with_disabled), self.getImportFormatExtensions(with_unavailables=with_unavailables, with_disabled=with_disabled), self.getImportFormatDescriptions( with_unavailables=with_unavailables, with_disabled=with_disabled)) supported_parsers.sort() return supported_parsers security.declareProtected(View, 'render') def render(self, entry, format='', output_encoding=None, **kw): """ renders a BibliographyEntry object in the specified format """ renderer = self.getRenderer(format=format, **kw) if renderer: return renderer.render(entry, output_encoding=output_encoding, **kw) else: return None security.declareProtected(View, 'isParserEnabled') def isParserEnabled(self, name): """ Check cmfbibat propertysheet """ return self.getSheetProperty(name, 'parser_enabled') security.declareProtected(View, 'isRendererEnabled') def isRendererEnabled(self, name): """ Check cmfbibat propertysheet """ return self.getSheetProperty(name, 'renderer_enabled') security.declareProtected(View, 'getRenderer') def getRenderer(self, format, with_unavailables=False, with_disabled=False, **kw): """ returns the renderer for the specified format first looks for a renderer with the 'format' name next looks for a renderer with the 'format' extension """ utils = component.getAllUtilitiesRegisteredFor(IBibliographyRenderer) for renderer in utils: if (renderer.available or with_unavailables) and \ (renderer.enabled or with_disabled): if format.lower() == renderer.__name__.lower(): return renderer.__of__(self) if format.lower() == renderer.target_format.lower(): return renderer.__of__(self) return None security.declareProtected(View, 'getEntries') def getEntries(self, source, format, file_name=None, input_encoding='utf-8'): """ main routine to be called from BibliographyFolders returns a list with the parsed entries """ source = self.checkEncoding(source, input_encoding) format = self.checkFormat(source, format, file_name) parser = self.getParser(format) if parser: try: return parser.getEntries(source) except Exception, e: LOG.error('Import error while importing file (%s)' % e, exc_info=True) raise RuntimeError( 'An error occured (%s) - please check the log file for details' % e) else:
class Box(Persistent): implements(IDepositBox) def __init__(self, max_age=config.MAX_AGE, purge_days=config.PURGE_DAYS): self.data = PersistentMapping() self._last_purge = int(time.time()) self.max_age = max_age self.purge_days = purge_days def _generate_new_id(self): """Generate new id. """ new_id = id_generator() while new_id in self.data.keys(): new_id = id_generator() return new_id def put(self, value, token=None): """Put value in box, with optional token, and return generated id. Calling this method also does a purge once a day (well, when the last purge was at least 24 hours ago). The frequency can be controlled with the purge_days attribute. """ cutoff = int(time.time()) - (self.purge_days * 86400) if self._last_purge < cutoff: self.purge() if value is None: raise ValueError id = self._generate_new_id() self.data[id] = BoxItem(token, value, confirmed=False) return id def edit(self, secret, value, token=None): """Edit value in the box, when secret and optional token match. """ if value is None: raise ValueError stored = self.get(secret, token=token) if value == stored: # No change return self.data[secret] = BoxItem(token, value, confirmed=True) def get(self, secret, token=None): stored = self.data.get(secret) if stored is None: return None if stored.token != token: # raise Exception return None if not stored.confirmed: # Purge this item when it is expired: cutoff = int(time.time()) - self.max_age * 86400 if stored.timestamp < cutoff: del self.data[secret] return None if token: # When there is a token, the item must be confirmed # before we return the value. Main use case: email # confirmation. return None return stored.value def confirm(self, secret, token=None): """Confirm the item/token and return whether this succeeded or not. """ stored = self.data.get(secret) if stored is None: return None if stored.token != token: # raise Exception? return None if not stored.confirmed: # First check if the confirmation comes too late. cutoff = int(time.time()) - self.max_age * 86400 if stored.timestamp < cutoff: del self.data[secret] # Report back that we have failed, in case anyone # wants to know. return False stored.confirmed = True return True def pop(self, secret, token=None): stored = self.get(secret, token=token) if stored is None: return None self.data.pop(secret) return stored def get_all_confirmed(self): for key, stored in self.data.items(): if stored.confirmed: yield stored.value def purge(self): """Purge items that have expired. Confirmed items are not purged. """ cutoff = int(time.time()) - self.max_age * 86400 logger.info("Started purging data.") for key, stored in self.data.items(): if not stored.confirmed and stored.timestamp < cutoff: logger.info("Purged data with secret %r", key) del self.data[key] self._last_purge = int(time.time()) logger.info("Finished purging data.")
class ContentGroupManager: """ """ def __init__(self): self.__groups_collection = PersistentMapping() def __add_group_item(self, id, name, filter, pattern): #create a new item item = ContentGroup(id, name, filter, pattern) self.__groups_collection[id] = item def __update_group_item(self, id, name, filter, pattern): #modify an item item = self.__groups_collection.get(id) if item is not None: item.name = name item.filter = filter item.pattern = pattern self.__groups_collection[id] = item def __delete_group_item(self, id): #delete an item try: del(self.__groups_collection[id]) except: pass ################# # BASIC API # ################# def get_groups_collection(self): #return the groups collection return self.__groups_collection def get_groups_ids(self): #get the groups ids return self.__groups_collection.keys() def get_groups_list(self): #get a list with all items return utils.utSortObjsListByAttr(self.__groups_collection.values(), 'name') def get_group_item(self, id): #get an item try: return self.__groups_collection[id] except: return None def get_group_item_data(self, id): #get an item data item = self.get_group_item(id) if item is not None: return ['update', item.id, item.name, item.filter, item.pattern, item.start, item.maxResults, item.g_filter, item.restrict, item.safeSearch, item.language, item.inputencoding, item.outputencoding, item.http_proxy, item.search_type] else: return ['add', '', '', '', ''] def add_group_item(self, id, name, filter, pattern): #create a new item self.__add_group_item(id, name, filter, pattern) def update_group_item(self, id, name, filter, pattern): #modify an item self.__update_group_item(id, name, filter, pattern) def update_google_props(self, id, start, maxResults, filter, restrict, safeSearch, language, inputencoding, outputencoding, http_proxy): #update the Google search properties msg = 0 item = self.__groups_collection.get(id) if item is not None: #set data try: #check if integer values start = int(start) maxResults = int(maxResults) filter = int(filter) safeSearch = int(safeSearch) except: msg = 1 if not msg: #set data item.start = start item.maxResults = maxResults item.g_filter = filter item.safeSearch = safeSearch item.restrict = restrict item.language = language item.inputencoding = inputencoding item.outputencoding = outputencoding item.http_proxy = http_proxy self.__groups_collection[id] = item return msg def update_search_type(self, id, search_type): #update the Google search type item = self.__groups_collection.get(id) item.search_type = search_type self.__groups_collection[id] = item def delete_group_item(self, ids): #delete 1 or more items map(self.__delete_group_item, ids) security = ClassSecurityInfo() security.setDefaultAccess("allow")
class NounBayesClassifier(Persistent): """ """ implements(IContentClassifier) def __init__(self,tagger=None,noNounRanksToKeep = 20): """ """ self.noNounRanksToKeep = noNounRanksToKeep self.trainingDocs = PersistentMapping() self.allNouns = OOSet() self.classifier = None self.trainAfterUpdate = True def addTrainingDocument(self,doc_id,tags): """ """ storage = getUtility(INounPhraseStorage) importantNouns = storage.getNounTerms(doc_id,self.noNounRanksToKeep) self.trainingDocs[doc_id] = (importantNouns,tags) self.allNouns = union(self.allNouns,OOSet(importantNouns)) def train(self): """ """ presentNouns = dict() trainingData = [] if not self.allNouns: storage = getUtility(INounPhraseStorage) for key in self.trainingDocs.keys(): importantNouns = storage.getNounTerms( key, self.noNounRanksToKeep) self.allNouns = union(self.allNouns,OOSet(importantNouns)) for item in self.allNouns: presentNouns.setdefault(item,0) for (nouns,tags) in self.trainingDocs.values(): nounPresence = presentNouns.copy() for noun in nouns: nounPresence[noun] = 1 for tag in tags: trainingData.append((nounPresence,tag,)) if trainingData: self.classifier = NaiveBayesClassifier.train(trainingData) def classify(self,doc_id): """ """ if not self.classifier: return [] presentNouns = dict() for item in self.allNouns: presentNouns.setdefault(item,0) storage = getUtility(INounPhraseStorage) importantNouns = storage.getNounTerms(doc_id,self.noNounRanksToKeep) for noun in importantNouns: if noun in presentNouns.keys(): presentNouns[noun] = 1 return self.classifier.classify(presentNouns) def probabilityClassify(self,doc_id): """ """ if not self.classifier: return [] presentNouns = dict() for item in self.allNouns: presentNouns.setdefault(item,0) storage = getUtility(INounPhraseStorage) importantNouns = storage.getNounTerms(doc_id,self.noNounRanksToKeep) for noun in importantNouns: if noun in presentNouns.keys(): presentNouns[noun] = 1 return self.classifier.prob_classify(presentNouns) def clear(self): """Wipes the classifier's data. """ self.allNouns.clear() self.trainingDocs.clear() def tags(self): if not self.classifier: return [] return self.classifier.labels()
class CustomField(Folder): """ A CustomField is an object that becomes automatically included as part of the Add Issue page. The ID of the custom field becomes the name of the input. So if the ID is 'foo' the input rendered becomes <input name="foo"> This class defines: Type of input --------------------------------------------------------------------------- You can select one of the following: text, textarea, password, hidden, select, checkbox, radio or file Depending on which one you select you'll specify parameters such as 'cols' (for type 'textarea' of course) or size. By having first selected a type, the field will autogenerate some default parameters that you can later modify. Default value --------------------------------------------------------------------------- The default value can be either a simple string inputted or it can be a reference to something else callable that will get the default value and this is done with a TALES expression. Being mandatory or optional --------------------------------------------------------------------------- By default every field is optional but by making it mandatory, you'll most likely going to have to specify a validation because sometimes it's not as simple as checking that a value is boolean or not (e.g. bool('')) Validation --------------------------------------------------------------------------- This is where you specify either a reference to a script or a TALES expression that will work out if a particular value is valid or not. Javascript events hooks (onchange, onclick, onfocus, onblur) --------------------------------------------------------------------------- You'll be responsible for what you write in the values for these. The values must be available javascript functions. Setting persistent values on issues --------------------------------------------------------------------------- (This is actually implemented in IssueTrackerProduct/IssueTracker.py) When saving the issue, we'll add an attribute to the issue like this:: <id of custom field>: <value at input> This will pass through the validation a second time but unlike the first time, if the validation fails this time a hard error is raised. The type of the value is by default a unicode string or what else is appropriate based on the input type. You can specify an expression that will massage the input before it's saved. So, suppose you want to save it as a floating point number you enter this expression:: python:float(value) Getting persistent values on issues --------------------------------------------------------------------------- (This is actually implemented in IssueTrackerProduct/IssueTracker.py) You can ask the issuetracker for the value of a custom field simply by specifying the ID of the custom field and an optional default value. Quite possibly you'll have an issuetracker where issues were added before the creation of the custom field so it'll be important to supply a default value. Additionally loaded Javascript and CSS --------------------------------------------------------------------------- You get an area for entering the Javascript and the CSS and this is automatically loaded on the Add Issue page. If you in your input of this (on the first line) enter a name of a file or DTML Method/Document that exists, that is instead rendered. The input can also be a valid URL if it looks relative and valid. """ meta_type = CUSTOMFIELD_METATYPE manage_options = ( {"label": "Manage", "action": "manage_field"}, {"label": "Validation", "action": "manage_validation"}, ) + Folder.manage_options _properties = ( {"id": "title", "type": "ustring", "mode": "w"}, {"id": "disabled", "type": "boolean", "mode": "w"}, {"id": "python_type", "type": "selection", "mode": "w", "select_variable": "getOKPythonTypes"}, {"id": "include_in_filter_options", "type": "boolean", "mode": "w"}, ) security = ClassSecurityInfo() def __init__( self, id, title=u"", input_type="text", python_type="ustring", extra_js=u"", extra_css=u"", mandatory=False, options=[], options_expression="", visibility_expression="", include_in_filter_options=False, ): self.id = str(id) self.title = title self.input_type = input_type self.python_type = python_type self.attributes = PersistentMapping() self.extra_css = extra_css self.extra_js = extra_js self.mandatory = mandatory self.options = options self.options_expression = options_expression self.disabled = False self.visibility_expression = visibility_expression self.include_in_filter_options = include_in_filter_options ## ## Attributes of the object ## def getId(self): return self.id def getTitle(self): return self.title def isMandatory(self): return self.mandatory def isDisabled(self): return self.disabled def getOptions(self): return self.options def getInputType(self): return self.input_type def getPythonType(self): return self.python_type security.declareProtected(VMS, "getOptionsFlat") def getOptionsFlat(self): """ return the list of options with a | pipe sign to split tuples """ return list_to_flat(self.getOptions()) def getOptionsExpression(self): """ true if it looks like a TALES expression """ return self.options_expression def getVisibilityExpression(self): return self.visibility_expression def includeInFilterOptions(self): return self.include_in_filter_options ## ## Special Zope magic ## def getOKPythonTypes(self): return OK_python_types ## ## Special massaging on the class attributes ## def _prepareByType(self): """ set all the appropriate default bits and pieces by the input_type. For example, if the input type is 'textarea' set a default cols and rows. """ if self.input_type == "textarea": self.attributes["cols"] = DEFAULT_TEXTAREA_COLS self.attributes["rows"] = DEFAULT_TEXTAREA_ROWS elif self.input_type == "checkbox": pass # if 'value' in self.attributes: # del self.attributes['value'] elif self.input_type == "radio": if "value" in self.attributes: del self.attributes["value"] elif self.input_type == "file": if "value" in self.attributes: del self.attributes["value"] ## ## Rendering stuff ## def render(self, *value, **extra_attributes): """ return the tag (e.g. <textarea>) and any other accompanying HTML stuff. """ # if someone passes None as the first and only parameter to render() # the value of variable 'value' will be (None,) # This should be considered as if nothing is set if value == (None,): value = [] if value and isinstance(value[0], InstanceType) and value[0].__class__.__name__ == "HTTPRequest": # this method has been called with REQUEST as the value parameter. # Note that it's still a list or tuple but convert it to the actual value. value = value[0].form.get(self.getId(), None) if value is None: value = () else: value = (value,) # make sure it's a tuple out = [] if DevelopmentMode: out.append(u"<!--CustomField: %s -->" % self.getId()) if self.isDisabled(): logger.warn("A disabled custom field (%s) is rendered" % self.absolute_url_path()) # take out some extra keywords from the extra_attributes skip_extra_css = extra_attributes.pop("skip_extra_css", False) skip_extra_js = extra_attributes.pop("skip_extra_js", False) if self.extra_css and not skip_extra_css: out.append(self.render_extra_css()) if self.extra_js and not skip_extra_js: out.append(self.render_extra_js()) out.append(self.render_tag(*value, **extra_attributes)) return "\n".join(out) def render_tag(self, *value, **extra_attributes): """ return a piece of unicode HTML that """ assert len(value) <= 1, "Can't pass more than one argument as value" inner = [] attributes = {} # notice the order of these update() calls! It matters name_prefix = extra_attributes.pop("name_prefix", "") # It's an option to called render_tag() with in_filter=True which tells # us that this tag is rendered as a filter, in the filter options. # This is something that can be done on-the-fly and it means that # certain things should work differently. For example, a 'select' type # input get's an added 'size' and 'multiple' attribute when used as a # filter. in_filter = extra_attributes.pop("in_filter", False) # core attributes dom_id = self.attributes.get("dom_id", "id_%s" % self.getId()) attributes.update({"name": self._wrapPythonTypeName(name_prefix), "id": dom_id, "title": self.getTitle()}) # saved attributes attributes.update(dict(self.attributes)) # extra on rendering attributes attributes.update(extra_attributes) # Now, "hack" the attributes if this is used in a filter if in_filter: if self.input_type == "select": attributes["multiple"] = "multiple" if "size" not in attributes: attributes["size"] = min(5, len(list(self.getOptionsIterable()))) # filler is a dict that we will use to render the template filler = {} if self.input_type == "textarea": template = u"<textarea %(inner)s>%(value)s</textarea>" v = None if value: v = value[0] # from the argument elif "value" in attributes: v = attributes.pop("value") if v: filler["value"] = Utils.safe_html_quote(v) else: filler["value"] = u"" elif self.input_type == "select": template = u"<select %(inner)s>\n%(all_options)s\n</select>" all_options = [] v = [] if value: v = value[0] # makes sure the value doesn't become a nested list if isinstance(v, list): v = Utils.flatten_lines(v) elif "value" in attributes: v = attributes.pop("value") if not isinstance(v, (tuple, list)): v = [v] # if the value passed to render this select contains # items that are not in the list of options, don't # use the list of options. _values_selected = [] for option in self.getOptionsIterable(): if isinstance(option, (tuple, list)): value, label = option else: value, label = option, option if self.getPythonType() == "int": try: value = int(value) except ValueError: pass elif self.getPythonType() == "float": try: value = float(value) except ValueError: pass if value in v: tmpl = u'<option value="%s" selected="selected">%s</option>' _values_selected.append(value) else: tmpl = u'<option value="%s">%s</option>' all_options.append(tmpl % (value, label)) if Set(v) - Set(_values_selected): # there were values that weren't in the list of options! _values_not_in_options = list(Set(v) - Set(_values_selected)) # if nothing was matched in the list of options, # reset the whole all_options list. if not _values_selected and all_options: all_options = [] for value in _values_not_in_options: label = value tmpl = u'<option value="%s" selected="selected">%s</option>' all_options.append(tmpl % (value, label)) filler["all_options"] = "\n".join(all_options) elif self.input_type == "radio": # special case if not self.getOptionsIterable(): template = u"ERROR: No options" else: template = u"%(all_inputs)s" all_inputs = [] v = None if value: v = value[0] # from the argument elif "value" in attributes: v = attributes.pop("value") special_attributes = "" inner = [] for k, v2 in attributes.items(): if k in ("id",): continue inner.append('%s="%s"' % (k, v2)) if inner: special_attributes = " " + " ".join(inner) for option in self.getOptions(): if isinstance(option, (tuple, list)): value, label = option else: value, label = option, option if value == v: tmpl = u'<input type="radio" value="%s" checked="checked"%s /> %s<br />' else: tmpl = u'<input type="radio" value="%s"%s/> %s<br />' all_inputs.append(tmpl % (value, special_attributes, label)) filler["all_inputs"] = "\n".join(all_inputs) elif self.input_type == "checkbox": # another special case v = None if value: v = value[0] # from the argument elif "value" in attributes: v = attributes.pop("value") # If there are no options you can work this like a normal text input if not self.getOptions(): # but what if it should be a boolean and it's true, then the # tag needs to contain checked="checked" if v: template = u'<input type="checkbox" checked="checked" %(inner)s />' else: template = u'<input type="checkbox" %(inner)s />' else: # crap! template = u"%(all_inputs)s" all_inputs = [] special_attributes = "" inner = [] for k, v2 in attributes.items(): if k in ("id",): continue inner.append('%s="%s"' % (k, v2)) if inner: special_attributes = " " + " ".join(inner) for option in self.getOptions(): if isinstance(option, (tuple, list)): value, label = option else: value, label = option, option if value == v: tmpl = u'<input type="checkbox" value="%s" checked="checked"%s /> %s<br />' else: tmpl = u'<input type="checkbox" value="%s"%s/> %s<br />' all_inputs.append(tmpl % (value, special_attributes, label)) filler["all_inputs"] = "\n".join(all_inputs) elif self.input_type == "password": template = u'<input type="password" %(inner)s />' elif self.input_type == "file": template = u'<input type="file" %(inner)s />' else: # type text template = u"<input %(inner)s />" if not (self.input_type == "radio" or (self.input_type == "checkbox" and self.getOptions())): if value and self.input_type not in ("select",): if value and value[0]: # This overrides the default value attributes["value"] = value[0] for key, val in sorted(attributes.items()): inner.append('%s="%s"' % (key, val)) filler["inner"] = " ".join(inner) return template % filler def __str__(self): return str(self.render()) def _wrapPythonTypeName(self, prefix=""): """ if name is 'age' and python_type is 'int' then return 'age:int'. If the type is unicode type, add the encoding """ name, python_type = self.getId(), self.python_type # add the prefix name = "%s%s" % (prefix, name) if self.input_type == "file": # exception return name if python_type in ("ustring", "ulines"): return "%s:%s:%s" % (name, UNICODE_ENCODING, python_type) elif python_type == "string": return name else: return "%s:%s" % (name, python_type) def render_extra_css(self): """ return a piece of HTML that loads the CSS. If it looks like the attribute self.extra_css is a URI, return a <link rel="stylesheet"> tag instead. """ css = self.extra_css if len(css.splitlines()) == 1 and (css.startswith("http") or css.startswith("/") or css.endswith(".css")): return u'<link rel="stylesheet" type="text/css" href="%s" />' % css elif css: return u'<style type="text/css">\n%s\n</style>' % css else: return u"" def render_extra_js(self): """ return a piece of HTML that loads the javascript. If it looks like the attribute self.extra_js is a URI, return a <script src="..."> tag instead. """ js = self.extra_js if len(js.splitlines()) == 1 and (js.startswith("http") or js.startswith("/") or js.endswith(".js")): return u'<script type="text/javascript" src="%s"></script>' % js elif js: return u'<script type="text/javascript">\n%s\n</script>' % js else: return u"" security.declareProtected(VMS, "preview_render") def preview_render(self, *value, **extra_attributes): """ wrapper on render() that is able to cut out some of the verbose stuff from the render output. """ html = self.render(*value, **extra_attributes) return html ## ## TALES expression for options ## def getOptionsIterable(self): """ return a list of options """ if self.getOptionsExpression(): ec = self._getExprContext(self) ex = Expression(self.options_expression) return list(ex(ec)) else: return self.getOptions() def _getExprContext(self, object, extra_namespaces={}): return getExprContext(self, object, extra_namespaces=extra_namespaces) def _valid_options_expression(self): """ return true if self.options_expression is valid otherwise raise an error. """ ec = self._getExprContext(self) ex = Expression(self.options_expression) iterable = ex(ec) if isinstance(iterable, (list, tuple)): # each item should be unicodeable and # every item must something for item in iterable: if isinstance(item, (tuple, list)): key, value = item if key and not value: value = key else: key, value = item, item if not item: return False # an iterable we can't find anything wrong with return True # default is not to pass return False ## ## Validation ## def getValidationExpressions(self): return self.objectValues(CUSTOMFIELD_VALIDATION_EXPRESSION_METATYPE) security.declarePrivate("testValidValue") def testValidValue(self, value): """ return a tuple of (valid or not [bool], message [unicode]) if the value passes all the validation expressions (assuming the field has any) """ # check the python type if self.python_type == "ustring": # should be possible to do this try: unicode(value) except TypeError: return False, u"Not a unicode string" elif self.python_type == "int": try: int(value) except ValueError: return False, u"Not an integer number" elif self.python_type == "float": try: float(value) except ValueError: return False, u"Not a floating point number" elif self.python_type == "long": try: long(value) except ValueError: return False, u"Not a long integer number" elif self.python_type == "date": try: if isinstance(value, basestring): DateTime(value) except DateError: return False, u"Not a valid date" elif self.python_type == "ulines": if isinstance(value, basestring): try: [unicode(x) for x in value.splitlines()] except ValueError: return False, u"Not a list of unicode strings" elif value is not None: value = Utils.flatten_lines(value) try: [unicode(x) for x in value] except ValueError: return False, u"Not a list of unicode strings" elif self.python_type == "lines": if isinstance(value, basestring): try: [str(x) for x in value.splitlines()] except ValueError: return False, u"Not a list of strings" elif value is not None: value = Utils.flatten_lines(value) try: [str(x) for x in value] except ValueError: return False, u"Not a list of strings" # check each TALES expression for ve in self.getValidationExpressions(): ec = self._getExprContext(self, extra_namespaces=dict(value=value)) ex = Expression(ve.expression) if not bool(ex(ec)): return False, ve.message # by default no validation expression made it invalid return True, None ## ## Working with the persistent attributes ## def getCoreAttribute(self, *key_and_default): """ return the value of this attribute. If len(@key_and_default) = 2 is the second one is a default value. If not don't fall back on a default. """ if not len(key_and_default) in (1, 2): raise ValueError, "Call getCoreAttribute(key [,default])" if len(key_and_default) == 1: return self.attributes[key_and_default[0]] else: return self.attributes.get(key_and_default[0], key_and_default[1]) security.declareProtected(VMS, "getCoreAttributeKeys") def getCoreAttributeKeys(self): return list(self.attributes.keys()) security.declareProtected(VMS, "getCoreAttributeKeyLabel") def getCoreAttributeKeyLabel(self, key, html_ok=False): """ return a string that explains what the key is. The resturn string can contain HTML. """ if key == "dom_id": if html_ok: return u'<abbr title="DOM element ID, not Zope object ID">DOM ID</abbr>' else: return u"DOM ID" if key.startswith("on") and re.findall("on\w+", key): return u"on" + key[2:].capitalize() if key in ("rows", "cols"): return u"Textarea %s" % key return key.title() def getCoreAttributeKeySuggestions(self): """ return a list of suggestions of attribute keys you might want to add """ suggestions = ["style", "size", "dom_id", "onchange", "onkeypress", "onclick", "onfocus", "onblur", "value"] # add more if self.input_type == "textarea": suggestions.append("cols") suggestions.append("rows") elif self.input_type == "select": suggestions.append("multiple") # reduce already used ones suggestions = [x for x in suggestions if x not in self.attributes] # sort them by their labels suggestions = [(self.getCoreAttributeKeyLabel(x), x) for x in suggestions] suggestions.sort() # return just the keys return [x[1] for x in suggestions] def getCoreAttributeKeyName(self, key): """ return what the suitable name for the key should be a input tag """ return u"%s:ustring" % key def getDeleteableAttributeKeys(self): """ return a list of keys of attributes you can delete """ all = Set(list(self.attributes.keys())) not_ = Set(CORE_ATTRIBUTES) return list(all - not_) ## ## Modifying the custom field ## security.declareProtected(VMS, "manage_saveFieldProperties") def manage_saveFieldProperties( self, input_type=None, python_type=None, title=None, mandatory=False, extra_css=None, extra_js=None, options=None, options_expression=None, visibility_expression=None, include_in_filter_options=False, REQUEST=None, **settings ): """ saving changes via the web """ if input_type is not None: different = input_type != self.input_type if not input_type in OK_input_types: raise ValueError, "invalid input_type" self.input_type = input_type if different: self._prepareByType() if python_type is not None: assert python_type in OK_python_types, "Invalid Python type (%r)" % python_type self.python_type = python_type if title is not None: self.title = unicode(title) self.mandatory = bool(mandatory) self.include_in_filter_options = bool(include_in_filter_options) if extra_css is not None: self.extra_css = unicode(extra_css).strip() if extra_js is not None: self.extra_js = unicode(extra_js).strip() if options_expression is not None: self.options_expression = str(options_expression).strip() if self.options_expression: assert self._valid_options_expression(), "Invalid expression" if visibility_expression is not None: self.visibility_expression = visibility_expression if options is not None: self.options = flat_to_list(options) if not settings and REQUEST is not None: settings = self.REQUEST.form # I don't like the pattern but it'll have to do for now for key, value in settings.items(): if key not in CORE_ATTRIBUTES: self.attributes[key] = value if REQUEST is not None: msg = "Changes saved" url = self.absolute_url() + "/manage_field" url += "?manage_tabs_message=%s" % Utils.url_quote_plus(msg) REQUEST.RESPONSE.redirect(url) security.declareProtected(VMS, "manage_addFieldProperty") def manage_addFieldProperty(self, key=None, new_key=None, REQUEST=None): """ add a new attribute property """ if not key and not new_key: raise ValueError, "must pass 'key' OR 'new_key'" if new_key: key = new_key.strip() key = str(key) self.attributes[key] = u"" if REQUEST is not None: msg = "Field added" url = self.absolute_url() + "/manage_field" url += "?manage_tabs_message=%s" % Utils.url_quote_plus(msg) url += "#field-%s" % key REQUEST.RESPONSE.redirect(url) security.declareProtected(VMS, "manage_deleteFieldProperty") def manage_deleteFieldProperty(self, key, REQUEST=None): """ delete a field property """ del self.attributes[key] if REQUEST is not None: msg = "Attribute deleted" url = self.absolute_url() + "/manage_field" url += "?manage_tabs_message=%s" % Utils.url_quote_plus(msg) REQUEST.RESPONSE.redirect(url) security.declareProtected(VMS, "manage_addValidationExpression") def manage_addValidationExpression(self, expression, message=u"", REQUEST=None): """ add a new validation expression """ # check that it's not complete rubbish expression = str(expression).strip() message = unicode(message).strip() if not expression: raise ValueError, "Expression can't be empty" # XXX: Got to figure out a better way to test the expression without a # arbitrary value like this ## test it # ec = self._getExprContext(self, extra_namespaces=dict(value='123')) # ex = Expression(expression) # try: # ex(ec) # except Exception, m: # raise ValueError, m c = len(self.objectIds(CUSTOMFIELD_VALIDATION_EXPRESSION_METATYPE)) + 1 oid = "validation_%s" % c while base_hasattr(self, oid): c += 1 oid = "validation_%s" % c instance = ValidationExpression(oid, expression, message) self._setObject(oid, instance) if REQUEST is not None: msg = "Expression added" url = self.absolute_url() + "/manage_validation" url += "?manage_tabs_message=%s" % Utils.url_quote_plus(msg) REQUEST.RESPONSE.redirect(url) security.declareProtected(VMS, "manage_deleteValidationExpression") def manage_deleteValidationExpression(self, id, REQUEST=None): """ delete a validation expression """ assert id in self.objectIds(CUSTOMFIELD_VALIDATION_EXPRESSION_METATYPE) self.manage_delObjects([id]) if REQUEST is not None: msg = "Expression delete" url = self.absolute_url() + "/manage_validation" url += "?manage_tabs_message=%s" % Utils.url_quote_plus(msg) REQUEST.RESPONSE.redirect(url) security.declareProtected(VMS, "manage_editValidationExpression") def manage_editValidationExpression(self, id, expression, message, delete=False, REQUEST=None): """ change a validation expression object """ assert id in self.objectIds(CUSTOMFIELD_VALIDATION_EXPRESSION_METATYPE) obj = getattr(self, id) if delete: return self.manage_deleteValidationExpression(id, REQUEST=REQUEST) expression = str(expression).strip() message = unicode(message).strip() if not expression: raise ValueError, "Expression can't be empty" # test it ec = self._getExprContext(self, extra_namespaces=dict(value="123")) ex = Expression(expression) try: ex(ec) except Exception, m: raise ValueError, m obj.expression = expression obj.message = message if REQUEST is not None: msg = "Expression changed" url = self.absolute_url() + "/manage_validation" url += "?manage_tabs_message=%s" % Utils.url_quote_plus(msg) REQUEST.RESPONSE.redirect(url)
class WeightNode(Node): 'A traditional model neuron: state in [0,1], weighted inputs' def __init__(self, par, weightDomain=(-7, 7), quanta=None, abs_weights=0): # with absolute weights and polarity neurons range must be >= 0. if abs_weights: assert weightDomain[0] >= 0 Node.__init__(self, par) self.weights = PersistentMapping() self.weightDomain = weightDomain self.quanta = quanta self.output = random.uniform(0, 1) # abs_weights only affects external inputs since weightDomain is forced # to be positive above self.abs_weights = abs_weights def destroy(self): Node.destroy(self) del self.weights def mutate(self, p): mutations = 0 for src in self.weights.keys(): if random.random() < p: mutations += 1 self.weights[src] = rdom(self.weightDomain, self.weights[src], self.quanta) return mutations def addInput(self, source): Node.addInput(self, source) self.weights[source] = rdom(self.weightDomain, None, self.quanta) def addExternalInput(self, s_bp, s_sig, weight): 'source = (srcBodypart, srcSignal, weight)' source = (s_bp, s_sig) if isinstance(s_sig, Node): assert s_sig in s_bp.network Node.addExternalInput(self, source) if self.abs_weights: weight = abs(weight) self.weights[source] = weight def removeExternalInput(self, bp, sig): 'source = (srcBodypart, srcSignal)' Node.removeExternalInput(self, bp, sig) del self.weights[(bp, sig)] def delInput(self, source): Node.delInput(self, source) del self.weights[source] def check(self): for key in self.weights.keys(): assert key in self.inputs for src in self.inputs: assert src in self.weights def fixup(self): # remove all weights that dont have an input for weight_key in self.weights.keys(): if weight_key not in self.inputs: del (self.weights[weight_key]) # add weight for any inputs that dont have one for source in self.inputs: if source not in self.weights: weight = self._chooseRandom() self.weights[source] = weight def swapInputs(self, a, b): Node.swapInputs(self, a, b) if a in self.weights and b in self.weights: t = self.weights[a] self.weights[a] = self.weights[b] self.weights[b] = t elif a in self.weights: self.weights[b] = self.weights[a] del self.weights[a] elif b in self.weights: self.weights[a] = self.weights[b] del self.weights[b] def wsum(self, inputs=None, use_external=1): 'sum of weighted inputs' cumulative = 0 if inputs == None: inputs = self.inputs # quantise inputs for src in inputs: x = src.output if self.quanta: x = quantise(x, self.quanta) if isinstance(src, SrmNode): # hack since output is spikes, we want eps function # note that we don't do quantisation here. # note: with async nodes, eps may not have been set yet. if hasattr(src, 'eps'): x = src.eps cumulative += x * self.weights[src] if use_external: for (src, x) in self.externalInputs.items(): if self.quanta: x = quantise(x, self.quanta) cumulative += x * self.weights[src] return cumulative
class HasEmail: """Mixin class proving email address(es) and related functions""" def __init__(self): self.__items = [] self.__unconfirmed = PersistentMapping() self.primary_email = None def is_valid_email(cls, email): """Class method returns True if email is valid, or False if it should be rejected. >>> HasEmail.is_valid_email('*****@*****.**') True >>> HasEmail.is_valid_email('*****@*****.**') True >>> HasEmail.is_valid_email('*****@*****.**') True >>> HasEmail.is_valid_email('xyz') False >>> HasEmail.is_valid_email('abc@xyz@foo') False """ global _blocked_domains if email.find('@') == -1: return False if email.count('@') != 1: return False (username, host) = email.split('@') if host in _blocked_domains: return False return True is_valid_email = classmethod(is_valid_email) def add_email(self, email): """Add email to the list. Adds primary if none set.""" email = email.lower() if email not in self.__items: self.__items.append(email) self._p_changed = 1 if self.primary_email is None: self.primary_email = email def add_unconfirmed_email(self, email): """Add new e-mail that has not yet been confirmed. Call confirm_email to move into active list of e-mails. Returns confirmation code that must be given to confirm_email to confirm. """ email = email.lower() if not self.__unconfirmed.has_key(email): self.__unconfirmed[email] = _password_generator.generate(seed=email) return self.__unconfirmed[email] def remove_unconfirmed_email(self, email): email = email.lower() if self.__unconfirmed.has_key(email): del self.__unconfirmed[email] def confirm_email(self, code): """Confirm email with the given code, or return False if invalid code.""" for email, conf_code in self.__unconfirmed.items(): if conf_code == code: self.add_email(email) del self.__unconfirmed[email] self.notify_email_confirmed(email) return email return None def remove_email(self, email): """Remove an e-mail address from the list. Raises KeyError if only one e-mail address left""" email = email.lower() if self.__unconfirmed.has_key(email): return self.remove_unconfirmed_email(email) emails = self.email_list() if len(emails) > 1: self.__items.remove(email) self._p_changed = 1 if email == self.get_primary_email(): self.set_primary_email(self.email_list()[0]) else: raise KeyError def remove_all_emails(self): self.__items = [] self.primary_email = None def has_email(self, email): email = email.lower() return email in self.__items def email_list(self): return self.__items def unconfirmed_email_list(self): return self.__unconfirmed.keys() def set_primary_email(self, email): email = email.lower() if self.has_email(email): self.primary_email = email else: raise ValueError("I don't know email <%s>" % email) def get_primary_email(self): return self.primary_email def notify_email_confirmed(self, email): """Notice that email was just confirmed.""" pass def _consistency_check(self): if self.primary_email is not None: if self.primary_email not in self.__items: raise KeyError, "primary_email not in email list" typecheck_seq(self.__items, str, allow_none=1)
class Game(Persistent): """ A Game aggregates the players and matches that are part of a competition. For example, a Game could be 'Football' or 'Hockey' """ def __init__(self, name): self.name = name # Player name -> Player self.players = PersistentMapping() # List of all matches for this game self.matches = PersistentList() # Whether to use average instead of sum-of-skill for this game self.use_average_team_skill = True def delete_match(self, match): if not match in self.matches: return self.matches.remove(match) players = match.teams[0] + match.teams[1] for p in players: if match in p.matches: p.matches.remove(match) self.recalculate_ratings() for p in list(self.players.keys()): if not self.players[p].matches: self.players.pop(p) def add_match(self, teams, score): players_a = [self.get_player(name) for name in teams[0]] players_b = [self.get_player(name) for name in teams[1]] # Add Match to the Database match = Match(self, [players_a, players_b], score) self.matches.append(match) self.update_player_ratings(match) match.update_rating_delta() def update_player_ratings(self, match): ratings_a = [p.get_rating() for p in match.teams[0]] ratings_b = [p.get_rating() for p in match.teams[1]] # Sort by score and get rank indices rank = list(zip(match.score, range(len(match.score)))) rank.sort(key=lambda r: r[0], reverse=True) rank_indices = list(zip(*rank))[1] # Check for Draw # TODO: make this generic for more than 2 teams if match.score[0] == match.score[1]: rank_indices = [0, 0] # Calculate new Ratings using trueskill algorithm new_ratings = trueskill.rate([ratings_a, ratings_b], ranks=rank_indices, weights=self.team_weights( ratings_a, ratings_b)) for r, p in zip(new_ratings[0], match.teams[0]): p.set_rating(r) p.add_match(match) for r, p in zip(new_ratings[1], match.teams[1]): p.set_rating(r) p.add_match(match) def recalculate_ratings(self): for player in self.players.values(): player.reset_rating() player.matches.clear() player.history.clear() for match in self.matches: match.init_stats() self.update_player_ratings(match) match.update_rating_delta() def get_player(self, name): if not name in self.players: self.players[name] = Player(name) return self.players[name] # Calcualte player weights for a match based on whether average or additive ratings # are used for this game def team_weights(self, team1, team2): ratings = [team1, team2] weights = [[1 for _ in r] for r in ratings] if self.use_average_team_skill: # Adjust weights by team-size. This effectively causes the TrueSkill algorithm to # look at the average instead of the sum of skills min_team_size = min(map(len, ratings)) weights = [[min_team_size / float(len(r)) for _ in r] for r in ratings] return weights def win_probability(self, team1, team2): """" Calculate the win probability of team1 over team2 given the skill ratings of all the players in the teams. """ def skill_sum(team, weights): return sum([v.skill() * w for (v, w) in zip(team, weights)]) weights = self.team_weights(team1, team2) delta_mu = skill_sum(team1, weights[0]) - skill_sum(team2, weights[1]) sum_sigma = sum((r.confidence() * w)**2 for ( r, w) in zip(itertools.chain(team1, team2), itertools.chain( *weights))) size = len(team1) + len(team2) denom = math.sqrt(size * (trueskill.BETA * trueskill.BETA) + sum_sigma) ts = trueskill.global_env() return ts.cdf(delta_mu / denom) def draw_probability(self, team1, team2): r1 = [p.get_rating() for p in team1] r2 = [p.get_rating() for p in team2] return trueskill.quality([r1, r2], weights=self.team_weights(team1, team2))
class ACL(Persistent): """ Access control hub. The ACL can be instantiated and added to, say the root object, with attribute name acl. """ def __init__(self, settings): self.users = PersistentMapping() self.groups = PersistentMapping() self.activation = PersistentMapping() admin, pwd = settings.get('pycms.admin_user', "admin:admin").split(":") self.users['admin'] = User(admin, "Administrator", "", pwd) self.groups['admin'] = Group('admin', users=PersistentList(['admin'])) self.groups['viewers'] = Group('viewers') self.groups['editors'] = Group('editors') def generate_user_invite_key(self, user_id): """ Generate unique registration key for user and set on user. """ if not user_id in self.users: return None t1 = time.time() time.sleep(random.random()) t2 = time.time() base = hashlib.md5(str(t1 + t2)) key = base.hexdigest()[:KEY_LENGTH] self.activation[key] = self.users[user_id] return key def get_user_for_activation(self, key): return self.activation.get(key, None) def unset_activation_key(self, key): if key in self.activation: del self.activation[key] def list_users(self): """ Return a dict of users, using the id as key """ return self.users.keys() def list_groups(self): return self.groups.keys() def update_user(self, **data): self.users[data['email']].name = data['name'] if data.get('pwd', None): self.users[data['email']].set_pwd(data['pwd']) def set_user_groups(self, user_id, groups=[]): """ Remove user from all groups, and then reset...""" for group_id in self.groups.keys(): self.rm_user_from_group(group_id, user_id) for group_id in groups: self.add_user_to_group(group_id, user_id) def rm_user_from_group(self, group_id, user_id): if user_id in self.groups[group_id].users: idx = self.groups[group_id].users.index(user_id) del self.groups[group_id].users[idx] def add_user_to_group(self, group_id, user_id): if not user_id in self.groups[group_id].users: self.groups[group_id].users.append(user_id) def create_user(self, email, pwd=None, name='', profile=None): if email in self.users: return None self.users[email] = User(email, name or email, email, pwd, profile=profile) return self.users[email] def remove_user(self, user_id): if user_id in self.users: del self.users[user_id]
class PeopleDirectory(Folder): implements(IPeopleDirectory) title = 'People' def __init__(self): super(PeopleDirectory, self).__init__() self.categories = PersistentMapping() # {id: PeopleCategory} self.categories.__parent__ = self self.catalog = CachingCatalog() self.catalog.document_map = DocumentMap() self.update_indexes() self.order = () # order of sections # Set up a default configuration self['all'] = section = PeopleSection('All') section['all'] = report = PeopleReport('All') report.set_columns(['name', 'organization', 'location', 'email']) self.set_order(['all']) def set_order(self, order): self.order = tuple(order) def update_indexes(self): indexes = { 'lastfirst': CatalogFieldIndex(get_lastfirst), 'lastnamestartswith': CatalogFieldIndex(get_lastname_firstletter), 'texts': CatalogTextIndex(get_textrepr), # path index is needed for profile deletion 'path': CatalogPathIndex2(get_path, attr_discriminator=get_acl), 'allowed': CatalogKeywordIndex(get_allowed_to_view), 'is_staff': CatalogFieldIndex(is_staff), 'groups': CatalogKeywordIndex(get_groups), # provide indexes for sorting reports 'department': CatalogFieldIndex(get_department), 'email': CatalogFieldIndex(get_email), 'location': CatalogFieldIndex(get_location), 'organization': CatalogFieldIndex(get_organization), 'phone': CatalogFieldIndex(get_phone), 'position': CatalogFieldIndex(get_position), } # provide indexes for filtering reports for catid in self.categories.keys(): getter = ProfileCategoryGetter(catid) indexes['category_%s' % catid] = CatalogKeywordIndex(getter) catalog = self.catalog need_reindex = False # add indexes for name, index in indexes.items(): if name not in catalog: catalog[name] = index need_reindex = True # remove indexes for name in catalog.keys(): if name not in indexes: del catalog[name] return need_reindex
class Item(Persistent): def __init__(self, parent=None, name=None, title=None, description=None, overwrite=False, **kwargs): self.__parent = None self.__sid = self.get_new_sid() self.__name = None self.__title = None self.__description = None self.__dateTimeCreated = datetime.datetime.now() self.__dateTimeModified = datetime.datetime.now() self.name = name self.title = title self.description = description self.__properties = PersistentMapping() if parent: parent.add_item(self, overwrite=overwrite) def __repr__(self): class_ = self.__class__ return repr('<%s.%s object at %#x with id:"%s" url:"%s">' % (class_.__module__, class_.__name__, id(self), self.id, self.url() ) ) def mark_changed(self): self.__dateTimeModified = datetime.datetime.now() self._p_changed = 1 @property def rename_able(self): """ Check if I can be renamed, an item can be renamed only if it is not plugged to a folder @return True or False """ if self.__parent is None: return True return False @property def name(self): return self.__name def validate_name(self, name): if not name or not self.is_string(name) or URL_SEPARATOR in name: return False return True @name.setter def name(self, name): # i will set my name only if me parent is None if self.rename_able: if self.validate_name(name): self.__name = name else: raise TypeError('item name not valid') else: raise NotRenameAbleError('i am in a folder, use folder.rename_item') # by default synonym of name def get_id_name(self): return 'name' def get_id(self): return getattr(self, self.get_id_name(), None) @property def id_name(self): return self.get_id_name() @property def id(self): return self.get_id() @property def sid(self): return self.__sid @property def title(self): if self.__title is None: return self.name else: return self.__title @title.setter def title(self, value): if (value and self.is_string(value)) or value is None: self.__title = value else: raise TypeError('title must string or None received %s' % type(value)) @property def description(self): if self.__description is None: return self.title else: return self.__description @description.setter def description(self, value): if (value and self.is_string(value)) or value is None: self.__description = value else: raise TypeError('description must string or None received %s' % type(value)) @property def created(self): return str(self.__dateTimeCreated) @property def modified(self): return str(self.__dateTimeModified) @property def root(self): if self.is_folder and self.parent is None: return True return False @property def is_folder(self): return False @property def parent(self): return self.__parent def inform_parent_attached(self, parent): """ this is a private package function This function is called from folder containing this item to inform that it has been added to it's children collection @param parent: Folder @return: boolean """ # I'll be attached to a parent folder only if i have no parent # and i must be already in the parent folder children collection if self.parent is None and parent.is_folder and self.name in parent: self.__parent = parent self.mark_changed() return True return False def inform_parent_detached(self): """ this is a private package function This function is called from folder containing this item to inform that it has been removed from it's children collection @return: boolean """ # i will detach my self from my parent only if i am no longer in my parent if self.parent is not None and self.name not in self.parent: self.__parent = None self.mark_changed() return True return False def allow_delete(self): """ Check if I can be deleted @return True or False """ return True def allow_move(self, target_folder): """ Check if I am allowed to move to target folder @param target_folder: Folder @return True or False """ return True def get_parents(self, validator=None): """ :param validator interface or callable :return: list of parent until root reached or if validator is submitted, until parent validate """ parents = [] folder_parent = self.parent while folder_parent: parents.append(folder_parent) if validator: if (prefixes.is_interface(validator) and validator.providedBy(folder_parent)) or \ (not prefixes.is_interface(validator) and callable(validator) and validator(folder_parent)): break folder_parent = folder_parent.parent return parents def is_folder_in_parents(self, folder_item): """ Check whether i am in the hierarchy tree of folder for example /a/folder/v/c/item @param folder_item: Folder @return: boolean """ if not isinstance(folder_item, folder.Folder): return False # go through my parents and try to find folder folder_parent = self.parent # go through the hierarchy of my parents and try to find folder while folder_parent: if folder_item == folder_parent: return True folder_parent = folder_parent.parent return False # properties operations def __getitem__(self, key): return self.get_property(key) def __delitem__(self, key): if key in self.__properties.keys(): del self.__properties[key] self.mark_changed() def __setitem__(self, key, value): self.set_property(key, value) def has_property(self, name): return name in self.__properties def get_property(self, name, default=None): if name in ('name', 'id', 'title', 'description', 'created', 'modified'): return getattr(self, name) if name in self.__properties: return self.__properties[name] return default def set_property(self, name, value): if self.is_string(name, raise_err=True): self.__properties[name] = value self.mark_changed() def get_properties(self, properties): if not properties: return [] if not isinstance(properties, (list, tuple)): raise TypeError('properties must be list or tuple received: %s' % type(properties)) view = {} for key in properties: view[key] = self.get_property(key) return view def set_properties(self, properties): if properties is None: properties = dict() if not isinstance(properties, dict): raise TypeError('expected dict type, received %s' % type(properties)) for name, value in properties.items(): self.set_property(name, value) return True def get_url_item(self, url): """ :param url: str, of type """ if not url: url = URL_SEPARATOR if self.is_string(url, raise_err=True): #log_debug('get_url_item - url: %s' % url) sep_url = url.split(URL_SEPARATOR) ind = 0 item = self len_sep_url = len(sep_url) for tu in sep_url: if tu == '' and ind == 0: # if the first one is empty, this is the url separator tu = URL_SEPARATOR elif tu == '': # ignore empty ones ind += 1 continue if prefixes.has_prefix(tu): # I would like to pass the next item to some validators that can need it #next_item_name if ind < len_sep_url-1: next_item_name = sep_url[ind+1] else: next_item_name = None item = prefixes.get_parent(tu, item, next_item_name=next_item_name) #log_debug('... get parent from prefix "%s"' % tu) if item is None: #log_debug('... parent from prefix "%s" not found' % tu) break ind += 1 continue if not item.is_folder: item = None break item = item.get_item(tu) if item is None: break ind += 1 if item is None: #@log_debug('... url do not exist: %s' % url) pass #log_debug('... return %s' % item) return item def url(self, prefix=None): """ @param prefix: str the prefix registered in module prefixes, by default prefix='/' @return: string , the url of this item from the prefix parent '/' is the root """ if not prefix: prefix = URL_SEPARATOR # will go through parents until i found a parent that is validated by this prefix #log_debug('url - item: %s, prefix: "%s"' % (self, prefix)) url_list = [] item = self found = False while item: if prefixes.validate_item_by_prefix(prefix, item, item_caller=self): url_list.append(prefix) found = True break url_list.append(item.name) item = item.parent if found: url_list.reverse() if url_list and url_list[0] == URL_SEPARATOR: url_list[0] = '' if len(url_list) == 1 and url_list[0] == '': #this is the root item url_text = URL_SEPARATOR else: url_text = URL_SEPARATOR.join(url_list) else: #log_debug('...getting url of item with prefix "%s" not found' % prefix) url_text = '' #log_debug('... return: %s' % url_text) return url_text @staticmethod def get_new_sid(): return uuid.uuid4().hex @staticmethod def is_string(value, raise_err=False): if is_string(value): return True else: if raise_err: raise TypeError('expected string type, received %s' % type(value)) return False @staticmethod def is_integer(value, raise_err=False): if is_integer(value): return True else: if raise_err: raise TypeError('expected integer type, received %s' % type(value)) return False