Vehicle-Anti-Theft-Face-Rec.../venv/Lib/site-packages/jupyter_core/migrate.py

283 lines
8.2 KiB
Python
Raw Permalink Normal View History

2020-11-12 16:05:57 +00:00
from __future__ import unicode_literals
"""Migrating IPython < 4.0 to Jupyter
This *copies* configuration and resources to their new locations in Jupyter
Migrations:
- .ipython/
- nbextensions -> JUPYTER_DATA_DIR/nbextensions
- kernels -> JUPYTER_DATA_DIR/kernels
- .ipython/profile_default/
- static/custom -> .jupyter/custom
- nbconfig -> .jupyter/nbconfig
- security/
- notebook_secret, notebook_cookie_secret, nbsignatures.db -> JUPYTER_DATA_DIR
- ipython_{notebook,nbconvert,qtconsole}_config.py -> .jupyter/jupyter_{name}_config.py
"""
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
import os
import re
import shutil
from datetime import datetime
from traitlets.config import PyFileConfigLoader, JSONFileConfigLoader
from traitlets.log import get_logger
from .utils import ensure_dir_exists
from .paths import jupyter_config_dir, jupyter_data_dir
from .application import JupyterApp
pjoin = os.path.join
migrations = {
pjoin('{ipython_dir}', 'nbextensions'): pjoin('{jupyter_data}', 'nbextensions'),
pjoin('{ipython_dir}', 'kernels'): pjoin('{jupyter_data}', 'kernels'),
pjoin('{profile}', 'nbconfig'): pjoin('{jupyter_config}', 'nbconfig'),
}
custom_src_t = pjoin('{profile}', 'static', 'custom')
custom_dst_t = pjoin('{jupyter_config}', 'custom')
for security_file in ('notebook_secret', 'notebook_cookie_secret', 'nbsignatures.db'):
src = pjoin('{profile}', 'security', security_file)
dst = pjoin('{jupyter_data}', security_file)
migrations[src] = dst
config_migrations = ['notebook', 'nbconvert', 'qtconsole']
regex = re.compile
config_substitutions = {
regex(r'\bIPythonQtConsoleApp\b'): 'JupyterQtConsoleApp',
regex(r'\bIPythonWidget\b'): 'JupyterWidget',
regex(r'\bRichIPythonWidget\b'): 'RichJupyterWidget',
regex(r'\bIPython\.html\b'): 'notebook',
regex(r'\bIPython\.nbconvert\b'): 'nbconvert',
}
def get_ipython_dir():
"""Return the IPython directory location.
Not imported from IPython because the IPython implementation
ensures that a writable directory exists,
creating a temporary directory if not.
We don't want to trigger that when checking if migration should happen.
We only need to support the IPython < 4 behavior for migration,
so importing for forward-compatibility and edge cases is not important.
"""
return os.environ.get('IPYTHONDIR', os.path.expanduser('~/.ipython'))
def migrate_dir(src, dst):
"""Migrate a directory from src to dst"""
log = get_logger()
if not os.listdir(src):
log.debug("No files in %s" % src)
return False
if os.path.exists(dst):
if os.listdir(dst):
# already exists, non-empty
log.debug("%s already exists" % dst)
return False
else:
os.rmdir(dst)
log.info("Copying %s -> %s" % (src, dst))
ensure_dir_exists(os.path.dirname(dst))
shutil.copytree(src, dst, symlinks=True)
return True
def migrate_file(src, dst, substitutions=None):
"""Migrate a single file from src to dst
substitutions is an optional dict of {regex: replacement} for performing replacements on the file.
"""
log = get_logger()
if os.path.exists(dst):
# already exists
log.debug("%s already exists" % dst)
return False
log.info("Copying %s -> %s" % (src, dst))
ensure_dir_exists(os.path.dirname(dst))
shutil.copy(src, dst)
if substitutions:
with open(dst) as f:
text = f.read()
for pat, replacement in substitutions.items():
text = pat.sub(replacement, text)
with open(dst, 'w') as f:
f.write(text)
return True
def migrate_one(src, dst):
"""Migrate one item
dispatches to migrate_dir/_file
"""
log = get_logger()
if os.path.isfile(src):
return migrate_file(src, dst)
elif os.path.isdir(src):
return migrate_dir(src, dst)
else:
log.debug("Nothing to migrate for %s" % src)
return False
def migrate_static_custom(src, dst):
"""Migrate non-empty custom.js,css from src to dst
src, dst are 'custom' directories containing custom.{js,css}
"""
log = get_logger()
migrated = False
custom_js = pjoin(src, 'custom.js')
custom_css = pjoin(src, 'custom.css')
# check if custom_js is empty:
custom_js_empty = True
if os.path.isfile(custom_js):
with open(custom_js) as f:
js = f.read().strip()
for line in js.splitlines():
if not (
line.isspace()
or line.strip().startswith(('/*', '*', '//'))
):
custom_js_empty = False
break
# check if custom_css is empty:
custom_css_empty = True
if os.path.isfile(custom_css):
with open(custom_css) as f:
css = f.read().strip()
custom_css_empty = css.startswith('/*') and css.endswith('*/')
if custom_js_empty:
log.debug("Ignoring empty %s" % custom_js)
if custom_css_empty:
log.debug("Ignoring empty %s" % custom_css)
if custom_js_empty and custom_css_empty:
# nothing to migrate
return False
ensure_dir_exists(dst)
if not custom_js_empty or not custom_css_empty:
ensure_dir_exists(dst)
if not custom_js_empty:
if migrate_file(custom_js, pjoin(dst, 'custom.js')):
migrated = True
if not custom_css_empty:
if migrate_file(custom_css, pjoin(dst, 'custom.css')):
migrated = True
return migrated
def migrate_config(name, env):
"""Migrate a config file
Includes substitutions for updated configurable names.
"""
log = get_logger()
src_base = pjoin('{profile}', 'ipython_{name}_config').format(name=name, **env)
dst_base = pjoin('{jupyter_config}', 'jupyter_{name}_config').format(name=name, **env)
loaders = {
'.py': PyFileConfigLoader,
'.json': JSONFileConfigLoader,
}
migrated = []
for ext in ('.py', '.json'):
src = src_base + ext
dst = dst_base + ext
if os.path.exists(src):
cfg = loaders[ext](src).load_config()
if cfg:
if migrate_file(src, dst, substitutions=config_substitutions):
migrated.append(src)
else:
# don't migrate empty config files
log.debug("Not migrating empty config file: %s" % src)
return migrated
def migrate():
"""Migrate IPython configuration to Jupyter"""
env = {
'jupyter_data': jupyter_data_dir(),
'jupyter_config': jupyter_config_dir(),
'ipython_dir': get_ipython_dir(),
'profile': os.path.join(get_ipython_dir(), 'profile_default'),
}
migrated = False
for src_t, dst_t in migrations.items():
src = src_t.format(**env)
dst = dst_t.format(**env)
if os.path.exists(src):
if migrate_one(src, dst):
migrated = True
for name in config_migrations:
if migrate_config(name, env):
migrated = True
custom_src = custom_src_t.format(**env)
custom_dst = custom_dst_t.format(**env)
if os.path.exists(custom_src):
if migrate_static_custom(custom_src, custom_dst):
migrated = True
# write a marker to avoid re-running migration checks
ensure_dir_exists(env['jupyter_config'])
with open(os.path.join(env['jupyter_config'], 'migrated'), 'w') as f:
f.write(datetime.utcnow().isoformat())
return migrated
class JupyterMigrate(JupyterApp):
name = 'jupyter-migrate'
description = """
Migrate configuration and data from .ipython prior to 4.0 to Jupyter locations.
This migrates:
- config files in the default profile
- kernels in ~/.ipython/kernels
- notebook javascript extensions in ~/.ipython/extensions
- custom.js/css to .jupyter/custom
to their new Jupyter locations.
All files are copied, not moved.
If the destinations already exist, nothing will be done.
"""
def start(self):
if not migrate():
self.log.info("Found nothing to migrate.")
main = JupyterMigrate.launch_instance
if __name__ == '__main__':
main()