nbval icon indicating copy to clipboard operation
nbval copied to clipboard

nbval cannot identify notebook kernel name

Open michaelaye opened this issue 7 years ago • 11 comments

These 2 lines

from pytelescope import basetypes as bt
from astropy import units as u

import without errors in the notebook, but running nbval like so:

pytest --nbval test_basetypes.ipynb

throws this myriad of errors (below, in the "details" section), I guess something isn't installed properly?

Using nbval 0.9.1 from conda-forge and these pytest modules are installed:

$ conda list pytest                                                               (py37)
# packages in environment at /Users/klay6683/miniconda3/envs/py37:
#
# Name                    Version                   Build  Channel
pytest                    3.8.2                 py37_1000    conda-forge
pytest-arraydiff          0.2                        py_0    conda-forge
pytest-astropy            0.4.0                      py_0    conda-forge
pytest-cache              1.0                      py37_1
pytest-cov                2.6.0                      py_0    conda-forge
pytest-doctestplus        0.1.3                      py_0    conda-forge
pytest-openfiles          0.3.0                      py_0    conda-forge
pytest-pep8               1.0.6                      py_1    conda-forge
pytest-remotedata         0.3.0                      py_0    conda-forge

on a macOS 10.13.6

============================= test session starts ============================== platform darwin -- Python 3.7.0, pytest-3.8.2, py-1.6.0, pluggy-0.7.1 rootdir: /Users/klay6683/Dropbox/src/pytelescope, inifile: plugins: remotedata-0.3.0, pep8-1.0.6, openfiles-0.3.0, doctestplus-0.1.3, cov-2.6.0, arraydiff-0.2, nbval-0.9.1 collected 2 items

test_basetypes.ipynb EE [100%]

==================================== ERRORS ==================================== _____________ ERROR at setup of tests/test_basetypes.ipynb::Cell 0 _____________

self = <CallInfo when='setup' exception: No such kernel named conda-env-py37-py> func = <function call_runtest_hook.. at 0x113537510> when = 'setup', treat_keyboard_interrupt_as_exception = False

def __init__(self, func, when, treat_keyboard_interrupt_as_exception=False):
    #: context of invocation: one of "setup", "call",
    #: "teardown", "memocollect"
    self.when = when
    self.start = time()
    try:
      self.result = func()

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/_pytest/runner.py:201:


lambda: ihook(item=item, **kwds), when=when, treat_keyboard_interrupt_as_exception=item.config.getvalue("usepdb"), )

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/_pytest/runner.py:183:


self = <_HookCaller 'pytest_runtest_setup'>, args = () kwargs = {'item': <IPyNbCell 'Cell 0'>}, notincall = set()

def __call__(self, *args, **kwargs):
    if args:
        raise TypeError("hook calling supports only keyword arguments")
    assert not self.is_historic()
    if self.argnames:
        notincall = set(self.argnames) - set(['__multicall__']) - set(
            kwargs.keys())
        if notincall:
            warnings.warn(
                "Argument(s) {} which are declared in the hookspec "
                "can not be found in this hook call"
                .format(tuple(notincall)),
                stacklevel=2,
            )
  return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/pluggy/hooks.py:258:


