def getFields(context, interface=None, annotation=None): """Generator of all [zope.schema] fields that will be displayed in a container listing. Redefines alchemist.ui.container.getFields, making use of the @listing_columns property of the ModelDescriptor class. """ if interface is None: domain_model = proxy.removeSecurityProxy(context.domain_model) interface = utils.get_derived_table_schema(domain_model) if annotation is None: annotation = utils.get_descriptor(interface) for field_name in annotation.listing_columns: if field_name in interface.names(): # !+FIELD_KEYERROR yield interface[field_name]
def fossilize_obj(cls, obj, interfaceArg=None, useAttrCache=False, mapClassType={}, **kwargs): """ Fossilizes the object, using the fossil provided by `interface`. :param interfaceArg: the target fossile type :type interfaceArg: IFossil, NoneType, or dict :param useAttrCache: use caching of attributes if same fields are repeated for a fossil :type useAttrCache: boolean """ interface = cls.__obtainInterface(obj, interfaceArg) name = interface.getName() fossilName = cls.__extractFossilName(name) result = {} # cache method names for each interface names = cls.__fossilInterfaceCache.get(interface) if names is None: names = interface.names(all=True) cls.__fossilInterfaceCache[interface] = names ### for methodName in names: method = interface[methodName] tags = method.getTaggedValueTags() isAttribute = False # In some cases it is better to use the attribute cache to # speed up the fossilization cacheUsed = False if useAttrCache: try: methodResult = cls.__fossilAttrsCache[ obj._p_oid][methodName] cacheUsed = True except KeyError: pass if not cacheUsed: # Please use 'produce' as little as possible; # there is almost always a more elegant and modular solution! if 'produce' in tags: methodResult = method.getTaggedValue('produce')(obj) else: attr = getattr(obj, methodName) if callable(attr): try: methodResult = attr() except: logging.getLogger('indico.fossilize').error( "Problem fossilizing '%r' with '%s'" % (obj, interfaceArg)) raise else: methodResult = attr isAttribute = True if hasattr(obj, "_p_oid"): cls.__fossilAttrsCache.setdefault( obj._p_oid, {})[methodName] = methodResult if 'filterBy' in tags: if 'filters' not in kwargs: raise Exception('No filters defined!') filterName = method.getTaggedValue('filterBy') if filterName in kwargs['filters']: filterBy = kwargs['filters'][filterName] else: raise Exception("No filter '%s' defined!" % filterName) else: filterBy = None # Result conversion if 'result' in tags: targetInterface = method.getTaggedValue('result') #targetInterface = globals()[targetInterfaceName] methodResult = Fossilizable.fossilizeIterable( methodResult, targetInterface, filterBy=filterBy, mapClassType=mapClassType, **kwargs) # Conversion function if 'convert' in tags: convertFunction = method.getTaggedValue('convert') converterArgNames = inspect.getargspec(convertFunction)[0] converterArgs = dict((name, kwargs[name]) for name in converterArgNames if name in kwargs) try: methodResult = convertFunction(methodResult, **converterArgs) except: logging.getLogger('indico.fossilize').error( "Problem fossilizing '%r' with '%s' (%s)" % (obj, interfaceArg, methodName)) raise # Re-name the attribute produced by the method if 'name' in tags: attrName = method.getTaggedValue('name') elif isAttribute: attrName = methodName else: attrName = cls.__extractName(methodName) # In case the name contains dots, each of the 'domains' but the # last one are translated into nested dictionnaries. For example, # if we want to re-name an attribute into "foo.bar.tofu", the # corresponding fossilized attribute will be of the form: # {"foo":{"bar":{"tofu": res,...},...},...} # instead of: # {"foo.bar.tofu": res, ...} current = result attrList = attrName.split('.') while len(attrList) > 1: attr = attrList.pop(0) if attr not in current: current[attr] = {} current = current[attr] # For the last attribute level current[attrList[0]] = methodResult if "_type" in result or "_fossil" in result: raise InvalidFossilException('"_type" or "_fossil"' ' cannot be a fossil attribute name') else: result["_type"] = mapClassType.get(obj.__class__.__name__, obj.__class__.__name__) if fossilName: #we check that it's not an empty string result["_fossil"] = fossilName else: result["_fossil"] = "" return result
def fossilize_obj(cls, obj, interfaceArg=None, useAttrCache=False, mapClassType=None, **kwargs): """ Fossilizes the object, using the fossil provided by `interface`. :param interfaceArg: the target fossile type :type interfaceArg: IFossil, NoneType, or dict :param useAttrCache: use caching of attributes if same fields are repeated for a fossil :type useAttrCache: boolean """ mapClassType = dict(mapClassType or {}, AvatarUserWrapper='Avatar', AvatarProvisionalWrapper='Avatar', EmailPrincipal='Email') interface = cls.__obtainInterface(obj, interfaceArg) name = interface.getName() fossilName = cls.__extractFossilName(name) result = {} # cache method names for each interface names = _fossil_cache.fossilInterface.get(interface) if names is None: names = interface.names(all=True) _fossil_cache.fossilInterface[interface] = names ### for methodName in names: method = interface[methodName] tags = method.getTaggedValueTags() isAttribute = False if 'onlyIf' in tags: onlyIf = method.getTaggedValue('onlyIf') # If the condition not in the kwargs or the condition False, we do not fossilize the method if not kwargs.get(onlyIf, False): continue # In some cases it is better to use the attribute cache to # speed up the fossilization cacheUsed = False if useAttrCache: try: methodResult = _fossil_cache.fossilAttrs[obj._p_oid][methodName] cacheUsed = True except KeyError: pass if not cacheUsed: # Please use 'produce' as little as possible; # there is almost always a more elegant and modular solution! if 'produce' in tags: methodResult = method.getTaggedValue('produce')(obj) else: attr = getattr(obj, methodName) if callable(attr): try: methodResult = attr() except: logging.getLogger('indico.fossilize').error("Problem fossilizing '%r' with '%s'", obj, interfaceArg) raise else: methodResult = attr isAttribute = True if hasattr(obj, "_p_oid"): _fossil_cache.fossilAttrs.setdefault(obj._p_oid, {})[methodName] = methodResult if 'filterBy' in tags: if 'filters' not in kwargs: raise Exception('No filters defined!') filterName = method.getTaggedValue('filterBy') if filterName in kwargs['filters']: filterBy = kwargs['filters'][filterName] else: raise Exception("No filter '%s' defined!" % filterName) else: filterBy = None # Result conversion if 'result' in tags: targetInterface = method.getTaggedValue('result') #targetInterface = globals()[targetInterfaceName] methodResult = Fossilizable.fossilizeIterable( methodResult, targetInterface, filterBy=filterBy, mapClassType=mapClassType, **kwargs) # Conversion function if 'convert' in tags: convertFunction = method.getTaggedValue('convert') converterArgNames = inspect.getargspec(convertFunction)[0] converterArgs = dict((name, kwargs[name]) for name in converterArgNames if name in kwargs) if '_obj' in converterArgNames: converterArgs['_obj'] = obj try: methodResult = convertFunction(methodResult, **converterArgs) except: logging.getLogger('indico.fossilize').error("Problem fossilizing '%r' with '%s' (%s)", obj, interfaceArg, methodName) raise # Re-name the attribute produced by the method if 'name' in tags: attrName = method.getTaggedValue('name') elif isAttribute: attrName = methodName else: attrName = cls.__extractName(methodName) # In case the name contains dots, each of the 'domains' but the # last one are translated into nested dictionnaries. For example, # if we want to re-name an attribute into "foo.bar.tofu", the # corresponding fossilized attribute will be of the form: # {"foo":{"bar":{"tofu": res,...},...},...} # instead of: # {"foo.bar.tofu": res, ...} current = result attrList = attrName.split('.') while len(attrList) > 1: attr = attrList.pop(0) if attr not in current: current[attr] = {} current = current[attr] # For the last attribute level current[attrList[0]] = methodResult if "_type" in result or "_fossil" in result: raise InvalidFossilException('"_type" or "_fossil"' ' cannot be a fossil attribute name') else: result["_type"] = mapClassType.get(obj.__class__.__name__, obj.__class__.__name__) if fossilName: #we check that it's not an empty string result["_fossil"] = fossilName else: result["_fossil"] = "" return result