Skip to content
Closed

Me #545

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions CONTRIBUTING.md.tmp.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<h1>Contributing</h1>

<p>Welcome!</p>

<p>For contributing tips, follow the <a href="https://jupyter.readthedocs.io/en/latest/contributor/content-contributor.html">Jupyter Contributing Guide</a>.
Please make sure to follow the <a href="https://github.com/jupyter/governance/blob/master/conduct/code_of_conduct.md">Jupyter Code of Conduct</a>.</p>

<h2>Installing ipykernel for development</h2>

<p>ipykernel is a pure Python package, so setting up for development is the same as most other Python projects:</p>

<p>```bash</p>

<h1>clone the repo</h1>

<p>git clone https://github.com/ipython/ipykernel
cd ipykernel</p>

<h1>do a 'development' or 'editable' install with pip:</h1>

<p>pip install -e .
```</p>

<h2>Releasing ipykernel</h2>

<p>Releasing ipykernel is <em>almost</em> standard for a Python package:</p>

<ul>
<li>set version for release</li>
<li>make and publish tag</li>
<li>publish release to PyPI</li>
<li>set version back to development</li>
</ul>

<p>The one extra step for ipykernel is that we need to make separate wheels for Python 2 and 3
because the bundled kernelspec has different contents for Python 2 and 3. This
affects only the 4.x branch of ipykernel as the 5+ version is only compatible
Python 3.</p>

<p>The full release process is available below:</p>

<p>```bash</p>

<h1>make sure version is set in ipykernel/_version.py</h1>

<p>VERSION="4.9.0"</p>

<h1>commit the version and make a release tag</h1>

<p>git add ipykernel/_version.py
git commit -m "release $VERSION"
git tag -am "release $VERSION" $VERSION</p>

<h1>push the changes to the repo</h1>

<p>git push
git push --tags</p>

<h1>publish the release to PyPI</h1>

<h1>note the extra <code>python2 setup.py bdist_wheel</code> for creating</h1>

<h1>the wheel for Python 2</h1>

<p>pip install --upgrade twine
git clean -xfd
python3 setup.py sdist bdist<em>wheel
python2 setup.py bdist</em>wheel # the extra step for the 4.x branch.
twine upload dist/*</p>

<h1>set the version back to '.dev' in ipykernel/_version.py</h1>

<h1>e.g. 4.10.0.dev if we just released 4.9.0</h1>

<p>git add ipykernel/_version.py
git commit -m "back to dev"
git push
```</p>
63 changes: 53 additions & 10 deletions ipykernel/kernelspec.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,37 +57,51 @@ def get_kernel_dict(extra_arguments=None):
}


def write_kernel_spec(path=None, overrides=None, extra_arguments=None):
def write_kernel_spec(path=None, overrides=None, extra_arguments=None, conda_env=False):
"""Write a kernel spec directory to `path`

If `path` is not specified, a temporary directory is created.
If `overrides` is given, the kernelspec JSON is updated before writing.

The path to the kernelspec is always returned.
"""
if path is None:
path = os.path.join(tempfile.mkdtemp(suffix='_kernels'), KERNEL_NAME)

# stage resources
shutil.copytree(RESOURCES, path)
# write kernel.json
kernel_dict = get_kernel_dict(extra_arguments)
if conda_env:
# argv is the list that jupyter invokes via a subprocess call
argv = kernel_dict.get('argv', [])
# The first element of argv is something like /home/user/miniconda/envs/<conda env name>/bin/python
# We want to pull out the <conda env name> so we can pass it to conda run. It's the third-from-last
# element in the path, so we'll get that with the os-specific path split
conda_env_name = argv[0].split(os.sep)[-3]
# Format the new argv and put it back in the original dict as the argv key
new_argv = ['conda', 'run', '-n', conda_env_name, 'python'] + argv[1:]
kernel_dict['argv'] = new_argv

if overrides:
kernel_dict.update(overrides)
with open(pjoin(path, 'kernel.json'), 'w') as f:
json.dump(kernel_dict, f, indent=1)

