text: # (C) Copyright 2007-2020 Enthought, Inc., Austin, TX
  # All rights reserved.
  #
  # This software is provided without warranty under the terms of the BSD
  # license included in LICENSE.txt and may be redistributed only under
  # the conditions described in the aforementioned license. The license
  # is also available online at http://www.enthought.com/licenses/BSD.txt
  #
  # Thanks for using Enthought open source!
  
  """ An IPython kernel plugin. """
  
  import logging
  import warnings
  
  # Enthought library imports.
  from envisage.api import (
      bind_extension_point,
      ExtensionPoint,
      Plugin,
      ServiceOffer,
  )
  from traits.api import Bool, Instance, List
  
  # Constants kept around for backwards compatibility.
  # These will be removed in a future release.
  # Extension point IDs.
  SERVICE_OFFERS = "envisage.service_offers"
  IPYTHON_NAMESPACE = "ipython_plugin.namespace"
  
  # Protocol for the contributed service offer.
  IPYTHON_KERNEL_PROTOCOL = (
      "envisage.plugins.ipython_kernel.internal_ipkernel.InternalIPKernel")
  
  logger = logging.getLogger(__name__)
  
  
  class IPythonKernelPlugin(Plugin):
      """ An IPython kernel plugin. """
  
      #: The plugin unique identifier.
      id = "envisage.plugins.ipython_kernel"
  
      #: The plugin name (suitable for displaying to the user).
      name = "IPython embedded kernel plugin"
  
      #: Extension point for objects contributed to the IPython kernel namespace.
      IPYTHON_NAMESPACE = 'ipython_plugin.namespace'
  
      #: Ipython kernel namespace ExtensionPoint
      kernel_namespace = ExtensionPoint(
          List,
          id=IPYTHON_NAMESPACE,
          desc="""
  
          Variables to add to the IPython kernel namespace.
          This is a list of tuples (name, value).
  
          """,
      )
  
      #: Service offers contributed by this plugin.
      service_offers = List(contributes_to=SERVICE_OFFERS)
  
      # Protocol for the contributed service offer.
      IPYTHON_KERNEL_PROTOCOL = 'envisage.plugins.ipython_kernel.internal_ipkernel.InternalIPKernel'  # noqa: E501
  
      #: Whether to initialize the kernel when the service is created.
      #: The default is ``False```, for backwards compatibility. It will change
      #: to ``True`` in a future version of Envisage. External users wanting
      #: to use the future behaviour now should pass ``init_ipkernel=True``
      #: when creating the plugin.
      init_ipkernel = Bool(False)
  
      def stop(self):
          """ Stop the plugin. """
          self._destroy_kernel()
  
      # Private traits and methods
  
      #: The InternalIPKernel instance provided by the service.
      _kernel = Instance(IPYTHON_KERNEL_PROTOCOL)
  
      def _create_kernel(self):
          from .internal_ipkernel import InternalIPKernel
  
          # This shouldn't happen with a normal lifecycle, but add a warning
          # just in case.
          if self._kernel is not None:
              warnings.warn(
                  "A kernel already exists. " "No new kernel will be created.",
                  RuntimeWarning,
              )
              return
  
          logger.debug("Creating the embedded IPython kernel")
          kernel = self._kernel = InternalIPKernel()
          bind_extension_point(
              kernel, "initial_namespace", IPYTHON_NAMESPACE, self.application
          )
          if self.init_ipkernel:
              kernel.init_ipkernel()
          else:
              warnings.warn(
                  (
                      "In the future, the IPython kernel will be initialized "
                      "automatically at creation time. To enable this "
                      "future behaviour now, create the plugin using "
                      "IPythonKernelPlugin(init_ipkernel=True)"
                  ),
                  DeprecationWarning,
              )
  
          return kernel
  
      def _destroy_kernel(self):
          """
          Destroy any existing kernel.
          """
          if self._kernel is None:
              return
  
          logger.debug("Shutting down the embedded IPython kernel")
          self._kernel.shutdown()
          self._kernel = None
  
      def _service_offers_default(self):
          ipython_kernel_service_offer = ServiceOffer(
              protocol=IPYTHON_KERNEL_PROTOCOL, factory=self._create_kernel,
          )
          return [ipython_kernel_service_offer]
  