Exemplo n.º 1
0
  if klass is None:
    klass = _importClass(type_class_path)

  global property_sheet_generating_portal_type_set

  accessor_holder_list = []

  if portal_type_name not in property_sheet_generating_portal_type_set:
    # LOG("ERP5Type.dynamic", INFO,
    #     "Filling accessor holder list for portal_type " + portal_type_name)

    property_sheet_generating_portal_type_set.add(portal_type_name)
    try:
      # Initialize ZODB Property Sheets accessor holders
      accessor_holder_list = createAllAccessorHolderList(site,
                                                         portal_type_name,
                                                         portal_type,
                                                         klass)

      base_category_set = set(attribute_dict['_categories'])
      for accessor_holder in accessor_holder_list:
        base_category_set.update(accessor_holder._categories)
        attribute_dict['constraints'].extend(accessor_holder.constraints)

      attribute_dict['_categories'] = list(base_category_set)
    finally:
      property_sheet_generating_portal_type_set.remove(portal_type_name)

  # LOG("ERP5Type.dynamic", INFO,
  #     "Filled accessor holder list for portal_type %s (%s)" % \
  #     (portal_type_name, accessor_holder_list))
Exemplo n.º 2
0
def generatePortalTypeClass(site, portal_type_name):
    """
  Given a portal type, look up in Types Tool the corresponding
  Base Type object holding the definition of this portal type,
  and computes __bases__ and __dict__ for the class that will
  be created to represent this portal type

  Returns tuple with 4 items:
    - base_tuple: a tuple of classes to be used as __bases__
    - base_category_list: categories defined on the portal type
        (and portal type only: this excludes property sheets)
    - interface_list: list of zope interfaces the portal type implements
    - attribute dictionary: any additional attributes to put on the class
  """
    # LOG("ERP5Type.dynamic", INFO, "Loading portal type " + portal_type_name)

    global core_portal_type_class_dict

    portal_type_category_list = []
    attribute_dict = dict(portal_type=portal_type_name,
                          _categories=[],
                          constraints=[])

    if portal_type_name in core_portal_type_class_dict:
        if not core_portal_type_class_dict[portal_type_name]['generating']:
            # Loading the (full) outer portal type class
            core_portal_type_class_dict[portal_type_name]['generating'] = True
        else:
            # Loading the inner portal type class without any mixin,
            # interface or Property Sheet
            klass = _importClass(
                document_class_registry.get(
                    core_portal_type_class_dict[portal_type_name]
                    ['type_class']))

            # LOG("ERP5Type.dynamic", INFO,
            #     "Loaded portal type %s (INNER)" % portal_type_name)

            # Don't do anything else, just allow to load fully the outer
            # portal type class
            return ((klass, ), [], [], attribute_dict)

    # Do not use __getitem__ (or _getOb) because portal_type may exist in a
    # type provider other than Types Tool.
    portal_type = getattr(site.portal_types, portal_type_name, None)

    type_class = None

    if portal_type is not None:
        # type_class has a compatibility getter that should return
        # something even if the field is not set (i.e. Base Type object
        # was not migrated yet). It only works if factory_method_id is set.
        type_class = portal_type.getTypeClass()

        # The Tools used to have 'Folder' or None as type_class instead of
        # 'NAME Tool', so make sure the type_class is correct
        #
        # NOTE: under discussion so might be removed later on
        if portal_type_name.endswith('Tool') and type_class in ('Folder',
                                                                None):
            type_class = portal_type_name.replace(' ', '')

        mixin_list = portal_type.getTypeMixinList()
        interface_list = portal_type.getTypeInterfaceList()
        portal_type_category_list = portal_type.getTypeBaseCategoryList()
        attribute_dict['_categories'] = portal_type_category_list[:]
        acquire_local_role = bool(portal_type.getTypeAcquireLocalRole())
    else:
        LOG(
            "ERP5Type.dynamic", WARNING,
            "Cannot find a portal type definition for '%s', trying to guess..."
            % portal_type_name)

    # But if neither factory_init_method_id nor type_class are set on
    # the portal type, we have to try to guess, for compatibility.
    # Moreover, some tools, such as 'Activity Tool', don't have any
    # portal type
    if type_class is None:
        if portal_type_name in core_portal_type_class_dict:
            # Only happen when portal_types is empty (e.g. when creating a
            # new ERP5Site)
            type_class = core_portal_type_class_dict[portal_type_name][
                'type_class']
        else:
            # Try to figure out a coresponding document class from the
            # document side.  This can happen when calling newTempAmount for
            # instance:
            #  Amount has no corresponding Base Type and will never have one
            #  But the semantic of newTempXXX requires us to create an
            #  object using the Amount Document, so we promptly do it:
            type_class = portal_type_name.replace(' ', '')

        mixin_list = []
        interface_list = []
        acquire_local_role = True

    if type_class is None:
        raise AttributeError('Document class is not defined on Portal Type ' + \
                               portal_type_name)

    klass = None
    if '.' in type_class:
        type_class_path = type_class
    else:
        type_class_path = None

        # Skip any document within ERP5Type Product as it is needed for
        # bootstrapping anyway
        type_class_namespace = document_class_registry.get(type_class, '')
        if not (type_class_namespace.startswith('Products.ERP5Type')
                or portal_type_name in core_portal_type_class_dict):
            module = None
            if portal_type_name.endswith('Tool'):
                import erp5.component.tool
                module = erp5.component.tool.find_load_module(type_class)

            # Tool Component was introduced recently and some Tool have already been
            # migrated as Document Component
            if module is None:
                import erp5.component.document
                module = erp5.component.document.find_load_module(type_class)
            if module is not None:
                try:
                    klass = getattr(module, type_class)
                except AttributeError:
                    LOG(
                        "ERP5Type.dynamic", WARNING,
                        "Could not get class '%s' in Component module %r, fallback on filesystem"
                        % (type_class, module))

        if klass is None:
            type_class_path = document_class_registry.get(type_class)
            if type_class_path is None:
                raise AttributeError(
                    'Document class %s has not been registered:'
                    ' cannot import it as base of Portal Type %s' %
                    (type_class, portal_type_name))

    if klass is None:
        try:
            klass = _importClass(type_class_path)
        except ImportError:
            error_msg = 'Could not import %s of Portal Type %s' % (
                type_class, portal_type_name)

            LOG("ERP5Type.Dynamic", WARNING, error_msg, error=True)
            raise AttributeError(error_msg)

    global property_sheet_generating_portal_type_set

    accessor_holder_list = []

    if portal_type_name not in property_sheet_generating_portal_type_set:
        # LOG("ERP5Type.dynamic", INFO,
        #     "Filling accessor holder list for portal_type " + portal_type_name)

        property_sheet_generating_portal_type_set.add(portal_type_name)
        try:
            # Initialize ZODB Property Sheets accessor holders
            accessor_holder_list = createAllAccessorHolderList(
                site, portal_type_name, portal_type, klass)

            base_category_set = set(attribute_dict['_categories'])
            for accessor_holder in accessor_holder_list:
                base_category_set.update(accessor_holder._categories)
                attribute_dict['constraints'].extend(
                    accessor_holder.constraints)

            attribute_dict['_categories'] = list(base_category_set)
        finally:
            property_sheet_generating_portal_type_set.remove(portal_type_name)

    # LOG("ERP5Type.dynamic", INFO,
    #     "Filled accessor holder list for portal_type %s (%s)" % \
    #     (portal_type_name, accessor_holder_list))

    mixin_class_list = []
    if mixin_list:
        # Only one Mixin class per ZODB Component (!= FS) where module_name ==
        # class_name, name ending with 'Mixin'.
        #
        # Rationale: same as Document/Interface; consistent naming; avoid a
        # registry like there used to be with FS.
        import erp5.component.mixin
        for mixin in mixin_list:
            mixin_module = erp5.component.mixin.find_load_module(mixin)
            mixin_class = None
            if mixin_module is not None:
                try:
                    mixin_class = getattr(mixin_module, mixin)
                except AttributeError:
                    LOG(
                        "ERP5Type.dynamic", WARNING,
                        "Could not get class '%s' in Component module %r, fallback on filesystem"
                        % (mixin, mixin_module))

            if mixin_class is None:
                mixin_class = _importClass(mixin_class_registry[mixin])

            mixin_class_list.append(mixin_class)

    base_class_list = [klass] + accessor_holder_list + mixin_class_list + [
        # _getAcquireLocalRoles is accessed by security machinery, so it needs to
        # be fast: make it a ConstantGetter while we have access to portal_type
        # configuration.
        ACQUIRE_LOCAL_ROLE_GETTER_DICT[acquire_local_role],
    ]

    interface_class_list = []
    if interface_list:
        # Filesystem Interfaces may have defined several Interfaces in one file
        # but only *one* Interface per ZODB Component where module_name ==
        # class_name, name starting with 'I'.
        #
        # Rationale: same as Document/Mixin; consistent naming; avoid a registry
        # like there used to be for Mixin or importing all class in
        # Products.ERP5Type.interfaces.__init__.py.
        import erp5.component.interface
        from Products.ERP5Type import interfaces as filesystem_interfaces
        for interface in interface_list:
            interface_module = erp5.component.interface.find_load_module(
                interface)
            interface_class = None
            if interface_module is not None:
                try:
                    interface_class = getattr(interface_module, interface)
                except AttributeError:
                    LOG(
                        "ERP5Type.dynamic", WARNING,
                        "Could not get class '%s' in Component module %r, fallback on filesystem"
                        % (interface, interface_module))

            if interface_class is None:
                interface_class = getattr(filesystem_interfaces, interface)

            interface_class_list.append(interface_class)

    if portal_type_name in core_portal_type_class_dict:
        core_portal_type_class_dict[portal_type_name]['generating'] = False

    attribute_dict['_restricted_setter_set'] = {
        method
        for ancestor in base_class_list
        for permissions in getattr(ancestor, '__ac_permissions__', ())
        if permissions[0] not in ('Access contents information',
                                  'Modify portal content')
        for method in permissions[1] if method.startswith('set')
    }

    attribute_dict['_restricted_getter_set'] = {
        method
        for ancestor in base_class_list
        for permissions in getattr(ancestor, '__ac_permissions__', ())
        if permissions[0] not in ('Access contents information', )
        for method in permissions[1] if method.startswith('get')
    }

    #LOG("ERP5Type.dynamic", INFO,
    #    "Portal type %s loaded with bases %s" \
    #        % (portal_type_name, repr(base_class_list)))

    return (tuple(base_class_list), portal_type_category_list,
            interface_class_list, attribute_dict)