self = <_pytest.config.PytestPluginManager object at 0x1051379e8> hook = <_HookCaller 'pytest_runtest_setup'> methods = [<HookImpl plugin_name='nose', plugin=<module '_pytest.nose' from '/Users/klay6683/miniconda3/envs/py37/lib/python3.7/... '_pytest.skipping' from '/Users/klay6683/miniconda3/envs/py37/lib/python3.7/site-packages/_pytest/skipping.py'>>, ...] kwargs = {'item': <IPyNbCell 'Cell 0'>}

def _hookexec(self, hook, methods, kwargs):
    # called from all hookcaller instances.
    # enable_tracing will set its own wrapping function at self._inner_hookexec
  return self._inner_hookexec(hook, methods, kwargs)

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/pluggy/manager.py:67:


hook = <_HookCaller 'pytest_runtest_setup'> methods = [<HookImpl plugin_name='nose', plugin=<module '_pytest.nose' from '/Users/klay6683/miniconda3/envs/py37/lib/python3.7/... '_pytest.skipping' from '/Users/klay6683/miniconda3/envs/py37/lib/python3.7/site-packages/_pytest/skipping.py'>>, ...] kwargs = {'item': <IPyNbCell 'Cell 0'>}

self._inner_hookexec = lambda hook, methods, kwargs: \
    hook.multicall(
        methods, kwargs,
      firstresult=hook.spec_opts.get('firstresult'),
    )

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/pluggy/manager.py:61:


hook_impls = [<HookImpl plugin_name='nose', plugin=<module '_pytest.nose' from '/Users/klay6683/miniconda3/envs/py37/lib/python3.7/... '_pytest.skipping' from '/Users/klay6683/miniconda3/envs/py37/lib/python3.7/site-packages/_pytest/skipping.py'>>, ...] caller_kwargs = {'item': <IPyNbCell 'Cell 0'>}, firstresult = False

def _multicall(hook_impls, caller_kwargs, firstresult=False):
    """Execute a call into multiple python functions/methods and return the
    result(s).

    ``caller_kwargs`` comes from _HookCaller.__call__().
    """
    __tracebackhide__ = True
    results = []
    excinfo = None
    try:  # run impl and wrapper setup functions in a loop
        teardowns = []
        try:
            for hook_impl in reversed(hook_impls):
                try:
                    args = [caller_kwargs[argname] for argname in hook_impl.argnames]
                except KeyError:
                    for argname in hook_impl.argnames:
                        if argname not in caller_kwargs:
                            raise HookCallError(
                                "hook call must provide argument %r" % (argname,))

                if hook_impl.hookwrapper:
                    try:
                        gen = hook_impl.function(*args)
                        next(gen)   # first yield
                        teardowns.append(gen)
                    except StopIteration:
                        _raise_wrapfail(gen, "did not yield")
                else:
                    res = hook_impl.function(*args)
                    if res is not None:
                        results.append(res)
                        if firstresult:  # halt further impl calls
                            break
        except BaseException:
            excinfo = sys.exc_info()
    finally:
        if firstresult:  # first result hooks return a single value
            outcome = _Result(results[0] if results else None, excinfo)
        else:
            outcome = _Result(results, excinfo)

        # run all wrapper post-yield blocks
        for gen in reversed(teardowns):
            try:
                gen.send(outcome)
                _raise_wrapfail(gen, "has second yield")
            except StopIteration:
                pass
      return outcome.get_result()

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/pluggy/callers.py:201:


self = <pluggy.callers._Result object at 0x11354a080>

def get_result(self):
    """Get the result(s) for this hook call.

        If the hook was marked as a ``firstresult`` only a single value
        will be returned otherwise a list of results.
        """
    __tracebackhide__ = True
    if self._excinfo is None:
        return self._result
    else:
        ex = self._excinfo
        if _py3:
          raise ex[1].with_traceback(ex[2])

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/pluggy/callers.py:76:


hook_impls = [<HookImpl plugin_name='nose', plugin=<module '_pytest.nose' from '/Users/klay6683/miniconda3/envs/py37/lib/python3.7/... '_pytest.skipping' from '/Users/klay6683/miniconda3/envs/py37/lib/python3.7/site-packages/_pytest/skipping.py'>>, ...] caller_kwargs = {'item': <IPyNbCell 'Cell 0'>}, firstresult = False

def _multicall(hook_impls, caller_kwargs, firstresult=False):
    """Execute a call into multiple python functions/methods and return the
    result(s).

    ``caller_kwargs`` comes from _HookCaller.__call__().
    """
    __tracebackhide__ = True
    results = []
    excinfo = None
    try:  # run impl and wrapper setup functions in a loop
        teardowns = []
        try:
            for hook_impl in reversed(hook_impls):
                try:
                    args = [caller_kwargs[argname] for argname in hook_impl.argnames]
                except KeyError:
                    for argname in hook_impl.argnames:
                        if argname not in caller_kwargs:
                            raise HookCallError(
                                "hook call must provide argument %r" % (argname,))

                if hook_impl.hookwrapper:
                    try:
                        gen = hook_impl.function(*args)
                        next(gen)   # first yield
                        teardowns.append(gen)
                    except StopIteration:
                        _raise_wrapfail(gen, "did not yield")
                else:
                  res = hook_impl.function(*args)

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/pluggy/callers.py:180:


item = <IPyNbCell 'Cell 0'>

def pytest_runtest_setup(item):
    _update_current_test_var(item, "setup")
  item.session._setupstate.prepare(item)

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/_pytest/runner.py:104:


self = <_pytest.runner.SetupState object at 0x112dcf0f0> colitem = <IPyNbCell 'Cell 0'>

def prepare(self, colitem):
    """ setup objects along the collector chain to the test-method
            and teardown previously setup objects."""
    needed_collectors = colitem.listchain()
    self._teardown_towards(needed_collectors)

    # check if the last collection node has raised an error
    for col in self.stack:
        if hasattr(col, "_prepare_exc"):
            six.reraise(*col._prepare_exc)
    for col in needed_collectors[len(self.stack) :]:
        self.stack.append(col)
        try:
          col.setup()

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/_pytest/runner.py:370:


self = <IPyNbFile 'test_basetypes.ipynb'>

def setup(self):
    """
        Called by pytest to setup the collector cells in .
        Here we start a kernel and setup the sanitize patterns.
        """

    if self.parent.config.option.current_env:
        kernel_name = CURRENT_ENV_KERNEL_NAME
    else:
        kernel_name = self.nb.metadata.get(
            'kernelspec', {}).get('name', 'python')
  self.kernel = RunningKernel(kernel_name, str(self.fspath.dirname))

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/nbval/plugin.py:232:


self = <nbval.kernel.RunningKernel object at 0x113978a20> kernel_name = 'conda-env-py37-py' cwd = '/Users/klay6683/Dropbox/src/pytelescope/tests'

def __init__(self, kernel_name, cwd=None):
    """
        Initialise a new kernel
        specify that matplotlib is inline and connect the stderr.
        Stores the active kernel process and its manager.
        """

    self.km, self.kc = start_new_kernel(
        kernel_name=kernel_name,
        stderr=open(os.devnull, 'w'),
      cwd=cwd,
    )

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/nbval/kernel.py:88:


startup_timeout = 60, kernel_name = 'conda-env-py37-py' kwargs = {'cwd': '/Users/klay6683/Dropbox/src/pytelescope/tests', 'stderr': <_io.TextIOWrapper name='/dev/null' mode='w' encoding='UTF-8'>} km = <jupyter_client.manager.KernelManager object at 0x1139789e8>

def start_new_kernel(startup_timeout=60, kernel_name='python', **kwargs):
    """Start a new kernel, and return its Manager and Client"""
    logger.debug('Starting new kernel: "%s"' % kernel_name)
    km = KernelManager(kernel_name=kernel_name,
                       kernel_spec_manager=NbvalKernelspecManager())
  km.start_kernel(**kwargs)

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/nbval/kernel.py:53:


self = <jupyter_client.manager.KernelManager object at 0x1139789e8> kw = {'cwd': '/Users/klay6683/Dropbox/src/pytelescope/tests', 'stderr': <_io.TextIOWrapper name='/dev/null' mode='w' encoding='UTF-8'>} extra_arguments = []

def start_kernel(self, **kw):
    """Starts a kernel on this host in a separate process.

        If random ports (port=0) are being used, this method must be called
        before the channels are created.

        Parameters
        ----------
        `**kw` : optional
             keyword arguments that are passed down to build the kernel_cmd
             and launching the kernel (e.g. Popen kwargs).
        """
    if self.transport == 'tcp' and not is_local_ip(self.ip):
        raise RuntimeError("Can only launch a kernel on a local interface. "
                           "This one is not: %s."
                           "Make sure that the '*_address' attributes are "
                           "configured properly. "
                           "Currently valid addresses are: %s" % (self.ip, local_ips())
                           )

    # write connection file / get default ports
    self.write_connection_file()

    # save kwargs for use in restart
    self._launch_args = kw.copy()
    # build the Popen cmd
    extra_arguments = kw.pop('extra_arguments', [])
  kernel_cmd = self.format_kernel_cmd(extra_arguments=extra_arguments)

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/jupyter_client/manager.py:246:


self = <jupyter_client.manager.KernelManager object at 0x1139789e8> extra_arguments = []

def format_kernel_cmd(self, extra_arguments=None):
    """replace templated args (e.g. {connection_file})"""
    extra_arguments = extra_arguments or []
    if self.kernel_cmd:
        cmd = self.kernel_cmd + extra_arguments
    else:
      cmd = self.kernel_spec.argv + extra_arguments

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/jupyter_client/manager.py:170:


self = <jupyter_client.manager.KernelManager object at 0x1139789e8>

@property
def kernel_spec(self):
    if self._kernel_spec is None and self.kernel_name is not '':
      self._kernel_spec = self.kernel_spec_manager.get_kernel_spec(self.kernel_name)

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/jupyter_client/manager.py:82:


self = <nbval.kernel.NbvalKernelspecManager object at 0x113978828> kernel_name = 'conda-env-py37-py'

def get_kernel_spec(self, kernel_name):
    """Returns a :class:`KernelSpec` instance for the given kernel_name.

        Raises :exc:`NoSuchKernel` if the given kernel name is not found.
        """
    if kernel_name == CURRENT_ENV_KERNEL_NAME:
        return self.kernel_spec_class(
            resource_dir=ipykernel.kernelspec.RESOURCES,
            **ipykernel.kernelspec.get_kernel_dict())
    else:
      return super(NbvalKernelspecManager, self).get_kernel_spec(kernel_name)

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/nbval/kernel.py:45:


self = <nbval.kernel.NbvalKernelspecManager object at 0x113978828> kernel_name = 'conda-env-py37-py'

def get_kernel_spec(self, kernel_name):
    """Returns a :class:`KernelSpec` instance for the given kernel_name.

        Raises :exc:`NoSuchKernel` if the given kernel name is not found.
        """
    if not _is_valid_kernel_name(kernel_name):
        self.log.warning("Kernelspec name %r is invalid: %s", kernel_name,
                         _kernel_name_description)

    resource_dir = self._find_spec_directory(kernel_name.lower())
    if resource_dir is None:
      raise NoSuchKernel(kernel_name)

E jupyter_client.kernelspec.NoSuchKernel: No such kernel named conda-env-py37-py

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/jupyter_client/kernelspec.py:236: NoSuchKernel _____________ ERROR at setup of tests/test_basetypes.ipynb::Cell 1 _____________

self = <CallInfo when='setup' exception: No such kernel named conda-env-py37-py> func = <function call_runtest_hook.. at 0x113537bf8> when = 'setup', treat_keyboard_interrupt_as_exception = False

def __init__(self, func, when, treat_keyboard_interrupt_as_exception=False):
    #: context of invocation: one of "setup", "call",
    #: "teardown", "memocollect"
    self.when = when
    self.start = time()
    try:
      self.result = func()

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/_pytest/runner.py:201:


lambda: ihook(item=item, **kwds), when=when, treat_keyboard_interrupt_as_exception=item.config.getvalue("usepdb"), )

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/_pytest/runner.py:183:


self = <_HookCaller 'pytest_runtest_setup'>, args = () kwargs = {'item': <IPyNbCell 'Cell 1'>}, notincall = set()

def __call__(self, *args, **kwargs):
    if args:
        raise TypeError("hook calling supports only keyword arguments")
    assert not self.is_historic()
    if self.argnames:
        notincall = set(self.argnames) - set(['__multicall__']) - set(
            kwargs.keys())
        if notincall:
            warnings.warn(
                "Argument(s) {} which are declared in the hookspec "
                "can not be found in this hook call"
                .format(tuple(notincall)),
                stacklevel=2,
            )
  return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/pluggy/hooks.py:258:


self = <_pytest.config.PytestPluginManager object at 0x1051379e8> hook = <_HookCaller 'pytest_runtest_setup'> methods = [<HookImpl plugin_name='nose', plugin=<module '_pytest.nose' from '/Users/klay6683/miniconda3/envs/py37/lib/python3.7/... '_pytest.skipping' from '/Users/klay6683/miniconda3/envs/py37/lib/python3.7/site-packages/_pytest/skipping.py'>>, ...] kwargs = {'item': <IPyNbCell 'Cell 1'>}

def _hookexec(self, hook, methods, kwargs):
    # called from all hookcaller instances.
    # enable_tracing will set its own wrapping function at self._inner_hookexec
  return self._inner_hookexec(hook, methods, kwargs)

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/pluggy/manager.py:67:


hook = <_HookCaller 'pytest_runtest_setup'> methods = [<HookImpl plugin_name='nose', plugin=<module '_pytest.nose' from '/Users/klay6683/miniconda3/envs/py37/lib/python3.7/... '_pytest.skipping' from '/Users/klay6683/miniconda3/envs/py37/lib/python3.7/site-packages/_pytest/skipping.py'>>, ...] kwargs = {'item': <IPyNbCell 'Cell 1'>}

self._inner_hookexec = lambda hook, methods, kwargs: \
    hook.multicall(
        methods, kwargs,
      firstresult=hook.spec_opts.get('firstresult'),
    )

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/pluggy/manager.py:61:


hook_impls = [<HookImpl plugin_name='nose', plugin=<module '_pytest.nose' from '/Users/klay6683/miniconda3/envs/py37/lib/python3.7/... '_pytest.skipping' from '/Users/klay6683/miniconda3/envs/py37/lib/python3.7/site-packages/_pytest/skipping.py'>>, ...] caller_kwargs = {'item': <IPyNbCell 'Cell 1'>}, firstresult = False

def _multicall(hook_impls, caller_kwargs, firstresult=False):
    """Execute a call into multiple python functions/methods and return the
    result(s).

    ``caller_kwargs`` comes from _HookCaller.__call__().
    """
    __tracebackhide__ = True
    results = []
    excinfo = None
    try:  # run impl and wrapper setup functions in a loop
        teardowns = []
        try:
            for hook_impl in reversed(hook_impls):
                try:
                    args = [caller_kwargs[argname] for argname in hook_impl.argnames]
                except KeyError:
                    for argname in hook_impl.argnames:
                        if argname not in caller_kwargs:
                            raise HookCallError(
                                "hook call must provide argument %r" % (argname,))

                if hook_impl.hookwrapper:
                    try:
                        gen = hook_impl.function(*args)
                        next(gen)   # first yield
                        teardowns.append(gen)
                    except StopIteration:
                        _raise_wrapfail(gen, "did not yield")
                else:
                    res = hook_impl.function(*args)
                    if res is not None:
                        results.append(res)
                        if firstresult:  # halt further impl calls
                            break
        except BaseException:
            excinfo = sys.exc_info()
    finally:
        if firstresult:  # first result hooks return a single value
            outcome = _Result(results[0] if results else None, excinfo)
        else:
            outcome = _Result(results, excinfo)

        # run all wrapper post-yield blocks
        for gen in reversed(teardowns):
            try:
                gen.send(outcome)
                _raise_wrapfail(gen, "has second yield")
            except StopIteration:
                pass
      return outcome.get_result()

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/pluggy/callers.py:201:


self = <pluggy.callers._Result object at 0x113de11d0>

def get_result(self):
    """Get the result(s) for this hook call.

        If the hook was marked as a ``firstresult`` only a single value
        will be returned otherwise a list of results.
        """
    __tracebackhide__ = True
    if self._excinfo is None:
        return self._result
    else:
        ex = self._excinfo
        if _py3:
          raise ex[1].with_traceback(ex[2])

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/pluggy/callers.py:76:


hook_impls = [<HookImpl plugin_name='nose', plugin=<module '_pytest.nose' from '/Users/klay6683/miniconda3/envs/py37/lib/python3.7/... '_pytest.skipping' from '/Users/klay6683/miniconda3/envs/py37/lib/python3.7/site-packages/_pytest/skipping.py'>>, ...] caller_kwargs = {'item': <IPyNbCell 'Cell 1'>}, firstresult = False

def _multicall(hook_impls, caller_kwargs, firstresult=False):
    """Execute a call into multiple python functions/methods and return the
    result(s).

    ``caller_kwargs`` comes from _HookCaller.__call__().
    """
    __tracebackhide__ = True
    results = []
    excinfo = None
    try:  # run impl and wrapper setup functions in a loop
        teardowns = []
        try:
            for hook_impl in reversed(hook_impls):
                try:
                    args = [caller_kwargs[argname] for argname in hook_impl.argnames]
                except KeyError:
                    for argname in hook_impl.argnames:
                        if argname not in caller_kwargs:
                            raise HookCallError(
                                "hook call must provide argument %r" % (argname,))

                if hook_impl.hookwrapper:
                    try:
                        gen = hook_impl.function(*args)
                        next(gen)   # first yield
                        teardowns.append(gen)
                    except StopIteration:
                        _raise_wrapfail(gen, "did not yield")
                else:
                  res = hook_impl.function(*args)

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/pluggy/callers.py:180:


item = <IPyNbCell 'Cell 1'>

def pytest_runtest_setup(item):
    _update_current_test_var(item, "setup")
  item.session._setupstate.prepare(item)

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/_pytest/runner.py:104:


self = <_pytest.runner.SetupState object at 0x112dcf0f0> colitem = <IPyNbCell 'Cell 1'>

def prepare(self, colitem):
    """ setup objects along the collector chain to the test-method
            and teardown previously setup objects."""
    needed_collectors = colitem.listchain()
    self._teardown_towards(needed_collectors)

    # check if the last collection node has raised an error
    for col in self.stack:
        if hasattr(col, "_prepare_exc"):
          six.reraise(*col._prepare_exc)

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/_pytest/runner.py:366:


tp = <class 'jupyter_client.kernelspec.NoSuchKernel'>, value = None, tb = None

def reraise(tp, value, tb=None):
    try:
        if value is None:
            value = tp()
        if value.__traceback__ is not tb:
          raise value.with_traceback(tb)

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/six.py:692:


self = <_pytest.runner.SetupState object at 0x112dcf0f0> colitem = <IPyNbCell 'Cell 0'>

def prepare(self, colitem):
    """ setup objects along the collector chain to the test-method
            and teardown previously setup objects."""
    needed_collectors = colitem.listchain()
    self._teardown_towards(needed_collectors)

    # check if the last collection node has raised an error
    for col in self.stack:
        if hasattr(col, "_prepare_exc"):
            six.reraise(*col._prepare_exc)
    for col in needed_collectors[len(self.stack) :]:
        self.stack.append(col)
        try:
          col.setup()

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/_pytest/runner.py:370:


self = <IPyNbFile 'test_basetypes.ipynb'>

def setup(self):
    """
        Called by pytest to setup the collector cells in .
        Here we start a kernel and setup the sanitize patterns.
        """

    if self.parent.config.option.current_env:
        kernel_name = CURRENT_ENV_KERNEL_NAME
    else:
        kernel_name = self.nb.metadata.get(
            'kernelspec', {}).get('name', 'python')
  self.kernel = RunningKernel(kernel_name, str(self.fspath.dirname))

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/nbval/plugin.py:232:


self = <nbval.kernel.RunningKernel object at 0x113978a20> kernel_name = 'conda-env-py37-py' cwd = '/Users/klay6683/Dropbox/src/pytelescope/tests'

def __init__(self, kernel_name, cwd=None):
    """
        Initialise a new kernel
        specify that matplotlib is inline and connect the stderr.
        Stores the active kernel process and its manager.
        """

    self.km, self.kc = start_new_kernel(
        kernel_name=kernel_name,
        stderr=open(os.devnull, 'w'),
      cwd=cwd,
    )

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/nbval/kernel.py:88:


startup_timeout = 60, kernel_name = 'conda-env-py37-py' kwargs = {'cwd': '/Users/klay6683/Dropbox/src/pytelescope/tests', 'stderr': <_io.TextIOWrapper name='/dev/null' mode='w' encoding='UTF-8'>} km = <jupyter_client.manager.KernelManager object at 0x1139789e8>

def start_new_kernel(startup_timeout=60, kernel_name='python', **kwargs):
    """Start a new kernel, and return its Manager and Client"""
    logger.debug('Starting new kernel: "%s"' % kernel_name)
    km = KernelManager(kernel_name=kernel_name,
                       kernel_spec_manager=NbvalKernelspecManager())
  km.start_kernel(**kwargs)

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/nbval/kernel.py:53:


self = <jupyter_client.manager.KernelManager object at 0x1139789e8> kw = {'cwd': '/Users/klay6683/Dropbox/src/pytelescope/tests', 'stderr': <_io.TextIOWrapper name='/dev/null' mode='w' encoding='UTF-8'>} extra_arguments = []

def start_kernel(self, **kw):
    """Starts a kernel on this host in a separate process.

        If random ports (port=0) are being used, this method must be called
        before the channels are created.

        Parameters
        ----------
        `**kw` : optional
             keyword arguments that are passed down to build the kernel_cmd
             and launching the kernel (e.g. Popen kwargs).
        """
    if self.transport == 'tcp' and not is_local_ip(self.ip):
        raise RuntimeError("Can only launch a kernel on a local interface. "
                           "This one is not: %s."
                           "Make sure that the '*_address' attributes are "
                           "configured properly. "
                           "Currently valid addresses are: %s" % (self.ip, local_ips())
                           )

    # write connection file / get default ports
    self.write_connection_file()

    # save kwargs for use in restart
    self._launch_args = kw.copy()
    # build the Popen cmd
    extra_arguments = kw.pop('extra_arguments', [])
  kernel_cmd = self.format_kernel_cmd(extra_arguments=extra_arguments)

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/jupyter_client/manager.py:246:


self = <jupyter_client.manager.KernelManager object at 0x1139789e8> extra_arguments = []

def format_kernel_cmd(self, extra_arguments=None):
    """replace templated args (e.g. {connection_file})"""
    extra_arguments = extra_arguments or []
    if self.kernel_cmd:
        cmd = self.kernel_cmd + extra_arguments
    else:
      cmd = self.kernel_spec.argv + extra_arguments

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/jupyter_client/manager.py:170:


self = <jupyter_client.manager.KernelManager object at 0x1139789e8>

@property
def kernel_spec(self):
    if self._kernel_spec is None and self.kernel_name is not '':
      self._kernel_spec = self.kernel_spec_manager.get_kernel_spec(self.kernel_name)

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/jupyter_client/manager.py:82:


self = <nbval.kernel.NbvalKernelspecManager object at 0x113978828> kernel_name = 'conda-env-py37-py'

def get_kernel_spec(self, kernel_name):
    """Returns a :class:`KernelSpec` instance for the given kernel_name.

        Raises :exc:`NoSuchKernel` if the given kernel name is not found.
        """
    if kernel_name == CURRENT_ENV_KERNEL_NAME:
        return self.kernel_spec_class(
            resource_dir=ipykernel.kernelspec.RESOURCES,
            **ipykernel.kernelspec.get_kernel_dict())
    else:
      return super(NbvalKernelspecManager, self).get_kernel_spec(kernel_name)

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/nbval/kernel.py:45:


self = <nbval.kernel.NbvalKernelspecManager object at 0x113978828> kernel_name = 'conda-env-py37-py'

def get_kernel_spec(self, kernel_name):
    """Returns a :class:`KernelSpec` instance for the given kernel_name.

        Raises :exc:`NoSuchKernel` if the given kernel name is not found.
        """
    if not _is_valid_kernel_name(kernel_name):
        self.log.warning("Kernelspec name %r is invalid: %s", kernel_name,
                         _kernel_name_description)

    resource_dir = self._find_spec_directory(kernel_name.lower())
    if resource_dir is None:
      raise NoSuchKernel(kernel_name)

E jupyter_client.kernelspec.NoSuchKernel: No such kernel named conda-env-py37-py

../../../../miniconda3/envs/py37/lib/python3.7/site-packages/jupyter_client/kernelspec.py:236: NoSuchKernel =============================== warnings summary =============================== /Users/klay6683/miniconda3/envs/py37/lib/python3.7/site-packages/jupyter_client/manager.py:72: DeprecationWarning: KernelManager._kernel_name_changed is deprecated in traitlets 4.1: use @observe and @unobserve instead. def _kernel_name_changed(self, name, old, new):

-- Docs: https://docs.pytest.org/en/latest/warnings.html ===================== 1 warnings, 2 error in 0.46 seconds ======================

michaelaye avatar Oct 19 '18 20:10 michaelaye

The actual error is that the notebook is saved with a kernel name that cannot be found. This should be solvable by adding the --current-env flag. The other question is whether a better error message can be given from nbval, as I assume this is a likely enough exception that a more helpful error is warranted.

vidartf avatar Oct 22 '18 07:10 vidartf

And just to make it clear, there are actually only two exceptions here, but it prints the full stack trace of the error (with context) for each exception, making the log rather verbose.

vidartf avatar Oct 22 '18 07:10 vidartf

sorry, I don't know what the --current-env is or what it is supposed to do. I scanned your docs but it isn't mentioned? I made sure that the notebook was run with an available kernel and that the same conda env is active when I run pytest so I don't understand why a certain kernel is not being found? It should just be the same as is currently active?

michaelaye avatar Oct 25 '18 23:10 michaelaye

Hmm, we should probably add the flag to the docs then. For now, here is the text from py.test --help:

--current-env         Force test execution to use a python kernel in the same enviornment that py.test was launched from.

The error you are seeing is E jupyter_client.kernelspec.NoSuchKernel: No such kernel named conda-env-py37-py. I don't know enough about conda kernel setup to debug it further than that. Maybe @takluyver knows more?

vidartf avatar Oct 26 '18 12:10 vidartf

PS: Does it work if you use the --current-env flag?

vidartf avatar Oct 26 '18 12:10 vidartf

oh, I see, it's an py.test flag? yes, it seems to be working with it! (now only all those failing tests ;)) I just never heard of this flag, because using pytest within my conda envs never required using it, that's why I am a bit perplexed why the nbval plugin requires it? I'm still using the same executable that is embedded in that currently active env? I guess the plugin should look up the current $CONDA_PREFIX which is dynamically pointing to the current env?

$ echo $CONDA_PREFIX                                                                                           (py37)
/Users/klay6683/miniconda3/envs/py37

michaelaye avatar Oct 26 '18 18:10 michaelaye

But, actually, simply looking up the path ( if it's a path issue at all) should suffice:

$ echo $PATH                                                                                                   (py37)
/Users/klay6683/miniconda3/envs/py37/bin /usr/local/bin /usr/bin /bin /usr/sbin /sbin /opt/X11/bin /Library/TeX/texbin /usr/local/sbin

b/c that's just the point of conda, to dynamically change it based on the currently active env.

michaelaye avatar Oct 26 '18 18:10 michaelaye

The current way it works takes its logic from the question: How would you test a non-python notebook (e.g. julia)? The current way is to look at the kernel name that the notebook was saved with, and try to use that. The --current-env flag is a flag that nbval adds to pytest, but it only makes sense for Python notebooks.

If there is another default logic that could consistently be applied, I'd be open to consider it :+1:

vidartf avatar Oct 27 '18 10:10 vidartf

The problem is caused by how the name of the conda env is stored in the jupyter notebook. They don't match if the kernel registration was done by a popular tool like nb_conda_kernels. In my case, my conda env is py37, but the notebook searches for a conda env conda-env-py37-py. I hope that the code that searches for the appropriate env could somehow be improved?

michaelaye avatar May 22 '20 20:05 michaelaye

I hope that the code that searches for the appropriate env could somehow be improved?

I would hope so too, but I'm not proficient enough in that part of the Jupyter stack to figure that out. Any contributors who want to help out here would be very welcome!

vidartf avatar Jun 02 '20 16:06 vidartf

i think this is less jupyter stack than realizing that any jupyter kernel name has not necessarily anything to do with the conda env name. but this is also a prob of pytest throwing thousands of errors without being more helpful of simply saying, "so i tried the current env but either there's no python or your package isn't installed, now what?" I'll think about this a bit more when I have my next test-dev round, possibly in a hackathon at the end of June.

michaelaye avatar Jun 02 '20 20:06 michaelaye