return path


def install(kernel_spec_manager=None, user=False, kernel_name=KERNEL_NAME, display_name=None,
<<<<<<< HEAD
prefix=None, profile=None, conda_env=False):
=======
prefix=None, profile=None, env=None):
>>>>>>> master
"""Install the IPython kernelspec for Jupyter

Parameters
----------

kernel_spec_manager: KernelSpecManager [optional]
A KernelSpecManager to use for installation.
If none provided, a default instance will be created.
Expand All @@ -103,14 +117,19 @@ def install(kernel_spec_manager=None, user=False, kernel_name=KERNEL_NAME, displ
prefix: str, optional
Specify an install prefix for the kernelspec.
This is needed to install into a non-default location, such as a conda/virtual-env.
<<<<<<< HEAD
conda_env: bool, optional
Format the kernelspec so that it properly activates the conda environment, if your kernel
is running the python executable out of a conda environment.
=======
env: dict, optional
A dictionary of extra environment variables for the kernel.
These will be added to the current environment variables before the
kernel is started
>>>>>>> master

Returns
-------

The path where the kernelspec was installed.
"""
if kernel_spec_manager is None:
Expand All @@ -130,9 +149,13 @@ def install(kernel_spec_manager=None, user=False, kernel_name=KERNEL_NAME, displ
overrides["display_name"] = 'Python %i [profile=%s]' % (sys.version_info[0], profile)
else:
extra_arguments = None
<<<<<<< HEAD
path = write_kernel_spec(overrides=overrides, extra_arguments=extra_arguments, conda_env=conda_env)
=======
if env:
overrides['env'] = env
path = write_kernel_spec(overrides=overrides, extra_arguments=extra_arguments)
>>>>>>> master
dest = kernel_spec_manager.install_kernel_spec(
path, kernel_name=kernel_name, user=user, prefix=prefix)
# cleanup afterward
Expand All @@ -147,12 +170,12 @@ def install(kernel_spec_manager=None, user=False, kernel_name=KERNEL_NAME, displ
class InstallIPythonKernelSpecApp(Application):
"""Dummy app wrapping argparse"""
name = 'ipython-kernel-install'

def initialize(self, argv=None):
if argv is None:
argv = sys.argv[1:]
self.argv = argv

def start(self):
import argparse
parser = argparse.ArgumentParser(prog=self.name,
Expand All @@ -174,6 +197,25 @@ def start(self):
parser.add_argument('--sys-prefix', action='store_const', const=sys.prefix, dest='prefix',
help="Install to Python's sys.prefix."
" Shorthand for --prefix='%s'. For use in conda/virtual-envs." % sys.prefix)
<<<<<<< HEAD
parser.add_argument('--conda', action='store_true', dest='conda_env',
default=False,
help="Ensure that the conda environment is properly activated for kernel launch")
# Temporary addition, will be removed after dev is finished
parser.add_argument('--pdb', action="store_true", help="Enable PDB debugging on exception",
default=False)
opts = parser.parse_args(self.argv)
if opts.pdb:
import pdb
# set the pdb_hook as the except hook for all exceptions
def pdb_hook(exctype, value, traceback):
pdb.post_mortem(traceback)
sys.excepthook = pdb_hook

try:
dest = install(user=opts.user, kernel_name=opts.name, profile=opts.profile,
prefix=opts.prefix, display_name=opts.display_name, conda_env=opts.conda_env)
=======
parser.add_argument('--env', action='append', nargs=2, metavar=('ENV', 'VALUE'),
help="Set environment variables for the kernel.")
opts = parser.parse_args(self.argv)
Expand All @@ -182,6 +224,7 @@ def start(self):
try:
dest = install(user=opts.user, kernel_name=opts.name, profile=opts.profile,
prefix=opts.prefix, display_name=opts.display_name, env=opts.env)
>>>>>>> master
except OSError as e:
if e.errno == errno.EACCES:
print(e, file=sys.stderr)
Expand Down