Exemplo n.º 3
0
def generatePortalTypeClass(site, portal_type_name):
  """
  Given a portal type, look up in Types Tool the corresponding
  Base Type object holding the definition of this portal type,
  and computes __bases__ and __dict__ for the class that will
  be created to represent this portal type

  Returns tuple with 4 items:
    - base_tuple: a tuple of classes to be used as __bases__
    - base_category_list: categories defined on the portal type
        (and portal type only: this excludes property sheets)
    - interface_list: list of zope interfaces the portal type implements
    - attribute dictionary: any additional attributes to put on the class
  """
  # LOG("ERP5Type.dynamic", INFO, "Loading portal type " + portal_type_name)

  global core_portal_type_class_dict

  portal_type_category_list = []
  attribute_dict = dict(portal_type=portal_type_name,
                        _categories=[],
                        constraints=[])

  if portal_type_name in core_portal_type_class_dict:
    if not core_portal_type_class_dict[portal_type_name]['generating']:
      # Loading the (full) outer portal type class
      core_portal_type_class_dict[portal_type_name]['generating'] = True
    else:
      # Loading the inner portal type class without any mixin,
      # interface or Property Sheet
      klass = _importClass(document_class_registry.get(
        core_portal_type_class_dict[portal_type_name]['type_class']))

      # LOG("ERP5Type.dynamic", INFO,
      #     "Loaded portal type %s (INNER)" % portal_type_name)

      # Don't do anything else, just allow to load fully the outer
      # portal type class
      return ((klass,), [], [], attribute_dict)

  # Do not use __getitem__ (or _getOb) because portal_type may exist in a
  # type provider other than Types Tool.
  portal_type = getattr(site.portal_types, portal_type_name, None)

  type_class = None

  if portal_type is not None:
    # type_class has a compatibility getter that should return
    # something even if the field is not set (i.e. Base Type object
    # was not migrated yet). It only works if factory_method_id is set.
    type_class = portal_type.getTypeClass()

    # The Tools used to have 'Folder' or None as type_class instead of
    # 'NAME Tool', so make sure the type_class is correct
    #
    # NOTE: under discussion so might be removed later on
    if portal_type_name.endswith('Tool') and type_class in ('Folder', None):
      type_class = portal_type_name.replace(' ', '')

    mixin_list = portal_type.getTypeMixinList()
    interface_list = portal_type.getTypeInterfaceList()
    portal_type_category_list = portal_type.getTypeBaseCategoryList()
    attribute_dict['_categories'] = portal_type_category_list[:]
  else:
    LOG("ERP5Type.dynamic", WARNING,
        "Cannot find a portal type definition for '%s', trying to guess..."
        % portal_type_name)

  # But if neither factory_init_method_id nor type_class are set on
  # the portal type, we have to try to guess, for compatibility.
  # Moreover, some tools, such as 'Activity Tool', don't have any
  # portal type
  if type_class is None:
    if portal_type_name in core_portal_type_class_dict:
      # Only happen when portal_types is empty (e.g. when creating a
      # new ERP5Site)
      type_class = core_portal_type_class_dict[portal_type_name]['type_class']
    else:
      # Try to figure out a coresponding document class from the
      # document side.  This can happen when calling newTempAmount for
      # instance:
      #  Amount has no corresponding Base Type and will never have one
      #  But the semantic of newTempXXX requires us to create an
      #  object using the Amount Document, so we promptly do it:
      type_class = portal_type_name.replace(' ', '')

    mixin_list = []
    interface_list = []

  if type_class is None:
    raise AttributeError('Document class is not defined on Portal Type %s' \
            % portal_type_name)

  if '.' in type_class:
    type_class_path = type_class
  else:
    type_class_path = document_class_registry.get(type_class)
    if type_class_path is None:
      raise AttributeError('Document class %s has not been registered:'
                           ' cannot import it as base of Portal Type %s'
                           % (type_class, portal_type_name))

  klass = _importClass(type_class_path)

  global property_sheet_generating_portal_type_set

  accessor_holder_list = []

  if portal_type_name not in property_sheet_generating_portal_type_set:
    # LOG("ERP5Type.dynamic", INFO,
    #     "Filling accessor holder list for portal_type " + portal_type_name)

    property_sheet_generating_portal_type_set.add(portal_type_name)
    try:
      # Initialize ZODB Property Sheets accessor holders
      accessor_holder_list = createAllAccessorHolderList(site,
                                                         portal_type_name,
                                                         portal_type,
                                                         klass)

      base_category_set = set(attribute_dict['_categories'])
      for accessor_holder in accessor_holder_list:
        base_category_set.update(accessor_holder._categories)
        attribute_dict['constraints'].extend(accessor_holder.constraints)

      attribute_dict['_categories'] = list(base_category_set)
    finally:
      property_sheet_generating_portal_type_set.remove(portal_type_name)

  # LOG("ERP5Type.dynamic", INFO,
  #     "Filled accessor holder list for portal_type %s (%s)" % \
  #     (portal_type_name, accessor_holder_list))

  mixin_path_list = []
  if mixin_list:
    mixin_path_list = map(mixin_class_registry.__getitem__, mixin_list)
  mixin_class_list = map(_importClass, mixin_path_list)

  base_class_list = [klass] + accessor_holder_list + mixin_class_list

  interface_class_list = []
  if interface_list:
    from Products.ERP5Type import interfaces
    interface_class_list = [getattr(interfaces, name)
                            for name in interface_list]

  if portal_type_name in core_portal_type_class_dict:
    core_portal_type_class_dict[portal_type_name]['generating'] = False

  #LOG("ERP5Type.dynamic", INFO,
  #    "Portal type %s loaded with bases %s" \
  #        % (portal_type_name, repr(base_class_list)))

  return (tuple(base_class_list),
          portal_type_category_list,
          interface_class_list,
          attribute_dict)
