# coding: utf-8 # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. """Test config file migration""" import os import re import shutil from subprocess import check_call from tempfile import mkdtemp try: from unittest.mock import patch except ImportError: from mock import patch import pytest from jupyter_core.utils import ensure_dir_exists from jupyter_core.paths import jupyter_data_dir from jupyter_core.migrate import ( migrate, migrate_one, migrate_config, migrate_dir, migrate_file, migrate_static_custom, ) from jupyter_core import migrate as migrate_mod pjoin = os.path.join here = os.path.dirname(__file__) dotipython = pjoin(here, 'dotipython') dotipython_empty = pjoin(here, 'dotipython_empty') @pytest.fixture def td(request): """Fixture for a temporary directory""" td = mkdtemp(u'μnïcø∂e') request.addfinalizer(lambda : shutil.rmtree(td)) return td @pytest.fixture def env(request): """Fixture for a full testing environment""" td = mkdtemp() env = { 'TESTDIR': td, 'IPYTHONDIR': pjoin(td, 'ipython'), 'JUPYTER_CONFIG_DIR': pjoin(td, 'jupyter'), 'JUPYTER_DATA_DIR': pjoin(td, 'jupyter_data'), 'JUPYTER_RUNTIME_DIR': pjoin(td, 'jupyter_runtime'), 'JUPYTER_PATH': '', } env_patch = patch.dict(os.environ, env) env_patch.start() def fin(): """Cleanup test env""" env_patch.stop() shutil.rmtree(td) request.addfinalizer(fin) return env def touch(path, content=''): ensure_dir_exists(os.path.dirname(path)) with open(path, 'w') as f: f.write(content) def assert_files_equal(a, b): """Verify that two files match""" assert os.path.exists(b) with open(a) as f: a_txt = f.read() with open(b) as f: b_txt = f.read() assert a_txt == b_txt def test_migrate_file(td): src = pjoin(td, 'src') dst = pjoin(td, 'dst') touch(src, 'test file') assert migrate_file(src, dst) assert_files_equal(src, dst) src2 = pjoin(td, 'src2') touch(src2, 'different src') assert not migrate_file(src2, dst) assert_files_equal(src, dst) def test_migrate_dir(td): src = pjoin(td, 'src') dst = pjoin(td, 'dst') os.mkdir(src) assert not migrate_dir(src, dst) assert not os.path.exists(dst) touch(pjoin(src, 'f'), 'test file') assert migrate_dir(src, dst) assert_files_equal(pjoin(src, 'f'), pjoin(dst, 'f')) touch(pjoin(src, 'g'), 'other test file') assert not migrate_dir(src, dst) assert not os.path.exists(pjoin(dst, 'g')) shutil.rmtree(dst) os.mkdir(dst) assert migrate_dir(src, dst) assert_files_equal(pjoin(src, 'f'), pjoin(dst, 'f')) assert_files_equal(pjoin(src, 'g'), pjoin(dst, 'g')) def test_migrate_one(td): src = pjoin(td, 'src') srcdir = pjoin(td, 'srcdir') dst = pjoin(td, 'dst') dstdir = pjoin(td, 'dstdir') touch(src, 'test file') touch(pjoin(srcdir, 'f'), 'test dir file') called = {} def notice_m_file(src, dst): called['migrate_file'] = True return migrate_file(src, dst) def notice_m_dir(src, dst): called['migrate_dir'] = True return migrate_dir(src, dst) with patch.object(migrate_mod, 'migrate_file', notice_m_file), \ patch.object(migrate_mod, 'migrate_dir', notice_m_dir): assert migrate_one(src, dst) assert called == {'migrate_file': True} called.clear() assert migrate_one(srcdir, dstdir) assert called == {'migrate_dir': True} called.clear() assert not migrate_one(pjoin(td, 'dne'), dst) assert called == {} def test_migrate_config(td): profile = pjoin(td, 'profile') jpy = pjoin(td, 'jupyter_config') ensure_dir_exists(profile) env = { 'profile': profile, 'jupyter_config': jpy, } cfg_py = pjoin(profile, 'ipython_test_config.py') touch(cfg_py, 'c.Klass.trait = 5\n') empty_cfg_py = pjoin(profile, 'ipython_empty_config.py') touch(empty_cfg_py, '# c.Klass.trait = 5\n') assert not migrate_config('empty', env) assert not os.path.exists(jpy) with patch.dict(migrate_mod.config_substitutions, { re.compile(r'\bKlass\b'): 'Replaced', }): assert migrate_config('test', env) assert os.path.isdir(jpy) assert sorted(os.listdir(jpy)) == [ 'jupyter_test_config.py', ] with open(pjoin(jpy, 'jupyter_test_config.py')) as f: text = f.read() assert text == 'c.Replaced.trait = 5\n' def test_migrate_custom_default(td): profile = pjoin(dotipython, 'profile_default') src = pjoin(profile, 'static', 'custom') assert os.path.exists(src) assert not migrate_static_custom(src, td) src = pjoin(td, 'src') dst = pjoin(td, 'dst') os.mkdir(src) src_custom_js = pjoin(src, 'custom.js') src_custom_css = pjoin(src, 'custom.css') touch(src_custom_js, 'var a=5;') touch(src_custom_css, 'div { height: 5px; }') assert migrate_static_custom(src, dst) def test_migrate_nothing(env): migrate() assert os.listdir(env['JUPYTER_CONFIG_DIR']) == ['migrated'] assert not os.path.exists(env['JUPYTER_DATA_DIR']) def test_migrate_default(env): shutil.copytree(dotipython_empty, env['IPYTHONDIR']) migrate() assert os.listdir(env['JUPYTER_CONFIG_DIR']) == ['migrated'] assert not os.path.exists(env['JUPYTER_DATA_DIR']) def test_migrate(env): shutil.copytree(dotipython, env['IPYTHONDIR']) migrate() assert os.path.exists(env['JUPYTER_CONFIG_DIR']) assert os.path.exists(env['JUPYTER_DATA_DIR'])