#!/usr/bin/env python
import argparse
import atexit
import os
import sys
import shutil
import sys
import tempfile
from glob import glob
try:
from urllib.request import urlopen
except ImportError:
from urllib2 import urlopen
from subprocess import Popen as Popen_orig, PIPE
[docs]class Popen(Popen_orig):
[docs] def wait(self):
rv = super(Popen, self).wait()
assert rv == 0
return rv
# https://stackoverflow.com/a/5227009/4166604
[docs]def which(file, windows_extension='exe'):
if sys.platform=='win32':
file=file+os.path.extsep+windows_extension
for path in os.environ["PATH"].split(os.pathsep):
if os.path.exists(os.path.join(path, file)):
return os.path.join(path, file)
return None
[docs]def find(name, path):
for root, dirs, files in os.walk(path):
if name in files:
return os.path.join(root, name)
[docs]def patch_site(site, config_dir, data_dir):
with open(site, 'a') as fid:
fid.write('''
os.environ['JUPYTER_CONFIG_DIR'] = '''
'''os.path.abspath(os.path.join(os.path.dirname(__file__), {}))
os.environ['JUPYTER_DATA_DIR'] = '''
'''os.path.abspath(os.path.join(os.path.dirname(__file__), {}))'''.format(
repr(config_dir),
repr(data_dir)))
[docs]def get_parser():
parser = argparse.ArgumentParser()
aa = parser.add_argument
aa('--notebook-dir',
default=os.path.expanduser(os.path.join('~', 'notebooks')),
help="Location where the notebooks will be stored")
aa('--ip', default='0.0.0.0', help='IP the notebook server will bind to')
aa('--port', default='8888', help='Port the notebook server will bind to')
aa('--browser', default=False, action='store_true',
help='Open the web browser on start')
aa('--random-token', default=False, action='store_true',
help='Use a random token')
aa('--one-python', default=False, action='store_true',
help='''Don't try and look for another python2/3. You may need '''
'''to do this if you don't have the python-devel installed '''
'''for both pythons''')
aa('--token', default='', help='Fixed token to use')
return parser
windows_bash_kernel_json = r'''{
"display_name": "Bash",
"language": "bash",
"argv": [
"c:\\Windows\\System32\\bash.exe", "-c",
"~/bash_kernel/bin/python -m bash_kernel -f \"`wslpath \"{connection_file}\"`\""
]
}'''
pipfile_3 = '''[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
[packages]
[requires]
python_version = "3"'''
pipfile_2 = '''[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
[packages]
[requires]
python_version = "2"'''
jupyter_notebook_config_py = """c.NotebookApp.ip = {ip}
# To link to a specific NIC: pip install netifaces
# c.NotebookApp.ip=netifaces.ifaddresses('eth0')[netifaces.AF_INET][0]['addr']
# Put in try/except just in case
c.NotebookApp.port = {port}
c.NotebookApp.notebook_dir = {notebooks}
c.NotebookApp.open_browser = {browser}\n"""
add_header = '''#!/usr/bin/env python
import json
import os
import sys
import argparse
parser = argparse.ArgumentParser(description='Add kernel.json for {}')
parser.add_argument('name', help='Name of kernel')
args = parser.parse_args()
try:
import ipykernel_launcher
ipykernel = 'ipykernel_launcher'
except ImportError:
try:
import ipykernel
ipykernel = 'ipykernel'
except ImportError:
print('IPython kernel not found. "pip install ipykernel" and try again')
exit(1)
kernel_dir = os.path.join(os.path.dirname(__file__),
'jupyter_data',
'kernels',
args.name)
try:
os.makedirs(kernel_dir)
except:
pass
'''
add_virtualenv = add_header.format('virtualenv. Run script from within an activated virtualenv.') + '''
kernel = {'display_name': args.name,
'argv': [sys.executable, '-m', ipykernel,
'-f', '{connection_file}'],
'env': {}}
with open(os.path.join(kernel_dir, 'kernel.json'), 'w') as fid:
json.dump(kernel, fid)
print('{} created'.format(kernel_dir))
'''
add_pipenv = add_header.format('pipenv. Run script from within a pipenv virtualenv ("pipenv run" or "pipenv shell").') + '''
import distutils.spawn
pipenv = distutils.spawn.find_executable('pipenv')
pipfile = os.environ.get('PIPENV_PIPFILE', None)
if pipfile is None:
from subprocess import Popen, PIPE
pid = Popen([pipenv, '--where'], stdout=PIPE)
pipfile = pid.communicate()[0]
if sys.version_info[0] == 3:
pipfile = pipfile.decode()
pipfile = pipfile.rstrip('\\r\\n')
if not pipfile: # If empty, then it wasn't found
pipfile = os.getcwd()
pipfile = os.path.join(pipfile, 'Pipfile')
kernel = {'display_name': args.name,
'argv': [pipenv, 'run', 'python', '-m', ipykernel,
'-f', '{connection_file}'],
'env': {'PIPENV_PIPFILE': pipfile}, 'language': 'python'}
with open(os.path.join(kernel_dir, 'kernel.json'), 'w') as fid:
json.dump(kernel, fid)
print('{} created'.format(kernel_dir))
'''
[docs]def main(args=None):
args = get_parser().parse_args(args)
tempdir = tempfile.mkdtemp()
atexit.register(shutil.rmtree, tempdir)
env = os.environ.copy()
env.pop('PYTHONPATH', None)
with open('Pipfile', 'w') as fid:
fid.write(pipfile_3)
python2 = None
python3 = None
### Setup python 3 ###
try:
Popen(['pipenv', "--three", 'install'], env=env).wait()
except AssertionError:
pass
else:
# Get python3 venv dir
python3 = Popen(['pipenv', "--venv"], stdout=PIPE).communicate()[0].decode().strip()
python2 = '2'
### Setup Python 2 ###
if python2:
try:
os.makedirs(python2)
except os.error:
pass
# Set up python2 venv
env = dict(os.environ)
env.pop('PYTHONPATH', None)
with open('2/Pipfile', 'w') as fid:
fid.write(pipfile_2)
try:
Popen(['pipenv', "--two", 'install'], env=env, cwd=python2).wait()
except AssertionError:
# If Python2 failed, and python3 succeeded, remove python2 subdir
if python2 == '2':
shutil.rmtree(python2)
python2 = None
else:
# get python2 venv dir
python2 = Popen(['pipenv', "--venv"], stdout=PIPE, cwd="2").communicate()[0].decode().strip()
# Determine which python dir is the "main" one, favor 3
if python3:
python_dir = python3
else:
python_dir = python2
# Setup config dir inside virtual env dir by monkey patching python executable
os.environ['JUPYTER_CONFIG_DIR'] = os.path.join(os.getcwd(), "jupyter_config")
os.environ['JUPYTER_DATA_DIR'] = os.path.join(os.getcwd(), "jupyter_data")
try:
os.makedirs(os.environ['JUPYTER_CONFIG_DIR'])
except os.error:
pass
with open(os.path.join(os.environ['JUPYTER_CONFIG_DIR'],
'jupyter_notebook_config.py'), 'w') as fid:
fid.write(jupyter_notebook_config_py.format(
ip=repr(args.ip), port=args.port,
notebooks=repr(args.notebook_dir),
browser=str(args.browser)))
if not args.random_token:
fid.write("c.NotebookApp.token = {token}\n".format(token=repr(args.token)))
fid.flush()
# On windows, we don't install the bash_kernel in windows
if os.name == 'nt':
bin_dir = 'Scripts'
lib_dir = 'Lib'
bash_kernel = []
else:
bin_dir = 'bin'
lib_dir = 'lib/python*'
bash_kernel = ['bash_kernel']
# Patch the site.py file
site_file = glob(os.path.join(python_dir, lib_dir, 'site.py'))[0]
patch_site(site_file,
os.path.relpath(os.environ['JUPYTER_CONFIG_DIR'],
os.path.dirname(site_file)),
os.path.relpath(os.environ['JUPYTER_DATA_DIR'],
os.path.dirname(site_file)))
# Install packages
Popen(['pipenv',
'install', 'notebook', 'jupyter-contrib-nbextensions',
'ipywidgets'] + bash_kernel).wait()
# Install the main python kernel
Popen([os.path.join(os.path.abspath(python_dir), bin_dir, 'python'),
'-m', 'ipykernel', 'install', '--user']).wait()
# Setup Notebook extensions and widgets
Popen([os.path.join(os.path.abspath(python_dir), bin_dir, 'jupyter-contrib'),
'nbextension', 'install', '--user']).wait()
Popen([os.path.join(os.path.abspath(python_dir),
bin_dir, 'jupyter-nbextension'),
'enable', '--py', '--user', 'widgetsnbextension']).wait()
# Setup bash_kernel
if os.name != "nt":
Popen([os.path.join(os.path.abspath(python_dir), bin_dir, 'python'),
'-m', 'bash_kernel', 'install', '--user', '--name', 'Bash']).wait()
else:
# on windows, use wsl to setup bash_kernel if available
if os.path.exists('c:\\Windows\\System32\\bash.exe'):
Popen(['c:\\Windows\\System32\\bash.exe',
'-c',
'tmp_dir="\\$(mktemp -d)";'
'cd "\\${tmp_dir}";'
'python3 <(curl -L https://bootstrap.pypa.io/get-pip.py) --no-cache-dir -I --root "\\${tmp_dir}" virtualenv;'
'PYTHONPATH="\\$(cd "\\${tmp_dir}"/usr/local/lib/python*/*-packages/; pwd)" "\\${tmp_dir}/usr/local/bin/virtualenv" ~/bash_kernel;'
'~/bash_kernel/bin/pip install --no-cache-dir bash_kernel ipykernel;'
'rm -r "\\${tmp_dir}"'], shell=False).wait()
try:
os.makedirs(os.path.join(os.environ['JUPYTER_DATA_DIR'], 'kernels',
'bash'))
except os.error:
pass
with open(os.path.join(os.environ['JUPYTER_DATA_DIR'], 'kernels', 'bash',
'kernel.json'), 'w') as fid:
fid.write(windows_bash_kernel_json)
# if both pythons worked, setup multi kernels
if python2 and python3:
with open(os.path.join(os.environ['JUPYTER_CONFIG_DIR'],
'jupyter_notebook_config.py'), 'a') as fid:
fid.write("c.MultiKernelManager.default_kernel_name = 'python3'")
# patch python2's site too
site_file = glob(os.path.join(python2, lib_dir, 'site.py'))[0]
patch_site(site_file,
os.path.relpath(os.environ['JUPYTER_CONFIG_DIR'],
os.path.dirname(site_file)),
os.path.relpath(os.environ['JUPYTER_DATA_DIR'],
os.path.dirname(site_file)))
# Install python2's ipywidget too
Popen(['pipenv', 'install', 'ipywidgets'], cwd="2").wait()
# Install the python2 kernel
Popen([os.path.join(python2, bin_dir, 'python'),
'-m', 'ipykernel', 'install', '--user', '--name', 'python2']).wait()
# Add add_virtualenv script
with open('add_virtualenv.py', 'w') as fid:
fid.write(add_virtualenv)
os.chmod('add_virtualenv.py', 0o755)
# Add add_pipenv script
with open('add_pipenv.py', 'w') as fid:
fid.write(add_pipenv)
os.chmod('add_pipenv.py', 0o755)
print("\n---------------------------------\n")
print("Notebook configured successfully!")
print('Run "jupyter-notebook password" to '
'secure your notebook with a password')
if __name__=='__main__':
main()