docs: def get_factory_details(self, name):
          # type: (str) -> Dict[str, Any]
          """
          Retrieves a dictionary with details about the given factory
  
          * ``name``: The factory name
          * ``bundle``: The Bundle object of the bundle providing the factory
          * ``properties``: Copy of the components properties defined by the
            factory
          * ``requirements``: List of the requirements defined by the factory
  
            * ``id``: Requirement ID (field where it is injected)
            * ``specification``: Specification of the required service
            * ``aggregate``: If True, multiple services will be injected
            * ``optional``: If True, the requirement is optional
  
          * ``services``: List of the specifications of the services provided by
            components of this factory
          * ``handlers``: Dictionary of the non-built-in handlers required by
            this factory.
            The dictionary keys are handler IDs, and it contains a tuple with:
  
            * A copy of the configuration of the handler (0)
            * A flag indicating if the handler is present or not
  
          :param name: The name of a factory
          :return: A dictionary describing the factory
          :raise ValueError: Invalid factory
          """
          with self.__factories_lock:
              try:
                  factory = self.__factories[name]
              except KeyError:
                  raise ValueError("Unknown factory '{0}'".format(name))
  
              context = getattr(factory, constants.IPOPO_FACTORY_CONTEXT)
              assert isinstance(context, FactoryContext)
  
              result = {}  # type: Dict[Any, Any]
              # Factory name & bundle
              result["name"] = context.name
              result["bundle"] = context.bundle_context.get_bundle()
  
              # Configurable properties
              # Name -> Default value
              result["properties"] = {
                  prop_name: context.properties.get(prop_name)
                  for prop_name in context.properties_fields.values()
              }
  
              # Requirements (list of dictionaries)
              reqs = result["requirements"] = []
              handler_requires = context.get_handler(constants.HANDLER_REQUIRES)
              if handler_requires is not None:
                  for field, requirement in handler_requires.items():
                      reqs.append(
                          {
                              "id": field,
                              "specification": requirement.specification,
                              "aggregate": requirement.aggregate,
                              "optional": requirement.optional,
                              "filter": requirement.original_filter,
                          }
                      )
  
              # Provided services (list of list of specifications)
              handler_provides = context.get_handler(constants.HANDLER_PROVIDES)
              if handler_provides is not None:
                  result["services"] = [
                      specs_controller[0] for specs_controller in handler_provides
                  ]
              else:
                  result["services"] = []
  
              # Other handlers
              handlers = set(context.get_handlers_ids())
              handlers.difference_update(
                  (
                      constants.HANDLER_PROPERTY,
                      constants.HANDLER_PROVIDES,
                      constants.HANDLER_REQUIRES,
                  )
              )
              result["handlers"] = {
                  handler: copy.deepcopy(context.get_handler(handler))
                  for handler in handlers
              }
  
              return result