Exemplo n.º 4
0
def generatePortalTypeClass(site, portal_type_name):
  """
  Given a portal type, look up in Types Tool the corresponding
  Base Type object holding the definition of this portal type,
  and computes __bases__ and __dict__ for the class that will
  be created to represent this portal type

  Returns tuple with 4 items:
    - base_tuple: a tuple of classes to be used as __bases__
    - base_category_list: categories defined on the portal type
        (and portal type only: this excludes property sheets)
    - interface_list: list of zope interfaces the portal type implements
    - attribute dictionary: any additional attributes to put on the class
  """
  # LOG("ERP5Type.dynamic", INFO, "Loading portal type " + portal_type_name)

  global core_portal_type_class_dict

  portal_type_category_list = []
  attribute_dict = dict(portal_type=portal_type_name,
                        _categories=[],
                        constraints=[])

  if portal_type_name in core_portal_type_class_dict:
    if not core_portal_type_class_dict[portal_type_name]['generating']:
      # Loading the (full) outer portal type class
      core_portal_type_class_dict[portal_type_name]['generating'] = True
    else:
      # Loading the inner portal type class without any mixin,
      # interface or Property Sheet
      klass = _importClass(document_class_registry.get(
        core_portal_type_class_dict[portal_type_name]['type_class']))

      # LOG("ERP5Type.dynamic", INFO,
      #     "Loaded portal type %s (INNER)" % portal_type_name)

      # Don't do anything else, just allow to load fully the outer
      # portal type class
      return ((klass,), [], [], attribute_dict)

  # Do not use __getitem__ (or _getOb) because portal_type may exist in a
  # type provider other than Types Tool.
  portal_type = getattr(site.portal_types, portal_type_name, None)

  type_class = None

  if portal_type is not None:
    # type_class has a compatibility getter that should return
    # something even if the field is not set (i.e. Base Type object
    # was not migrated yet). It only works if factory_method_id is set.
    type_class = portal_type.getTypeClass()

    # The Tools used to have 'Folder' or None as type_class instead of
    # 'NAME Tool', so make sure the type_class is correct
    #
    # NOTE: under discussion so might be removed later on
    if portal_type_name.endswith('Tool') and type_class in ('Folder', None):
      type_class = portal_type_name.replace(' ', '')

    mixin_list = portal_type.getTypeMixinList()
    interface_list = portal_type.getTypeInterfaceList()
    portal_type_category_list = portal_type.getTypeBaseCategoryList()
    attribute_dict['_categories'] = portal_type_category_list[:]
  else:
    LOG("ERP5Type.dynamic", WARNING,
        "Cannot find a portal type definition for '%s', trying to guess..."
        % portal_type_name)

  # But if neither factory_init_method_id nor type_class are set on
  # the portal type, we have to try to guess, for compatibility.
  # Moreover, some tools, such as 'Activity Tool', don't have any
  # portal type
  if type_class is None:
    if portal_type_name in core_portal_type_class_dict:
      # Only happen when portal_types is empty (e.g. when creating a
      # new ERP5Site)
      type_class = core_portal_type_class_dict[portal_type_name]['type_class']
    else:
      # Try to figure out a coresponding document class from the
      # document side.  This can happen when calling newTempAmount for
      # instance:
      #  Amount has no corresponding Base Type and will never have one
      #  But the semantic of newTempXXX requires us to create an
      #  object using the Amount Document, so we promptly do it:
      type_class = portal_type_name.replace(' ', '')

    mixin_list = []
    interface_list = []

  if type_class is None:
    raise AttributeError('Document class is not defined on Portal Type ' + \
                           portal_type_name)

  klass = None
  if '.' in type_class:
    type_class_path = type_class
  else:
    type_class_path = None

    # Skip any document within ERP5Type Product as it is needed for
    # bootstrapping anyway
    type_class_namespace = document_class_registry.get(type_class, '')
    if not (type_class_namespace.startswith('Products.ERP5Type') or
            portal_type_name in core_portal_type_class_dict):
      import erp5.component.document
      module = erp5.component.document.find_load_module(type_class)
      if module is not None:
        try:
          klass = getattr(module, type_class)
        except AttributeError:
          LOG("ERP5Type.dynamic", WARNING,
              "Could not get class '%s' in Component module '%s'" % \
              (type_class,
               module_fullname))

    if klass is None:
      type_class_path = document_class_registry.get(type_class)
      if type_class_path is None:
        raise AttributeError('Document class %s has not been registered:'
                             ' cannot import it as base of Portal Type %s'
                             % (type_class, portal_type_name))

  if klass is None:
    klass = _importClass(type_class_path)

  global property_sheet_generating_portal_type_set

  accessor_holder_list = []

  if portal_type_name not in property_sheet_generating_portal_type_set:
    # LOG("ERP5Type.dynamic", INFO,
    #     "Filling accessor holder list for portal_type " + portal_type_name)

    property_sheet_generating_portal_type_set.add(portal_type_name)
    try:
      # Initialize ZODB Property Sheets accessor holders
      accessor_holder_list = createAllAccessorHolderList(site,
                                                         portal_type_name,
                                                         portal_type,
                                                         klass)

      base_category_set = set(attribute_dict['_categories'])
      for accessor_holder in accessor_holder_list:
        base_category_set.update(accessor_holder._categories)
        attribute_dict['constraints'].extend(accessor_holder.constraints)

      attribute_dict['_categories'] = list(base_category_set)
    finally:
      property_sheet_generating_portal_type_set.remove(portal_type_name)

  # LOG("ERP5Type.dynamic", INFO,
  #     "Filled accessor holder list for portal_type %s (%s)" % \
  #     (portal_type_name, accessor_holder_list))

  mixin_path_list = []
  if mixin_list:
    mixin_path_list = map(mixin_class_registry.__getitem__, mixin_list)
  mixin_class_list = map(_importClass, mixin_path_list)

  base_class_list = [klass] + accessor_holder_list + mixin_class_list

  interface_class_list = []
  if interface_list:
    from Products.ERP5Type import interfaces
    interface_class_list = [getattr(interfaces, name)
                            for name in interface_list]

  if portal_type_name in core_portal_type_class_dict:
    core_portal_type_class_dict[portal_type_name]['generating'] = False

  #LOG("ERP5Type.dynamic", INFO,
  #    "Portal type %s loaded with bases %s" \
  #        % (portal_type_name, repr(base_class_list)))

  return (tuple(base_class_list),
          portal_type_category_list,
          interface_class_list,
          attribute_dict)