You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ORPA-pyOpenRPA/Resources/LPy64-3105/lib/python3.10/site-packages/jupyter_core/migrate.py

275 lines
8.1 KiB

"""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 JSONFileConfigLoader, PyFileConfigLoader
from traitlets.log import get_logger
from .application import JupyterApp
from .paths import jupyter_config_dir, jupyter_data_dir
from .utils import ensure_dir_exists
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(f"Copying {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(f"Copying {src} -> {dst}")
ensure_dir_exists(os.path.dirname(dst))
shutil.copy(src, dst)
if substitutions:
with open(dst, encoding="utf-8") as f:
text = f.read()
for pat, replacement in substitutions.items():
text = pat.sub(replacement, text)
with open(dst, "w", encoding="utf-8") 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, encoding="utf-8") 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, encoding="utf-8") 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", encoding="utf-8") 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()