class PickleShareDBTestCase(TestCase): def setUp(self): self.tempdir = TemporaryDirectory() def tearDown(self): self.tempdir.cleanup() def test_picklesharedb(self): db = PickleShareDB(self.tempdir.name) db.clear() print("Should be empty:", db.items()) db['hello'] = 15 db['aku ankka'] = [1, 2, 313] db['paths/nest/ok/keyname'] = [1, (5, 46)] db.hset('hash', 'aku', 12) db.hset('hash', 'ankka', 313) self.assertEqual(db.hget('hash', 'aku'), 12) self.assertEqual(db.hget('hash', 'ankka'), 313) print("all hashed", db.hdict('hash')) print(db.keys()) print(db.keys('paths/nest/ok/k*')) print(dict(db)) # snapsot of whole db db.uncache() # frees memory, causes re-reads later # shorthand for accessing deeply nested files lnk = db.getlink('myobjects/test') lnk.foo = 2 lnk.bar = lnk.foo + 5 self.assertEqual(lnk.bar, 7) @skip("Too slow for regular running.") def test_stress(self): db = PickleShareDB('~/fsdbtest') import time import sys for i in range(1000): for j in range(1000): if i % 15 == 0 and i < 200: if str(j) in db: del db[str(j)] continue if j % 33 == 0: time.sleep(0.02) db[str(j)] = db.get(str(j), []) + \ [(i, j, "proc %d" % os.getpid())] db.hset('hash', j, db.hget('hash', j, 15) + 1) print(i, end=' ') sys.stdout.flush() if i % 10 == 0: db.uncache()
class PickleShareDBTestCase(TestCase): def setUp(self): self.tempdir = TemporaryDirectory() def tearDown(self): self.tempdir.cleanup() def test_picklesharedb(self): db = PickleShareDB(self.tempdir.name) db.clear() print("Should be empty:", db.items()) db['hello'] = 15 db['aku ankka'] = [1, 2, 313] db['paths/nest/ok/keyname'] = [1, (5, 46)] db.hset('hash', 'aku', 12) db.hset('hash', 'ankka', 313) self.assertEqual(db.hget('hash', 'aku'), 12) self.assertEqual(db.hget('hash', 'ankka'), 313) print("all hashed", db.hdict('hash')) print(db.keys()) print(db.keys('paths/nest/ok/k*')) print(dict(db)) # snapsot of whole db db.uncache() # frees memory, causes re-reads later # shorthand for accessing deeply nested files lnk = db.getlink('myobjects/test') lnk.foo = 2 lnk.bar = lnk.foo + 5 self.assertEqual(lnk.bar, 7) @skip("Too slow for regular running.") def test_stress(self): db = PickleShareDB('~/fsdbtest') import time, sys for i in range(1000): for j in range(1000): if i % 15 == 0 and i < 200: if str(j) in db: del db[str(j)] continue if j % 33 == 0: time.sleep(0.02) db[str(j)] = db.get(str(j), []) + [(i, j, "proc %d" % os.getpid())] db.hset('hash', j, db.hget('hash', j, 15) + 1) print(i, end=' ') sys.stdout.flush() if i % 10 == 0: db.uncache()
class FileTestCase(TestContentsManager): def setUp(self): self._temp_dir = TemporaryDirectory() self.td = self._temp_dir.name self._file_manager = FileContentsManager(root_dir=self.td) self.contents_manager = HybridContentsManager( managers={'': self._file_manager}) def tearDown(self): self._temp_dir.cleanup() def make_dir(self, api_path): """make a subdirectory at api_path override in subclasses if contents are not on the filesystem. """ _make_dir(self._file_manager, api_path)
def test_get_ipython_dir_3(): """test_get_ipython_dir_3, use XDG if defined and exists, and .ipython doesn't exist.""" tmphome = TemporaryDirectory() try: with patch_get_home_dir(tmphome.name), \ patch('os.name', 'posix'), \ modified_env({ 'IPYTHON_DIR': None, 'IPYTHONDIR': None, 'XDG_CONFIG_HOME': XDG_TEST_DIR, }), warnings.catch_warnings(record=True) as w: ipdir = paths.get_ipython_dir() assert ipdir == os.path.join(tmphome.name, XDG_TEST_DIR, "ipython") assert len(w) == 0 finally: tmphome.cleanup()
def test_extension(): tmpdir = TemporaryDirectory() orig_ipython_dir = _ip.ipython_dir try: _ip.ipython_dir = tmpdir.name nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension") url = os.path.join(os.path.dirname(__file__), "daft_extension.py") _ip.magic("install_ext %s" % url) _ip.user_ns.pop('arq', None) invalidate_caches() # Clear import caches _ip.magic("load_ext daft_extension") nt.assert_equal(_ip.user_ns['arq'], 185) _ip.magic("unload_ext daft_extension") assert 'arq' not in _ip.user_ns finally: _ip.ipython_dir = orig_ipython_dir tmpdir.cleanup()
class FileTestCase(TestContentsManager): def setUp(self): self._temp_dir = TemporaryDirectory() self.td = self._temp_dir.name self._file_manager = FileContentsManager(root_dir=self.td) self.contents_manager = HybridContentsManager( managers={'': self._file_manager} ) def tearDown(self): self._temp_dir.cleanup() def make_dir(self, api_path): """make a subdirectory at api_path override in subclasses if contents are not on the filesystem. """ _make_dir(self._file_manager, api_path)
def test_get_ipython_dir_3(): """test_get_ipython_dir_3, move XDG if defined, and .ipython doesn't exist.""" tmphome = TemporaryDirectory() try: with patch_get_home_dir(tmphome.name): os.name = "posix" env.pop('IPYTHON_DIR', None) env.pop('IPYTHONDIR', None) env['XDG_CONFIG_HOME'] = XDG_TEST_DIR with warnings.catch_warnings(record=True) as w: ipdir = path.get_ipython_dir() nt.assert_equal(ipdir, os.path.join(tmphome.name, ".ipython")) if sys.platform != 'darwin': nt.assert_equal(len(w), 1) nt.assert_in('Moving', str(w[0])) finally: tmphome.cleanup()
def test_get_ipython_dir_3(): """test_get_ipython_dir_3, move XDG if defined, and .ipython doesn't exist.""" tmphome = TemporaryDirectory() try: with patch_get_home_dir(tmphome.name), \ patch('os.name', 'posix'), \ modified_env({ 'IPYTHON_DIR': None, 'IPYTHONDIR': None, 'XDG_CONFIG_HOME': XDG_TEST_DIR, }), warnings.catch_warnings(record=True) as w: ipdir = paths.get_ipython_dir() nt.assert_equal(ipdir, os.path.join(tmphome.name, ".ipython")) if sys.platform != 'darwin': nt.assert_equal(len(w), 1) nt.assert_in('Moving', str(w[0])) finally: tmphome.cleanup()
def test_get_ipython_dir_3(): """test_get_ipython_dir_3, move XDG if defined, and .ipython doesn't exist.""" tmphome = TemporaryDirectory() try: with patch_get_home_dir(tmphome.name), patch( "os.name", "posix"), modified_env({ "IPYTHON_DIR": None, "IPYTHONDIR": None, "XDG_CONFIG_HOME": XDG_TEST_DIR }), warnings.catch_warnings(record=True) as w: ipdir = paths.get_ipython_dir() nt.assert_equal(ipdir, os.path.join(tmphome.name, ".ipython")) if sys.platform != "darwin": nt.assert_equal(len(w), 1) nt.assert_in("Moving", str(w[0])) finally: tmphome.cleanup()
class GLFRepl: def __init__(self, GF_BIN): self.GF_BIN = GF_BIN GF_ARGS = [GF_BIN, '--run'] self.td = TemporaryDirectory() self.to_clean_up = ['.dot', '.png', '.gfo'] self.out_file_name = os.path.join(self.td.name, 'shell.out') self.out = open(self.out_file_name, 'w+') self.shell = Popen(GF_ARGS, stdin=PIPE, stdout=self.out, stderr=self.out) self.pid = os.getpid() self.out_count = 0 # initialize the MMT interface self.mmtInterface = MMTInterface() # register the signal handler for the notify process signal.signal(signal.SIGUSR1, self.signal_handler) def do_shutdown(self): "Terminates the GF shell and the MMT subprocess" # terminate gf shell self.td.cleanup() self.shell.communicate(b'q\n')[0] self.shell.stdin.close() self.shell.kill() # terminate mmt self.mmtInterface.do_shutdown() def clean_up(self): """Removes all files whose extensions are contained in `self.to_clean_up`""" removed = [] files = os.listdir('.') for file in files: _, file_extension = os.path.splitext(file) if file_extension in self.to_clean_up: removed.append(file) os.remove(file) if removed: s = map(lambda x: 'Removed: %s' % (x), removed) return "\n".join(s) else: return "No files removed" def do_export(self, file_name): source_path = os.path.join(self.mmtInterface.content_path, self.mmtInterface.archive, 'source') files = os.listdir(source_path) file_reg = re.compile('^%s.gf$' % (file_name)) for file in files: if file_reg.match(file): from shutil import copy2 copy2(os.path.join(source_path, file), file) return 'Exported %s' % (file) return 'Could not find %s' % (file_name) def handle_input(self, code): """Handles all kinds of user inputs""" messages = [] parse_dict = parse(code) if parse_dict['type']: if parse_dict['type'] == 'commands': for command in parse_dict['commands']: name = command['name'] args = command['args'] if name == 'view': messages.append( self.handle_multiple_view(' '.join(args))) elif name == 'clean': messages.append( to_message_format(message=self.clean_up())) elif name == 'export': if len(args) > 1: messages.append( to_message_format( message="export only takes one argument!")) else: messages.append( to_message_format( message=self.do_export(args[0]))) elif name == 'archive': if len(args) > 2: messages.append( to_message_format( message= "archive takes at maximum two arguments!")) else: messages.append( to_message_format(message=self.mmtInterface. handle_archive(args))) elif name == 'request': messages.append( to_message_format(message=self.mmtInterface. handle_request(args))) elif name == 'help': # TODO move this to another external file (probably a json) messages.append( to_message_format("""Available kernel commands: view 'gf_command' : view the graph(s) generated by 'gf_command' clean : remove all %s files from the current directory. export 'name' : export the grammar with 'name' to your current directory h : display more information on the GF shell commands Otherwise you can use the kernel as an editor for your grammars. Stated grammars are automatically imported upon definiton.""" % (", ".join(self.to_clean_up)))) else: cmd = '%s %s' % (name, ' '.join(args)) msg = self.handle_shell_input(cmd) if name == 'import' and not msg: messages.append( to_message_format( message='Import successful!')) else: messages.append(to_message_format(message=msg)) elif parse_dict['type'] == 'GFContent': messages.append( to_message_format( message=self.handle_grammar(code, parse_dict['name']))) elif parse_dict['type'] == 'MMTContent': messages.append( to_message_format( message=self.mmtInterface.create_mmt_file( code, parse_dict['name'], parse_dict['mmt_type']))) else: messages.append( to_message_format( message= "Input is neither valid GF or MMT content nor a valid shell command!" )) return messages def handle_grammar(self, content, name): """ Handles a grammar input ``grammar``: str; the content of the grammar ``name``: str; the name of the grammar """ file_path = "%s.gf" % (os.path.join(self.mmtInterface.content_path, self.mmtInterface.archive, 'source', name)) try: with open(file_path, 'w') as f: f.write(content) f.close() except OSError: return 'Failed to create grammar %s' % (name) out = self.handle_shell_input("import %s" % (file_path)) if not out: self.mmtInterface.build_archive() out = "Defined %s" % (name) return out def handle_multiple_view(self, command): """Handles view commands with possibly multiple graph outputs""" cmd = parse_command(command) if cmd['tree_type']: raw_command = cmd['cmd'] out = self.handle_shell_input(raw_command) lines = out.split('\n') trees = [] for line in lines: if line != '' and line != ' ': trees.append(line) if len(trees) > 1: return to_message_format(trees=trees, tree_type=cmd['tree_type']) return to_message_format(file=self.handle_single_view(command)) def handle_single_view(self, command): """ Handles a single view command Sends the `command` to the GF shell and converts the output to a .png file returns the name of the .png file """ out = self.handle_shell_input(command) if not out: return "no file" out_dot = os.path.join(self.td.name, 'out%s.dot' % (self.out_count)) out_png = os.path.join(self.td.name, 'out%s.png' % (self.out_count)) with open(out_dot, 'w') as f: f.write(out) DOT_ARGS = ['dot', '-Tpng', out_dot, '-o', out_png] p = Popen(DOT_ARGS, shell=False) p.communicate()[0] p.kill() self.out_count += 1 return out_png def handle_shell_input(self, code): """Sends the `code` to the GF shell""" if self.out.closed: self.out = open(self.out_file_name, 'w') cp_s = self.out.tell() # send the command code = code + '\n' self.shell.stdin.write(code.encode()) self.shell.stdin.flush() # start the notify process cmd = 'sp -command=\"python %s/notify.py %s\"\n' % (os.path.dirname( os.path.abspath(__file__)), self.pid) self.shell.stdin.write(cmd.encode()) self.shell.stdin.flush() # wait for the notify process signal.pause() # some shell commands (mostly the ones that are dealing with files) are asynchronous from the shells execution, # like e.g. searching a file to include. This means the notify process can report back even though the shell # hasn't actually written its output to the output file yet. Hence we need to wait a little here to be sure the output is there. time.sleep(0.2) out = readFile(self.out_file_name, cp_s).replace('ExitFailure 1', '') return out def start(self): """Starts the REPL""" i = sys.stdin.readline() while i and i != 'quit\n' and i != 'q\n': # send input without the newline print(self.handle_shell_input(i[:-1])) i = sys.stdin.readline() def signal_handler(self, signum, frame): """Signal handler for the notify process""" pass
class TestMagicRunWithPackage(unittest.TestCase): def writefile(self, name, content): path = os.path.join(self.tempdir.name, name) d = os.path.dirname(path) if not os.path.isdir(d): os.makedirs(d) with open(path, 'w') as f: f.write(textwrap.dedent(content)) def setUp(self): self.package = package = 'tmp{0}'.format(''.join([random.choice(string.ascii_letters) for i in range(10)])) """Temporary (probably) valid python package name.""" self.value = int(random.random() * 10000) self.tempdir = TemporaryDirectory() self.__orig_cwd = os.getcwd() sys.path.insert(0, self.tempdir.name) self.writefile(os.path.join(package, '__init__.py'), '') self.writefile(os.path.join(package, 'sub.py'), """ x = {0!r} """.format(self.value)) self.writefile(os.path.join(package, 'relative.py'), """ from .sub import x """) self.writefile(os.path.join(package, 'absolute.py'), """ from {0}.sub import x """.format(package)) self.writefile(os.path.join(package, 'args.py'), """ import sys a = " ".join(sys.argv[1:]) """.format(package)) def tearDown(self): os.chdir(self.__orig_cwd) sys.path[:] = [p for p in sys.path if p != self.tempdir.name] self.tempdir.cleanup() def check_run_submodule(self, submodule, opts=''): _ip.user_ns.pop('x', None) _ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts)) self.assertEqual(_ip.user_ns['x'], self.value, 'Variable `x` is not loaded from module `{0}`.' .format(submodule)) def test_run_submodule_with_absolute_import(self): self.check_run_submodule('absolute') def test_run_submodule_with_relative_import(self): """Run submodule that has a relative import statement (#2727).""" self.check_run_submodule('relative') def test_prun_submodule_with_absolute_import(self): self.check_run_submodule('absolute', '-p') def test_prun_submodule_with_relative_import(self): self.check_run_submodule('relative', '-p') def with_fake_debugger(func): @functools.wraps(func) def wrapper(*args, **kwds): with patch.object(debugger.Pdb, 'run', staticmethod(eval)): return func(*args, **kwds) return wrapper @with_fake_debugger def test_debug_run_submodule_with_absolute_import(self): self.check_run_submodule('absolute', '-d') @with_fake_debugger def test_debug_run_submodule_with_relative_import(self): self.check_run_submodule('relative', '-d') def test_module_options(self): _ip.user_ns.pop('a', None) test_opts = '-x abc -m test' _ip.run_line_magic('run', '-m {0}.args {1}'.format(self.package, test_opts)) nt.assert_equal(_ip.user_ns['a'], test_opts) def test_module_options_with_separator(self): _ip.user_ns.pop('a', None) test_opts = '-x abc -m test' _ip.run_line_magic('run', '-m {0}.args -- {1}'.format(self.package, test_opts)) nt.assert_equal(_ip.user_ns['a'], test_opts)
class TestContentsManager(TestCase): def setUp(self): self._temp_dir = TemporaryDirectory() self.td = self._temp_dir.name self.contents_manager = FileContentsManager(root_dir=self.td, log=logging.getLogger()) def tearDown(self): self._temp_dir.cleanup() def make_dir(self, abs_path, rel_path): """make subdirectory, rel_path is the relative path to that directory from the location where the server started""" os_path = os.path.join(abs_path, rel_path) try: os.makedirs(os_path) except OSError: print("Directory already exists: %r" % os_path) return os_path def add_code_cell(self, nb): output = current.new_output("display_data", output_javascript="alert('hi');") cell = current.new_code_cell("print('hi')", outputs=[output]) if not nb.worksheets: nb.worksheets.append(current.new_worksheet()) nb.worksheets[0].cells.append(cell) def new_notebook(self): cm = self.contents_manager model = cm.create_file() name = model['name'] path = model['path'] full_model = cm.get_model(name, path) nb = full_model['content'] self.add_code_cell(nb) cm.save(full_model, name, path) return nb, name, path def test_create_file(self): cm = self.contents_manager # Test in root directory model = cm.create_file() assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'Untitled0.ipynb') self.assertEqual(model['path'], '') # Test in sub-directory sub_dir = '/foo/' self.make_dir(cm.root_dir, 'foo') model = cm.create_file(None, sub_dir) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'Untitled0.ipynb') self.assertEqual(model['path'], sub_dir.strip('/')) def test_get(self): cm = self.contents_manager # Create a notebook model = cm.create_file() name = model['name'] path = model['path'] # Check that we 'get' on the notebook we just created model2 = cm.get_model(name, path) assert isinstance(model2, dict) self.assertIn('name', model2) self.assertIn('path', model2) self.assertEqual(model['name'], name) self.assertEqual(model['path'], path) # Test in sub-directory sub_dir = '/foo/' self.make_dir(cm.root_dir, 'foo') model = cm.create_file(None, sub_dir) model2 = cm.get_model(name, sub_dir) assert isinstance(model2, dict) self.assertIn('name', model2) self.assertIn('path', model2) self.assertIn('content', model2) self.assertEqual(model2['name'], 'Untitled0.ipynb') self.assertEqual(model2['path'], sub_dir.strip('/')) @dec.skip_win32 def test_bad_symlink(self): cm = self.contents_manager path = 'test bad symlink' os_path = self.make_dir(cm.root_dir, path) file_model = cm.create_file(path=path, ext='.txt') # create a broken symlink os.symlink("target", os.path.join(os_path, "bad symlink")) model = cm.get_model(path) self.assertEqual(model['content'], [file_model]) @dec.skip_win32 def test_good_symlink(self): cm = self.contents_manager path = 'test good symlink' os_path = self.make_dir(cm.root_dir, path) file_model = cm.create_file(path=path, ext='.txt') # create a good symlink os.symlink(file_model['name'], os.path.join(os_path, "good symlink")) symlink_model = cm.get_model(name="good symlink", path=path, content=False) dir_model = cm.get_model(path) self.assertEqual( sorted(dir_model['content'], key=lambda x: x['name']), [symlink_model, file_model], ) def test_update(self): cm = self.contents_manager # Create a notebook model = cm.create_file() name = model['name'] path = model['path'] # Change the name in the model for rename model['name'] = 'test.ipynb' model = cm.update(model, name, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'test.ipynb') # Make sure the old name is gone self.assertRaises(HTTPError, cm.get_model, name, path) # Test in sub-directory # Create a directory and notebook in that directory sub_dir = '/foo/' self.make_dir(cm.root_dir, 'foo') model = cm.create_file(None, sub_dir) name = model['name'] path = model['path'] # Change the name in the model for rename model['name'] = 'test_in_sub.ipynb' model = cm.update(model, name, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'test_in_sub.ipynb') self.assertEqual(model['path'], sub_dir.strip('/')) # Make sure the old name is gone self.assertRaises(HTTPError, cm.get_model, name, path) def test_save(self): cm = self.contents_manager # Create a notebook model = cm.create_file() name = model['name'] path = model['path'] # Get the model with 'content' full_model = cm.get_model(name, path) # Save the notebook model = cm.save(full_model, name, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], name) self.assertEqual(model['path'], path) # Test in sub-directory # Create a directory and notebook in that directory sub_dir = '/foo/' self.make_dir(cm.root_dir, 'foo') model = cm.create_file(None, sub_dir) name = model['name'] path = model['path'] model = cm.get_model(name, path) # Change the name in the model for rename model = cm.save(model, name, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'Untitled0.ipynb') self.assertEqual(model['path'], sub_dir.strip('/')) def test_delete(self): cm = self.contents_manager # Create a notebook nb, name, path = self.new_notebook() # Delete the notebook cm.delete(name, path) # Check that a 'get' on the deleted notebook raises and error self.assertRaises(HTTPError, cm.get_model, name, path) def test_copy(self): cm = self.contents_manager path = u'å b' name = u'nb √.ipynb' os.mkdir(os.path.join(cm.root_dir, path)) orig = cm.create_file({'name': name}, path=path) # copy with unspecified name copy = cm.copy(name, path=path) self.assertEqual(copy['name'], orig['name'].replace('.ipynb', '-Copy0.ipynb')) # copy with specified name copy2 = cm.copy(name, u'copy 2.ipynb', path=path) self.assertEqual(copy2['name'], u'copy 2.ipynb') def test_trust_notebook(self): cm = self.contents_manager nb, name, path = self.new_notebook() untrusted = cm.get_model(name, path)['content'] assert not cm.notary.check_cells(untrusted) # print(untrusted) cm.trust_notebook(name, path) trusted = cm.get_model(name, path)['content'] # print(trusted) assert cm.notary.check_cells(trusted) def test_mark_trusted_cells(self): cm = self.contents_manager nb, name, path = self.new_notebook() cm.mark_trusted_cells(nb, name, path) for cell in nb.worksheets[0].cells: if cell.cell_type == 'code': assert not cell.trusted cm.trust_notebook(name, path) nb = cm.get_model(name, path)['content'] for cell in nb.worksheets[0].cells: if cell.cell_type == 'code': assert cell.trusted def test_check_and_sign(self): cm = self.contents_manager nb, name, path = self.new_notebook() cm.mark_trusted_cells(nb, name, path) cm.check_and_sign(nb, name, path) assert not cm.notary.check_signature(nb) cm.trust_notebook(name, path) nb = cm.get_model(name, path)['content'] cm.mark_trusted_cells(nb, name, path) cm.check_and_sign(nb, name, path) assert cm.notary.check_signature(nb)
class TestNotebookManager(TestCase): def setUp(self): self._temp_dir = TemporaryDirectory() self.td = self._temp_dir.name self.notebook_manager = FileNotebookManager( notebook_dir=self.td, log=logging.getLogger() ) def tearDown(self): self._temp_dir.cleanup() def make_dir(self, abs_path, rel_path): """make subdirectory, rel_path is the relative path to that directory from the location where the server started""" os_path = os.path.join(abs_path, rel_path) try: os.makedirs(os_path) except OSError: print("Directory already exists: %r" % os_path) def add_code_cell(self, nb): output = current.new_output("display_data", output_javascript="alert('hi');") cell = current.new_code_cell("print('hi')", outputs=[output]) if not nb.worksheets: nb.worksheets.append(current.new_worksheet()) nb.worksheets[0].cells.append(cell) def new_notebook(self): nbm = self.notebook_manager model = nbm.create_notebook() name = model['name'] path = model['path'] full_model = nbm.get_notebook(name, path) nb = full_model['content'] self.add_code_cell(nb) nbm.save_notebook(full_model, name, path) return nb, name, path def test_create_notebook(self): nm = self.notebook_manager # Test in root directory model = nm.create_notebook() assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'Untitled0.ipynb') self.assertEqual(model['path'], '') # Test in sub-directory sub_dir = '/foo/' self.make_dir(nm.notebook_dir, 'foo') model = nm.create_notebook(None, sub_dir) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'Untitled0.ipynb') self.assertEqual(model['path'], sub_dir.strip('/')) def test_get_notebook(self): nm = self.notebook_manager # Create a notebook model = nm.create_notebook() name = model['name'] path = model['path'] # Check that we 'get' on the notebook we just created model2 = nm.get_notebook(name, path) assert isinstance(model2, dict) self.assertIn('name', model2) self.assertIn('path', model2) self.assertEqual(model['name'], name) self.assertEqual(model['path'], path) # Test in sub-directory sub_dir = '/foo/' self.make_dir(nm.notebook_dir, 'foo') model = nm.create_notebook(None, sub_dir) model2 = nm.get_notebook(name, sub_dir) assert isinstance(model2, dict) self.assertIn('name', model2) self.assertIn('path', model2) self.assertIn('content', model2) self.assertEqual(model2['name'], 'Untitled0.ipynb') self.assertEqual(model2['path'], sub_dir.strip('/')) def test_update_notebook(self): nm = self.notebook_manager # Create a notebook model = nm.create_notebook() name = model['name'] path = model['path'] # Change the name in the model for rename model['name'] = 'test.ipynb' model = nm.update_notebook(model, name, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'test.ipynb') # Make sure the old name is gone self.assertRaises(HTTPError, nm.get_notebook, name, path) # Test in sub-directory # Create a directory and notebook in that directory sub_dir = '/foo/' self.make_dir(nm.notebook_dir, 'foo') model = nm.create_notebook(None, sub_dir) name = model['name'] path = model['path'] # Change the name in the model for rename model['name'] = 'test_in_sub.ipynb' model = nm.update_notebook(model, name, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'test_in_sub.ipynb') self.assertEqual(model['path'], sub_dir.strip('/')) # Make sure the old name is gone self.assertRaises(HTTPError, nm.get_notebook, name, path) def test_save_notebook(self): nm = self.notebook_manager # Create a notebook model = nm.create_notebook() name = model['name'] path = model['path'] # Get the model with 'content' full_model = nm.get_notebook(name, path) # Save the notebook model = nm.save_notebook(full_model, name, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], name) self.assertEqual(model['path'], path) # Test in sub-directory # Create a directory and notebook in that directory sub_dir = '/foo/' self.make_dir(nm.notebook_dir, 'foo') model = nm.create_notebook(None, sub_dir) name = model['name'] path = model['path'] model = nm.get_notebook(name, path) # Change the name in the model for rename model = nm.save_notebook(model, name, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'Untitled0.ipynb') self.assertEqual(model['path'], sub_dir.strip('/')) def test_save_notebook_with_script(self): nm = self.notebook_manager # Create a notebook model = nm.create_notebook() nm.save_script = True model = nm.create_notebook() name = model['name'] path = model['path'] # Get the model with 'content' full_model = nm.get_notebook(name, path) # Save the notebook model = nm.save_notebook(full_model, name, path) # Check that the script was created py_path = os.path.join(nm.notebook_dir, os.path.splitext(name)[0]+'.py') assert os.path.exists(py_path), py_path def test_delete_notebook(self): nm = self.notebook_manager # Create a notebook nb, name, path = self.new_notebook() # Delete the notebook nm.delete_notebook(name, path) # Check that a 'get' on the deleted notebook raises and error self.assertRaises(HTTPError, nm.get_notebook, name, path) def test_copy_notebook(self): nm = self.notebook_manager path = u'å b' name = u'nb √.ipynb' os.mkdir(os.path.join(nm.notebook_dir, path)) orig = nm.create_notebook({'name' : name}, path=path) # copy with unspecified name copy = nm.copy_notebook(name, path=path) self.assertEqual(copy['name'], orig['name'].replace('.ipynb', '-Copy0.ipynb')) # copy with specified name copy2 = nm.copy_notebook(name, u'copy 2.ipynb', path=path) self.assertEqual(copy2['name'], u'copy 2.ipynb') def test_trust_notebook(self): nbm = self.notebook_manager nb, name, path = self.new_notebook() untrusted = nbm.get_notebook(name, path)['content'] assert not nbm.notary.check_cells(untrusted) # print(untrusted) nbm.trust_notebook(name, path) trusted = nbm.get_notebook(name, path)['content'] # print(trusted) assert nbm.notary.check_cells(trusted) def test_mark_trusted_cells(self): nbm = self.notebook_manager nb, name, path = self.new_notebook() nbm.mark_trusted_cells(nb, name, path) for cell in nb.worksheets[0].cells: if cell.cell_type == 'code': assert not cell.trusted nbm.trust_notebook(name, path) nb = nbm.get_notebook(name, path)['content'] for cell in nb.worksheets[0].cells: if cell.cell_type == 'code': assert cell.trusted def test_check_and_sign(self): nbm = self.notebook_manager nb, name, path = self.new_notebook() nbm.mark_trusted_cells(nb, name, path) nbm.check_and_sign(nb, name, path) assert not nbm.notary.check_signature(nb) nbm.trust_notebook(name, path) nb = nbm.get_notebook(name, path)['content'] nbm.mark_trusted_cells(nb, name, path) nbm.check_and_sign(nb, name, path) assert nbm.notary.check_signature(nb)
class GLFRepl: def __init__(self): self.td = TemporaryDirectory() self.to_clean_up = ['.dot', '.png', '.gfo'] # by default save grammars into td self.grammar_path = self.td.name self.out_count = 0 self.gfRepl = None self.mmtInterface = None if GF_PATH: # start the GF Repl self.gfRepl = GFRepl(GF_PATH) if os.path.isdir(MMT_PATH): # initialize the MMT interface self.mmtInterface = MMTInterface(MMT_PATH) # in case of MMT installation store grammars in MMT archive self.grammar_path = self.mmtInterface.get_cwd() self.MMT_blocked = False self.grammars = self.search_grammars() # content handlers self.handlers = { 'MMT_command': self.handle_mmt_command, 'ELPI_command': self.handle_elpi_command, 'GF_command': self.handle_gf_command, 'kernel_command': self.handle_kernel_command } # load help messages from messages.json file messages_path = os.path.dirname(os.path.realpath(__file__)) try: with open(os.path.join(messages_path, 'messages.json')) as f: self.messages = load(f) except: self.messages = None def do_shutdown(self): """Terminates the GF shell and the MMT subprocess""" self.td.cleanup() if self.gfRepl: self.gfRepl.do_shutdown() if self.mmtInterface: self.mmtInterface.do_shutdown() def reload_gfrepl(self): if GF_PATH: self.gfRepl = GFRepl(GF_PATH, self.grammar_path) return 'Successfully reloaded GF' else: return 'No gf executable was found' # ---------------------------------------------------------------------------- # # General Content Handling # # ---------------------------------------------------------------------------- # def handle_input(self, code): """ Parses the `code` from the notebook and delegates command handling to the respective handlers `code`: str; the user input from the notebook """ messages = [] parse_dict = parse(code) if parse_dict['type']: if parse_dict['type'] == 'commands': for command in parse_dict['commands']: pipe_commands = command['pipe_commands'] pipe_res = [] for pipe_command in pipe_commands: pipe_command_type = pipe_command['type'] pipe_command_str = pipe_command['command'] if pipe_commands.index(pipe_command) == 0: res = self.handlers[pipe_command_type]( pipe_command_str) name = get_name(pipe_command_str) trees = [] try: # TODO make this produce a meaningful error message lines = res.split('\n') except: continue for line in lines: if line != '' and line != ' ' and line != '\n': if name == 'parse' or name == 'p': trees.append(line) pipe_res.append(line) else: # in case the output contains multiple lines new_pipe_res = [] for res in pipe_res: new_res = self.handlers[pipe_command_type]( '%s %s' % (pipe_command_str, res)) new_pipe_res.append(new_res) pipe_res = new_pipe_res messages.append(to_message_format(trees=trees)) for res in pipe_res: if type(res) is dict: messages.append(res) else: messages.append(to_message_format(message=res)) elif parse_dict['type'] == 'GFContent': messages.append( to_message_format( message=self.handle_grammar(code, parse_dict['name']))) elif parse_dict['type'] == 'MMTContent': if self.mmtInterface: messages.append( to_message_format( message=self.mmtInterface.create_mmt_file( code, parse_dict['name'], parse_dict['mmt_type']))) else: messages.append( to_message_format( message= "No MMT installation found. MMT content not available." )) elif parse_dict['type'] == 'ELPIContent': messages.append( to_message_format(message=self.handle_elpi_rules( code, parse_dict['name']))) else: messages.append( to_message_format( message= "Input is neither valid GF or MMT content nor a valid shell command!" )) return messages # ---------------------------------------------------------------------------- # # Kernel Commands # # ---------------------------------------------------------------------------- # def handle_kernel_command(self, command): """ Handles the Kernel-Commands `show`, `clean, `export` and `help` 'command': str; the command """ name = get_name(command) args = get_args(command) if name == 'show': graph = ' '.join(args) return to_message_format(graph=graph) elif name == 'clean': return self.clean_up() elif name == 'export': return self.do_export(args[0]) elif name == 'grammar-path': self.grammar_path = create_nested_dir(os.getcwd(), args[0]) gf_msg = self.reload_gfrepl() if self.mmtInterface: self.MMT_blocked = True return "Set grammar-path to %s. MMT functionality is now disabled.\n%s" % ( self.grammar_path, gf_msg) return "Set grammar-path to %s.\n%s" % (self.grammar_path, gf_msg) elif name == 'help': if not self.messages: return "No help available" if args: name = args[0] if name in self.messages.keys(): return self.messages[name] else: return "No help available on %s" % (name) else: return self.messages['help'] def convert_to_png(self, graph): """ Converts the given `graph` into a png Returns the file name of the picture `graph`: str """ out_dot = os.path.join(self.td.name, 'out%s.dot' % (self.out_count)) out_png = os.path.join(self.td.name, 'out%s.png' % (self.out_count)) with open(out_dot, 'w') as f: f.write(graph) DOT_ARGS = ['dot', '-Tpng', out_dot, '-o', out_png] p = Popen(DOT_ARGS, shell=False) p.communicate()[0] p.kill() self.out_count += 1 return out_png def clean_up(self): """Removes all files whose extensions are contained in `self.to_clean_up`""" removed = [] files = os.listdir('.') for file in files: _, file_extension = os.path.splitext(file) if file_extension in self.to_clean_up: removed.append(file) os.remove(file) if removed: s = map(lambda x: 'Removed: %s' % (x), removed) return "\n".join(s) else: return "No files removed" def do_export(self, file_name): """ Handles an export command Copies the specified Grammar to the current working directory `file_name`: str; the name of the file to export """ args = get_args(file_name) if len(args) > 1: return "export only takes one argument!" source_path = os.path.join(self.mmtInterface.content_path, self.mmtInterface.archive, 'source') files = os.listdir(source_path) file_reg = re.compile('^%s.gf$' % (file_name)) for file in files: if file_reg.match(file): from shutil import copy2 copy2(os.path.join(source_path, file), file) return 'Exported %s' % (file) return 'Could not find %s' % (file_name) # ---------------------------------------------------------------------------- # # ELPI Commands # # ---------------------------------------------------------------------------- # def handle_elpi_command(self, command): args = get_args(command) if len(args) < 3: return 'ERROR: "elpi" command requires at least 3 arguments (command, file and rule)' command = args[0] if command not in ['filter']: return 'Unknown command: ' + command filename = args[1] if not filename.endswith('.elpi'): filename += '.elpi' rule = args[2] argsmerged = ' '.join(args[3:]) fullcommand = f'glif.{command} {rule} [{argsmerged}]' extraargs = '' elpi = subprocess.Popen(( find_executable('elpi'), '-exec', fullcommand, os.path.join(self.mmtInterface.get_cwd(), filename), '--', extraargs, ), stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE, text=True) out, err = elpi.communicate() if elpi.returncode not in [0, 1]: return 'ELPI ERROR: ' + str( elpi.returncode) + '\nOUTPUT:\n' + out + '\nERROR:\n' + err else: return out # ---------------------------------------------------------------------------- # # MMT Commands # # ---------------------------------------------------------------------------- # def handle_mmt_command(self, command): """ Handles the MMT-Commands 'archive', 'construct' and 'subdir' 'command': str; the command """ if not self.mmtInterface: return "MMT functionality unavailable. No MMT installation detected." if self.MMT_blocked: return "MMT-functionality is blocked due to changes to the storing location for Grammars with 'grammar-location'." name = get_name(command) args = get_args(command) if name == 'archive': if not args: # TODO make this into a string so output order doesn't get screwed tree(dir=self.mmtInterface.get_archive_path(), archive_name=self.mmtInterface.get_archive()) return '' if len(args) > 1: return 'archive takes only one argument!' msg = self.mmtInterface.handle_archive(args[0]) self.grammar_path = self.mmtInterface.get_cwd() gf_msg = self.reload_gfrepl() return msg + '\n' + gf_msg if name == 'archives': return ', '.join(self.mmtInterface.get_archives()) elif name == 'construct': view = None i = 0 toElpi = False while True: if args[i] == '-v' or args[i] == '-view': if len(args) <= i: return f'{args[i]} option requires argument' view = args[i + 1] i += 2 elif args[i] == '-e' or args[i] == '-elpi': toElpi = True i += 1 else: break ASTsStr = ' '.join(args[i:]) h = ASTsStr.split('|') ASTs = list(map(str.strip, h)) return self.mmtInterface.construct(ASTs, view, toElpi) elif name == 'elpigen': theory = None mode = None targetName = None meta = False includes = True i = 0 while True: if not i < len(args): break if args[i] == '-o' or args[i] == '-out': if not i + 1 < len(args): return f'Option {args[i]} requires argument' targetName = args[i + 1] i += 2 continue if args[i] == '-noincludes': includes = False elif args[i] == '-withmeta': meta = True elif not mode: mode = args[i] elif not theory: theory = args[i] else: return 'Too many arguments' i += 1 if not mode: return 'No mode specified' if not theory: return 'No theory specified' result = self.mmtInterface.elpigen(mode, theory, targetName, meta, includes) if not result[0]: return 'An error occured:\n' + result[1] elpicode = result[1] if not targetName: targetName = theory if not targetName.endswith('.elpi'): targetName += '.elpi' with open(os.path.join(self.mmtInterface.get_cwd(), targetName), 'w') as fp: fp.write(str(elpicode)) return 'Success' elif name == 'subdir': if args and len(args) == 1: msg = self.mmtInterface.create_subdir(args[0]) self.grammar_path = self.mmtInterface.get_cwd() gf_msg = self.reload_gfrepl() return msg + '\n' + gf_msg elif not args: return os.path.relpath( self.mmtInterface.get_cwd(), os.path.join(self.mmtInterface.get_archive_path(), 'source')) # ---------------------------------------------------------------------------- # # GF Content # # ---------------------------------------------------------------------------- # def handle_gf_command(self, command): if not self.gfRepl: return "GF functionality unavailable. No GF installation detected." return self.gfRepl.handle_gf_command(command) def handle_elpi_rules(self, content, name): if not name.endswith('.elpi'): name += '.elpi' file_path = os.path.join(self.grammar_path, name) try: shutil.copyfile( os.path.join(os.path.dirname(os.path.realpath(__file__)), 'glif.elpi'), os.path.join(self.mmtInterface.get_cwd(), 'glif.elpi')) with open(file_path, 'w') as f: f.write('accumulate glif.\n' + '\n'.join(content.splitlines()[1:])) f.close() except OSError as ex: return 'Failed to create %s:\n%s' % (name, ex) return 'Created ' + name def handle_grammar(self, content, name): """ Handles grammar input `content`: str; the content of the grammar `name`: str; the name of the grammar """ file_name = "%s.gf" % (name) file_path = os.path.join(self.grammar_path, file_name) try: with open(file_path, 'w') as f: f.write(content) f.close() except OSError: return 'Failed to create grammar %s' % (name) out = self.handle_gf_command("import %s" % (file_path)) if out == 'success' or out.startswith('Abstract changed'): if not self.mmtInterface: self.grammars[name] = file_path return "Defined %s" % (name) build_result = self.mmtInterface.build_file( file_name) # build the Grammar with the GlfBuild extension if build_result['isSuccessful']: self.grammars[name] = file_path return "Defined %s" % (name) else: return '\n'.join(build_result['errors']) return out def search_grammars(self): grammars = {} cwd = self.grammar_path for file in os.listdir(cwd): if file.endswith(".gf"): path = os.path.join(cwd, file) name = os.path.splitext(file) grammars[name] = path return grammars def get_grammars(self): return self.grammars
class TestContentsManager(TestCase): def setUp(self): self._temp_dir = TemporaryDirectory() self.td = self._temp_dir.name self.contents_manager = FileContentsManager(root_dir=self.td) def tearDown(self): self._temp_dir.cleanup() @contextmanager def assertRaisesHTTPError(self, status, msg=None): msg = msg or "Should have raised HTTPError(%i)" % status try: yield except HTTPError as e: self.assertEqual(e.status_code, status) else: self.fail(msg) def make_dir(self, api_path): """make a subdirectory at api_path override in subclasses if contents are not on the filesystem. """ _make_dir(self.contents_manager, api_path) def add_code_cell(self, nb): output = nbformat.new_output("display_data", {"application/javascript": "alert('hi');"}) cell = nbformat.new_code_cell("print('hi')", outputs=[output]) nb.cells.append(cell) def new_notebook(self): cm = self.contents_manager model = cm.new_untitled(type="notebook") name = model["name"] path = model["path"] full_model = cm.get(path) nb = full_model["content"] nb["metadata"]["counter"] = int(1e6 * time.time()) self.add_code_cell(nb) cm.save(full_model, path) return nb, name, path def test_new_untitled(self): cm = self.contents_manager # Test in root directory model = cm.new_untitled(type="notebook") assert isinstance(model, dict) self.assertIn("name", model) self.assertIn("path", model) self.assertIn("type", model) self.assertEqual(model["type"], "notebook") self.assertEqual(model["name"], "Untitled.ipynb") self.assertEqual(model["path"], "Untitled.ipynb") # Test in sub-directory model = cm.new_untitled(type="directory") assert isinstance(model, dict) self.assertIn("name", model) self.assertIn("path", model) self.assertIn("type", model) self.assertEqual(model["type"], "directory") self.assertEqual(model["name"], "Untitled Folder") self.assertEqual(model["path"], "Untitled Folder") sub_dir = model["path"] model = cm.new_untitled(path=sub_dir) assert isinstance(model, dict) self.assertIn("name", model) self.assertIn("path", model) self.assertIn("type", model) self.assertEqual(model["type"], "file") self.assertEqual(model["name"], "untitled") self.assertEqual(model["path"], "%s/untitled" % sub_dir) def test_get(self): cm = self.contents_manager # Create a notebook model = cm.new_untitled(type="notebook") name = model["name"] path = model["path"] # Check that we 'get' on the notebook we just created model2 = cm.get(path) assert isinstance(model2, dict) self.assertIn("name", model2) self.assertIn("path", model2) self.assertEqual(model["name"], name) self.assertEqual(model["path"], path) nb_as_file = cm.get(path, content=True, type="file") self.assertEqual(nb_as_file["path"], path) self.assertEqual(nb_as_file["type"], "file") self.assertEqual(nb_as_file["format"], "text") self.assertNotIsInstance(nb_as_file["content"], dict) nb_as_bin_file = cm.get(path, content=True, type="file", format="base64") self.assertEqual(nb_as_bin_file["format"], "base64") # Test in sub-directory sub_dir = "/foo/" self.make_dir("foo") model = cm.new_untitled(path=sub_dir, ext=".ipynb") model2 = cm.get(sub_dir + name) assert isinstance(model2, dict) self.assertIn("name", model2) self.assertIn("path", model2) self.assertIn("content", model2) self.assertEqual(model2["name"], "Untitled.ipynb") self.assertEqual(model2["path"], "{0}/{1}".format(sub_dir.strip("/"), name)) # Test with a regular file. file_model_path = cm.new_untitled(path=sub_dir, ext=".txt")["path"] file_model = cm.get(file_model_path) self.assertDictContainsSubset( { "content": u"", "format": u"text", "mimetype": u"text/plain", "name": u"untitled.txt", "path": u"foo/untitled.txt", "type": u"file", "writable": True, }, file_model, ) self.assertIn("created", file_model) self.assertIn("last_modified", file_model) # Test getting directory model # Create a sub-sub directory to test getting directory contents with a # subdir. self.make_dir("foo/bar") dirmodel = cm.get("foo") self.assertEqual(dirmodel["type"], "directory") self.assertIsInstance(dirmodel["content"], list) self.assertEqual(len(dirmodel["content"]), 3) self.assertEqual(dirmodel["path"], "foo") self.assertEqual(dirmodel["name"], "foo") # Directory contents should match the contents of each individual entry # when requested with content=False. model2_no_content = cm.get(sub_dir + name, content=False) file_model_no_content = cm.get(u"foo/untitled.txt", content=False) sub_sub_dir_no_content = cm.get("foo/bar", content=False) self.assertEqual(sub_sub_dir_no_content["path"], "foo/bar") self.assertEqual(sub_sub_dir_no_content["name"], "bar") for entry in dirmodel["content"]: # Order isn't guaranteed by the spec, so this is a hacky way of # verifying that all entries are matched. if entry["path"] == sub_sub_dir_no_content["path"]: self.assertEqual(entry, sub_sub_dir_no_content) elif entry["path"] == model2_no_content["path"]: self.assertEqual(entry, model2_no_content) elif entry["path"] == file_model_no_content["path"]: self.assertEqual(entry, file_model_no_content) else: self.fail("Unexpected directory entry: %s" % entry()) with self.assertRaises(HTTPError): cm.get("foo", type="file") def test_update(self): cm = self.contents_manager # Create a notebook model = cm.new_untitled(type="notebook") name = model["name"] path = model["path"] # Change the name in the model for rename model["path"] = "test.ipynb" model = cm.update(model, path) assert isinstance(model, dict) self.assertIn("name", model) self.assertIn("path", model) self.assertEqual(model["name"], "test.ipynb") # Make sure the old name is gone self.assertRaises(HTTPError, cm.get, path) # Test in sub-directory # Create a directory and notebook in that directory sub_dir = "/foo/" self.make_dir("foo") model = cm.new_untitled(path=sub_dir, type="notebook") path = model["path"] # Change the name in the model for rename d = path.rsplit("/", 1)[0] new_path = model["path"] = d + "/test_in_sub.ipynb" model = cm.update(model, path) assert isinstance(model, dict) self.assertIn("name", model) self.assertIn("path", model) self.assertEqual(model["name"], "test_in_sub.ipynb") self.assertEqual(model["path"], new_path) # Make sure the old name is gone self.assertRaises(HTTPError, cm.get, path) def test_save(self): cm = self.contents_manager # Create a notebook model = cm.new_untitled(type="notebook") name = model["name"] path = model["path"] # Get the model with 'content' full_model = cm.get(path) # Save the notebook model = cm.save(full_model, path) assert isinstance(model, dict) self.assertIn("name", model) self.assertIn("path", model) self.assertEqual(model["name"], name) self.assertEqual(model["path"], path) # Test in sub-directory # Create a directory and notebook in that directory sub_dir = "/foo/" self.make_dir("foo") model = cm.new_untitled(path=sub_dir, type="notebook") name = model["name"] path = model["path"] model = cm.get(path) # Change the name in the model for rename model = cm.save(model, path) assert isinstance(model, dict) self.assertIn("name", model) self.assertIn("path", model) self.assertEqual(model["name"], "Untitled.ipynb") self.assertEqual(model["path"], "foo/Untitled.ipynb") def test_delete(self): cm = self.contents_manager # Create a notebook nb, name, path = self.new_notebook() # Delete the notebook cm.delete(path) # Check that deleting a non-existent path raises an error. self.assertRaises(HTTPError, cm.delete, path) # Check that a 'get' on the deleted notebook raises and error self.assertRaises(HTTPError, cm.get, path) def test_copy(self): cm = self.contents_manager parent = u"å b" name = u"nb √.ipynb" path = u"{0}/{1}".format(parent, name) self.make_dir(parent) orig = cm.new(path=path) # copy with unspecified name copy = cm.copy(path) self.assertEqual(copy["name"], orig["name"].replace(".ipynb", "-Copy1.ipynb")) # copy with specified name copy2 = cm.copy(path, u"å b/copy 2.ipynb") self.assertEqual(copy2["name"], u"copy 2.ipynb") self.assertEqual(copy2["path"], u"å b/copy 2.ipynb") # copy with specified path copy2 = cm.copy(path, u"/") self.assertEqual(copy2["name"], name) self.assertEqual(copy2["path"], name) def test_trust_notebook(self): cm = self.contents_manager nb, name, path = self.new_notebook() untrusted = cm.get(path)["content"] assert not cm.notary.check_cells(untrusted) # print(untrusted) cm.trust_notebook(path) trusted = cm.get(path)["content"] # print(trusted) assert cm.notary.check_cells(trusted) def test_mark_trusted_cells(self): cm = self.contents_manager nb, name, path = self.new_notebook() cm.mark_trusted_cells(nb, path) for cell in nb.cells: if cell.cell_type == "code": assert not cell.metadata.trusted cm.trust_notebook(path) nb = cm.get(path)["content"] for cell in nb.cells: if cell.cell_type == "code": assert cell.metadata.trusted def test_check_and_sign(self): cm = self.contents_manager nb, name, path = self.new_notebook() cm.mark_trusted_cells(nb, path) cm.check_and_sign(nb, path) assert not cm.notary.check_signature(nb) cm.trust_notebook(path) nb = cm.get(path)["content"] cm.mark_trusted_cells(nb, path) cm.check_and_sign(nb, path) assert cm.notary.check_signature(nb) def test_escape_root(self): cm = self.contents_manager # make foo, bar next to root with open(os.path.join(cm.root_dir, "..", "foo"), "w") as f: f.write("foo") with open(os.path.join(cm.root_dir, "..", "bar"), "w") as f: f.write("bar") with self.assertRaisesHTTPError(404): cm.get("..") with self.assertRaisesHTTPError(404): cm.get("foo/../../../bar") with self.assertRaisesHTTPError(404): cm.delete("../foo") with self.assertRaisesHTTPError(404): cm.rename("../foo", "../bar") with self.assertRaisesHTTPError(404): cm.save(model={"type": "file", "content": u"", "format": "text"}, path="../foo")
class TestMagicRunWithPackage(unittest.TestCase): def writefile(self, name, content): path = os.path.join(self.tempdir.name, name) d = os.path.dirname(path) if not os.path.isdir(d): os.makedirs(d) with open(path, 'w') as f: f.write(textwrap.dedent(content)) def setUp(self): self.package = package = 'tmp{0}'.format(repr(random.random())[2:]) """Temporary valid python package name.""" self.value = int(random.random() * 10000) self.tempdir = TemporaryDirectory() self.__orig_cwd = py3compat.getcwd() sys.path.insert(0, self.tempdir.name) self.writefile(os.path.join(package, '__init__.py'), '') self.writefile(os.path.join(package, 'sub.py'), """ x = {0!r} """.format(self.value)) self.writefile(os.path.join(package, 'relative.py'), """ from .sub import x """) self.writefile(os.path.join(package, 'absolute.py'), """ from {0}.sub import x """.format(package)) def tearDown(self): os.chdir(self.__orig_cwd) sys.path[:] = [p for p in sys.path if p != self.tempdir.name] self.tempdir.cleanup() def check_run_submodule(self, submodule, opts=''): _ip.user_ns.pop('x', None) _ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts)) self.assertEqual(_ip.user_ns['x'], self.value, 'Variable `x` is not loaded from module `{0}`.' .format(submodule)) def test_run_submodule_with_absolute_import(self): self.check_run_submodule('absolute') def test_run_submodule_with_relative_import(self): """Run submodule that has a relative import statement (#2727).""" self.check_run_submodule('relative') def test_prun_submodule_with_absolute_import(self): self.check_run_submodule('absolute', '-p') def test_prun_submodule_with_relative_import(self): self.check_run_submodule('relative', '-p') def with_fake_debugger(func): @functools.wraps(func) def wrapper(*args, **kwds): with tt.monkeypatch(debugger.Pdb, 'run', staticmethod(eval)): return func(*args, **kwds) return wrapper @with_fake_debugger def test_debug_run_submodule_with_absolute_import(self): self.check_run_submodule('absolute', '-d') @with_fake_debugger def test_debug_run_submodule_with_relative_import(self): self.check_run_submodule('relative', '-d')
class TestContentsManager(TestCase): def setUp(self): self._temp_dir = TemporaryDirectory() self.td = self._temp_dir.name self.contents_manager = FileContentsManager( root_dir=self.td, ) def tearDown(self): self._temp_dir.cleanup() def make_dir(self, abs_path, rel_path): """make subdirectory, rel_path is the relative path to that directory from the location where the server started""" os_path = os.path.join(abs_path, rel_path) try: os.makedirs(os_path) except OSError: print("Directory already exists: %r" % os_path) return os_path def add_code_cell(self, nb): output = nbformat.new_output("display_data", {'application/javascript': "alert('hi');"}) cell = nbformat.new_code_cell("print('hi')", outputs=[output]) nb.cells.append(cell) def new_notebook(self): cm = self.contents_manager model = cm.new_untitled(type='notebook') name = model['name'] path = model['path'] full_model = cm.get(path) nb = full_model['content'] self.add_code_cell(nb) cm.save(full_model, path) return nb, name, path def test_new_untitled(self): cm = self.contents_manager # Test in root directory model = cm.new_untitled(type='notebook') assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertIn('type', model) self.assertEqual(model['type'], 'notebook') self.assertEqual(model['name'], 'Untitled.ipynb') self.assertEqual(model['path'], 'Untitled.ipynb') # Test in sub-directory model = cm.new_untitled(type='directory') assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertIn('type', model) self.assertEqual(model['type'], 'directory') self.assertEqual(model['name'], 'Untitled Folder') self.assertEqual(model['path'], 'Untitled Folder') sub_dir = model['path'] model = cm.new_untitled(path=sub_dir) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertIn('type', model) self.assertEqual(model['type'], 'file') self.assertEqual(model['name'], 'untitled') self.assertEqual(model['path'], '%s/untitled' % sub_dir) def test_get(self): cm = self.contents_manager # Create a notebook model = cm.new_untitled(type='notebook') name = model['name'] path = model['path'] # Check that we 'get' on the notebook we just created model2 = cm.get(path) assert isinstance(model2, dict) self.assertIn('name', model2) self.assertIn('path', model2) self.assertEqual(model['name'], name) self.assertEqual(model['path'], path) nb_as_file = cm.get(path, content=True, type='file') self.assertEqual(nb_as_file['path'], path) self.assertEqual(nb_as_file['type'], 'file') self.assertEqual(nb_as_file['format'], 'text') self.assertNotIsInstance(nb_as_file['content'], dict) nb_as_bin_file = cm.get(path, content=True, type='file', format='base64') self.assertEqual(nb_as_bin_file['format'], 'base64') # Test in sub-directory sub_dir = '/foo/' self.make_dir(cm.root_dir, 'foo') model = cm.new_untitled(path=sub_dir, ext='.ipynb') model2 = cm.get(sub_dir + name) assert isinstance(model2, dict) self.assertIn('name', model2) self.assertIn('path', model2) self.assertIn('content', model2) self.assertEqual(model2['name'], 'Untitled.ipynb') self.assertEqual(model2['path'], '{0}/{1}'.format(sub_dir.strip('/'), name)) # Test getting directory model dirmodel = cm.get('foo') self.assertEqual(dirmodel['type'], 'directory') with self.assertRaises(HTTPError): cm.get('foo', type='file') @dec.skip_win32 def test_bad_symlink(self): cm = self.contents_manager path = 'test bad symlink' os_path = self.make_dir(cm.root_dir, path) file_model = cm.new_untitled(path=path, ext='.txt') # create a broken symlink os.symlink("target", os.path.join(os_path, "bad symlink")) model = cm.get(path) self.assertEqual(model['content'], [file_model]) @dec.skip_win32 def test_good_symlink(self): cm = self.contents_manager parent = 'test good symlink' name = 'good symlink' path = '{0}/{1}'.format(parent, name) os_path = self.make_dir(cm.root_dir, parent) file_model = cm.new(path=parent + '/zfoo.txt') # create a good symlink os.symlink(file_model['name'], os.path.join(os_path, name)) symlink_model = cm.get(path, content=False) dir_model = cm.get(parent) self.assertEqual( sorted(dir_model['content'], key=lambda x: x['name']), [symlink_model, file_model], ) def test_update(self): cm = self.contents_manager # Create a notebook model = cm.new_untitled(type='notebook') name = model['name'] path = model['path'] # Change the name in the model for rename model['path'] = 'test.ipynb' model = cm.update(model, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'test.ipynb') # Make sure the old name is gone self.assertRaises(HTTPError, cm.get, path) # Test in sub-directory # Create a directory and notebook in that directory sub_dir = '/foo/' self.make_dir(cm.root_dir, 'foo') model = cm.new_untitled(path=sub_dir, type='notebook') name = model['name'] path = model['path'] # Change the name in the model for rename d = path.rsplit('/', 1)[0] new_path = model['path'] = d + '/test_in_sub.ipynb' model = cm.update(model, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'test_in_sub.ipynb') self.assertEqual(model['path'], new_path) # Make sure the old name is gone self.assertRaises(HTTPError, cm.get, path) def test_save(self): cm = self.contents_manager # Create a notebook model = cm.new_untitled(type='notebook') name = model['name'] path = model['path'] # Get the model with 'content' full_model = cm.get(path) # Save the notebook model = cm.save(full_model, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], name) self.assertEqual(model['path'], path) # Test in sub-directory # Create a directory and notebook in that directory sub_dir = '/foo/' self.make_dir(cm.root_dir, 'foo') model = cm.new_untitled(path=sub_dir, type='notebook') name = model['name'] path = model['path'] model = cm.get(path) # Change the name in the model for rename model = cm.save(model, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'Untitled.ipynb') self.assertEqual(model['path'], 'foo/Untitled.ipynb') def test_delete(self): cm = self.contents_manager # Create a notebook nb, name, path = self.new_notebook() # Delete the notebook cm.delete(path) # Check that a 'get' on the deleted notebook raises and error self.assertRaises(HTTPError, cm.get, path) def test_copy(self): cm = self.contents_manager parent = u'å b' name = u'nb √.ipynb' path = u'{0}/{1}'.format(parent, name) os.mkdir(os.path.join(cm.root_dir, parent)) orig = cm.new(path=path) # copy with unspecified name copy = cm.copy(path) self.assertEqual(copy['name'], orig['name'].replace('.ipynb', '-Copy1.ipynb')) # copy with specified name copy2 = cm.copy(path, u'å b/copy 2.ipynb') self.assertEqual(copy2['name'], u'copy 2.ipynb') self.assertEqual(copy2['path'], u'å b/copy 2.ipynb') # copy with specified path copy2 = cm.copy(path, u'/') self.assertEqual(copy2['name'], name) self.assertEqual(copy2['path'], name) def test_trust_notebook(self): cm = self.contents_manager nb, name, path = self.new_notebook() untrusted = cm.get(path)['content'] assert not cm.notary.check_cells(untrusted) # print(untrusted) cm.trust_notebook(path) trusted = cm.get(path)['content'] # print(trusted) assert cm.notary.check_cells(trusted) def test_mark_trusted_cells(self): cm = self.contents_manager nb, name, path = self.new_notebook() cm.mark_trusted_cells(nb, path) for cell in nb.cells: if cell.cell_type == 'code': assert not cell.metadata.trusted cm.trust_notebook(path) nb = cm.get(path)['content'] for cell in nb.cells: if cell.cell_type == 'code': assert cell.metadata.trusted def test_check_and_sign(self): cm = self.contents_manager nb, name, path = self.new_notebook() cm.mark_trusted_cells(nb, path) cm.check_and_sign(nb, path) assert not cm.notary.check_signature(nb) cm.trust_notebook(path) nb = cm.get(path)['content'] cm.mark_trusted_cells(nb, path) cm.check_and_sign(nb, path) assert cm.notary.check_signature(nb)
class TestUploadDownload(TestCase): def setUp(self): self.td = TemporaryDirectory() self.checkpoints = PostgresCheckpoints( user_id='test', db_url=TEST_DB_URL, ) self.contents = FileContentsManager( root_dir=self.td.name, checkpoints=self.checkpoints, ) self.checkpoints.ensure_user() def tearDown(self): self.td.cleanup() clear_test_db() def add_markdown_cell(self, path): # Load and update model = self.contents.get(path=path) model['content'].cells.append( new_markdown_cell('Created by test: ' + path)) # Save and checkpoint again. self.contents.save(model, path=path) return model def test_download_checkpoints(self): """ Create two checkpoints for two notebooks, then call download_checkpoints. Assert that we get the correct version of both notebooks. """ self.contents.new({'type': 'directory'}, 'subdir') paths = ('a.ipynb', 'subdir/a.ipynb') expected_content = {} for path in paths: # Create and checkpoint. self.contents.new(path=path) self.contents.create_checkpoint(path) model = self.add_markdown_cell(path) self.contents.create_checkpoint(path) # Assert greater because FileContentsManager creates a checkpoint # on creation, but this isn't part of the spec. self.assertGreater(len(self.contents.list_checkpoints(path)), 2) # Store the content to verify correctness after download. expected_content[path] = model['content'] with TemporaryDirectory() as td: download_checkpoints( self.checkpoints.db_url, td, user='******', ) fm = FileContentsManager(root_dir=td) root_entries = sorted(m['path'] for m in fm.get('')['content']) self.assertEqual(root_entries, ['a.ipynb', 'subdir']) subdir_entries = sorted(m['path'] for m in fm.get('subdir')['content']) self.assertEqual(subdir_entries, ['subdir/a.ipynb']) for path in paths: content = fm.get(path)['content'] self.assertEqual(expected_content[path], content) def test_checkpoint_all(self): """ Test that checkpoint_all correctly makes a checkpoint for all files. """ paths = populate(self.contents) original_content_minus_trust = { # Remove metadata that we expect to have dropped path: strip_transient(self.contents.get(path)['content']) for path in paths } original_cps = {} for path in paths: # Create a checkpoint, then update the file. original_cps[path] = self.contents.create_checkpoint(path) self.add_markdown_cell(path) # Verify that we still have the old version checkpointed. cp_content = { path: self.checkpoints.get_notebook_checkpoint( cp['id'], path, )['content'] for path, cp in iteritems(original_cps) } self.assertEqual(original_content_minus_trust, cp_content) new_cps = checkpoint_all( self.checkpoints.db_url, self.td.name, self.checkpoints.user_id, ) new_cp_content = { path: self.checkpoints.get_notebook_checkpoint( cp['id'], path, )['content'] for path, cp in iteritems(new_cps) } for path, new_content in iteritems(new_cp_content): old_content = original_content_minus_trust[_norm_unicode(path)] self.assertEqual( new_content['cells'][:-1], old_content['cells'], ) self.assertEqual( new_content['cells'][-1], new_markdown_cell('Created by test: ' + _norm_unicode(path)), )
class TestLinkOrCopy(object): def setUp(self): self.tempdir = TemporaryDirectory() self.src = self.dst("src") with open(self.src, "w") as f: f.write("Hello, world!") def tearDown(self): self.tempdir.cleanup() def dst(self, *args): return os.path.join(self.tempdir.name, *args) def assert_inode_not_equal(self, a, b): nt.assert_not_equals(os.stat(a).st_ino, os.stat(b).st_ino, "%r and %r do reference the same indoes" %(a, b)) def assert_inode_equal(self, a, b): nt.assert_equals(os.stat(a).st_ino, os.stat(b).st_ino, "%r and %r do not reference the same indoes" %(a, b)) def assert_content_equal(self, a, b): with open(a) as a_f: with open(b) as b_f: nt.assert_equals(a_f.read(), b_f.read()) @skip_win32 def test_link_successful(self): dst = self.dst("target") path.link_or_copy(self.src, dst) self.assert_inode_equal(self.src, dst) @skip_win32 def test_link_into_dir(self): dst = self.dst("some_dir") os.mkdir(dst) path.link_or_copy(self.src, dst) expected_dst = self.dst("some_dir", os.path.basename(self.src)) self.assert_inode_equal(self.src, expected_dst) @skip_win32 def test_target_exists(self): dst = self.dst("target") open(dst, "w").close() path.link_or_copy(self.src, dst) self.assert_inode_equal(self.src, dst) @skip_win32 def test_no_link(self): real_link = os.link try: del os.link dst = self.dst("target") path.link_or_copy(self.src, dst) self.assert_content_equal(self.src, dst) self.assert_inode_not_equal(self.src, dst) finally: os.link = real_link @skip_if_not_win32 def test_windows(self): dst = self.dst("target") path.link_or_copy(self.src, dst) self.assert_content_equal(self.src, dst)
class TestContentsManager(TestCase): def setUp(self): self._temp_dir = TemporaryDirectory() self.td = self._temp_dir.name self.contents_manager = FileContentsManager( root_dir=self.td, log=logging.getLogger() ) def tearDown(self): self._temp_dir.cleanup() def make_dir(self, abs_path, rel_path): """make subdirectory, rel_path is the relative path to that directory from the location where the server started""" os_path = os.path.join(abs_path, rel_path) try: os.makedirs(os_path) except OSError: print("Directory already exists: %r" % os_path) return os_path def add_code_cell(self, nb): output = current.new_output("display_data", output_javascript="alert('hi');") cell = current.new_code_cell("print('hi')", outputs=[output]) if not nb.worksheets: nb.worksheets.append(current.new_worksheet()) nb.worksheets[0].cells.append(cell) def new_notebook(self): cm = self.contents_manager model = cm.create_file() name = model['name'] path = model['path'] full_model = cm.get_model(name, path) nb = full_model['content'] self.add_code_cell(nb) cm.save(full_model, name, path) return nb, name, path def test_create_file(self): cm = self.contents_manager # Test in root directory model = cm.create_file() assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'Untitled0.ipynb') self.assertEqual(model['path'], '') # Test in sub-directory sub_dir = '/foo/' self.make_dir(cm.root_dir, 'foo') model = cm.create_file(None, sub_dir) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'Untitled0.ipynb') self.assertEqual(model['path'], sub_dir.strip('/')) def test_get(self): cm = self.contents_manager # Create a notebook model = cm.create_file() name = model['name'] path = model['path'] # Check that we 'get' on the notebook we just created model2 = cm.get_model(name, path) assert isinstance(model2, dict) self.assertIn('name', model2) self.assertIn('path', model2) self.assertEqual(model['name'], name) self.assertEqual(model['path'], path) # Test in sub-directory sub_dir = '/foo/' self.make_dir(cm.root_dir, 'foo') model = cm.create_file(None, sub_dir) model2 = cm.get_model(name, sub_dir) assert isinstance(model2, dict) self.assertIn('name', model2) self.assertIn('path', model2) self.assertIn('content', model2) self.assertEqual(model2['name'], 'Untitled0.ipynb') self.assertEqual(model2['path'], sub_dir.strip('/')) @dec.skip_win32 def test_bad_symlink(self): cm = self.contents_manager path = 'test bad symlink' os_path = self.make_dir(cm.root_dir, path) file_model = cm.create_file(path=path, ext='.txt') # create a broken symlink os.symlink("target", os.path.join(os_path, "bad symlink")) model = cm.get_model(path) self.assertEqual(model['content'], [file_model]) @dec.skip_win32 def test_good_symlink(self): cm = self.contents_manager path = 'test good symlink' os_path = self.make_dir(cm.root_dir, path) file_model = cm.create_file(path=path, ext='.txt') # create a good symlink os.symlink(file_model['name'], os.path.join(os_path, "good symlink")) symlink_model = cm.get_model(name="good symlink", path=path, content=False) dir_model = cm.get_model(path) self.assertEqual( sorted(dir_model['content'], key=lambda x: x['name']), [symlink_model, file_model], ) def test_update(self): cm = self.contents_manager # Create a notebook model = cm.create_file() name = model['name'] path = model['path'] # Change the name in the model for rename model['name'] = 'test.ipynb' model = cm.update(model, name, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'test.ipynb') # Make sure the old name is gone self.assertRaises(HTTPError, cm.get_model, name, path) # Test in sub-directory # Create a directory and notebook in that directory sub_dir = '/foo/' self.make_dir(cm.root_dir, 'foo') model = cm.create_file(None, sub_dir) name = model['name'] path = model['path'] # Change the name in the model for rename model['name'] = 'test_in_sub.ipynb' model = cm.update(model, name, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'test_in_sub.ipynb') self.assertEqual(model['path'], sub_dir.strip('/')) # Make sure the old name is gone self.assertRaises(HTTPError, cm.get_model, name, path) def test_save(self): cm = self.contents_manager # Create a notebook model = cm.create_file() name = model['name'] path = model['path'] # Get the model with 'content' full_model = cm.get_model(name, path) # Save the notebook model = cm.save(full_model, name, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], name) self.assertEqual(model['path'], path) # Test in sub-directory # Create a directory and notebook in that directory sub_dir = '/foo/' self.make_dir(cm.root_dir, 'foo') model = cm.create_file(None, sub_dir) name = model['name'] path = model['path'] model = cm.get_model(name, path) # Change the name in the model for rename model = cm.save(model, name, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'Untitled0.ipynb') self.assertEqual(model['path'], sub_dir.strip('/')) def test_delete(self): cm = self.contents_manager # Create a notebook nb, name, path = self.new_notebook() # Delete the notebook cm.delete(name, path) # Check that a 'get' on the deleted notebook raises and error self.assertRaises(HTTPError, cm.get_model, name, path) def test_copy(self): cm = self.contents_manager path = u'å b' name = u'nb √.ipynb' os.mkdir(os.path.join(cm.root_dir, path)) orig = cm.create_file({'name' : name}, path=path) # copy with unspecified name copy = cm.copy(name, path=path) self.assertEqual(copy['name'], orig['name'].replace('.ipynb', '-Copy0.ipynb')) # copy with specified name copy2 = cm.copy(name, u'copy 2.ipynb', path=path) self.assertEqual(copy2['name'], u'copy 2.ipynb') def test_trust_notebook(self): cm = self.contents_manager nb, name, path = self.new_notebook() untrusted = cm.get_model(name, path)['content'] assert not cm.notary.check_cells(untrusted) # print(untrusted) cm.trust_notebook(name, path) trusted = cm.get_model(name, path)['content'] # print(trusted) assert cm.notary.check_cells(trusted) def test_mark_trusted_cells(self): cm = self.contents_manager nb, name, path = self.new_notebook() cm.mark_trusted_cells(nb, name, path) for cell in nb.worksheets[0].cells: if cell.cell_type == 'code': assert not cell.trusted cm.trust_notebook(name, path) nb = cm.get_model(name, path)['content'] for cell in nb.worksheets[0].cells: if cell.cell_type == 'code': assert cell.trusted def test_check_and_sign(self): cm = self.contents_manager nb, name, path = self.new_notebook() cm.mark_trusted_cells(nb, name, path) cm.check_and_sign(nb, name, path) assert not cm.notary.check_signature(nb) cm.trust_notebook(name, path) nb = cm.get_model(name, path)['content'] cm.mark_trusted_cells(nb, name, path) cm.check_and_sign(nb, name, path) assert cm.notary.check_signature(nb)
class TestUploadDownload(TestCase): def setUp(self): drop_testing_db_tables() migrate_testing_db() self.td = TemporaryDirectory() self.checkpoints = PostgresCheckpoints( user_id='test', db_url=TEST_DB_URL, ) self.contents = FileContentsManager( root_dir=self.td.name, checkpoints=self.checkpoints, ) self.checkpoints.ensure_user() def tearDown(self): self.td.cleanup() def add_markdown_cell(self, path): # Load and update model = self.contents.get(path=path) model['content'].cells.append( new_markdown_cell('Created by test: ' + path) ) # Save and checkpoint again. self.contents.save(model, path=path) return model def test_download_checkpoints(self): """ Create two checkpoints for two notebooks, then call download_checkpoints. Assert that we get the correct version of both notebooks. """ self.contents.new({'type': 'directory'}, 'subdir') paths = ('a.ipynb', 'subdir/a.ipynb') expected_content = {} for path in paths: # Create and checkpoint. self.contents.new(path=path) self.contents.create_checkpoint(path) model = self.add_markdown_cell(path) self.contents.create_checkpoint(path) # Assert greater because FileContentsManager creates a checkpoint # on creation, but this isn't part of the spec. self.assertGreater(len(self.contents.list_checkpoints(path)), 2) # Store the content to verify correctness after download. expected_content[path] = model['content'] with TemporaryDirectory() as td: download_checkpoints( self.checkpoints.db_url, td, user='******', ) fm = FileContentsManager(root_dir=td) root_entries = sorted(m['path'] for m in fm.get('')['content']) self.assertEqual(root_entries, ['a.ipynb', 'subdir']) subdir_entries = sorted( m['path'] for m in fm.get('subdir')['content'] ) self.assertEqual(subdir_entries, ['subdir/a.ipynb']) for path in paths: content = fm.get(path)['content'] self.assertEqual(expected_content[path], content) def test_checkpoint_all(self): """ Test that checkpoint_all correctly makes a checkpoint for all files. """ paths = populate(self.contents) original_content_minus_trust = { # Remove metadata that we expect to have dropped path: strip_transient(self.contents.get(path)['content']) for path in paths } original_cps = {} for path in paths: # Create a checkpoint, then update the file. original_cps[path] = self.contents.create_checkpoint(path) self.add_markdown_cell(path) # Verify that we still have the old version checkpointed. cp_content = { path: self.checkpoints.get_notebook_checkpoint( cp['id'], path, )['content'] for path, cp in iteritems(original_cps) } self.assertEqual(original_content_minus_trust, cp_content) new_cps = checkpoint_all( self.checkpoints.db_url, self.td.name, self.checkpoints.user_id, ) new_cp_content = { path: self.checkpoints.get_notebook_checkpoint( cp['id'], path, )['content'] for path, cp in iteritems(new_cps) } for path, new_content in iteritems(new_cp_content): old_content = original_content_minus_trust[_norm_unicode(path)] self.assertEqual( new_content['cells'][:-1], old_content['cells'], ) self.assertEqual( new_content['cells'][-1], new_markdown_cell('Created by test: ' + _norm_unicode(path)), )
class TestLinkOrCopy(object): def setUp(self): self.tempdir = TemporaryDirectory() self.src = self.dst("src") with open(self.src, "w") as f: f.write("Hello, world!") def tearDown(self): self.tempdir.cleanup() def dst(self, *args): return os.path.join(self.tempdir.name, *args) def assert_inode_not_equal(self, a, b): nt.assert_not_equal(os.stat(a).st_ino, os.stat(b).st_ino, "%r and %r do reference the same indoes" %(a, b)) def assert_inode_equal(self, a, b): nt.assert_equal(os.stat(a).st_ino, os.stat(b).st_ino, "%r and %r do not reference the same indoes" %(a, b)) def assert_content_equal(self, a, b): with open(a) as a_f: with open(b) as b_f: nt.assert_equal(a_f.read(), b_f.read()) @skip_win32 def test_link_successful(self): dst = self.dst("target") path.link_or_copy(self.src, dst) self.assert_inode_equal(self.src, dst) @skip_win32 def test_link_into_dir(self): dst = self.dst("some_dir") os.mkdir(dst) path.link_or_copy(self.src, dst) expected_dst = self.dst("some_dir", os.path.basename(self.src)) self.assert_inode_equal(self.src, expected_dst) @skip_win32 def test_target_exists(self): dst = self.dst("target") open(dst, "w").close() path.link_or_copy(self.src, dst) self.assert_inode_equal(self.src, dst) @skip_win32 def test_no_link(self): real_link = os.link try: del os.link dst = self.dst("target") path.link_or_copy(self.src, dst) self.assert_content_equal(self.src, dst) self.assert_inode_not_equal(self.src, dst) finally: os.link = real_link @skip_if_not_win32 def test_windows(self): dst = self.dst("target") path.link_or_copy(self.src, dst) self.assert_content_equal(self.src, dst) def test_link_twice(self): # Linking the same file twice shouldn't leave duplicates around. # See https://github.com/ipython/ipython/issues/6450 dst = self.dst('target') path.link_or_copy(self.src, dst) path.link_or_copy(self.src, dst) self.assert_inode_equal(self.src, dst) nt.assert_equal(sorted(os.listdir(self.tempdir.name)), ['src', 'target'])
class GLFRepl: def __init__(self): # initialize the MMT interface self.mmtInterface = MMTInterface() self.td = TemporaryDirectory() self.to_clean_up = ['.dot', '.png', '.gfo'] # start the GF Repl self.gfRepl = GFRepl() self.out_count = 0 self.grammars = self.search_grammars() # content handlers self.handlers = { 'MMT_command': self.handle_mmt_command, 'GF_command': self.gfRepl.handle_gf_command, 'kernel_command': self.handle_kernel_command } # load help messages from messages.json file messages_path = os.path.dirname(os.path.realpath(__file__)) try: with open(os.path.join(messages_path, 'messages.json')) as f: self.messages = load(f) except: self.messages = None def do_shutdown(self): """Terminates the GF shell and the MMT subprocess""" self.td.cleanup() self.gfRepl.do_shutdown() self.mmtInterface.do_shutdown() # ---------------------------------------------------------------------------- # # General Content Handling # # ---------------------------------------------------------------------------- # def handle_input(self, code): """ Parses the `code` from the notebook and delegates command handling to the respective handlers `code`: str; the user input from the notebook """ messages = [] parse_dict = parse(code) if parse_dict['type']: if parse_dict['type'] == 'commands': for command in parse_dict['commands']: pipe_commands = command['pipe_commands'] pipe_res = [] for pipe_command in pipe_commands: pipe_command_type = pipe_command['type'] pipe_command_str = pipe_command['command'] if pipe_commands.index(pipe_command) == 0: res = self.handlers[pipe_command_type]( pipe_command_str) name = get_name(pipe_command_str) trees = [] try: # TODO make this produce a meaningful error message lines = res.split('\n') except: continue for line in lines: if line != '' and line != ' ' and line != '\n': if name == 'parse' or name == 'p': trees.append(line) pipe_res.append(line) else: # in case the output contains multiple lines new_pipe_res = [] for res in pipe_res: new_res = self.handlers[pipe_command_type]( '%s %s' % (pipe_command_str, res)) new_pipe_res.append(new_res) pipe_res = new_pipe_res messages.append(to_message_format(trees=trees)) for res in pipe_res: if type(res) is dict: messages.append(res) else: messages.append(to_message_format(message=res)) elif parse_dict['type'] == 'GFContent': messages.append( to_message_format( message=self.handle_grammar(code, parse_dict['name']))) elif parse_dict['type'] == 'MMTContent': messages.append( to_message_format( message=self.mmtInterface.create_mmt_file( code, parse_dict['name'], parse_dict['mmt_type']))) else: messages.append( to_message_format( message= "Input is neither valid GF or MMT content nor a valid shell command!" )) return messages # ---------------------------------------------------------------------------- # # Kernel Commands # # ---------------------------------------------------------------------------- # def handle_kernel_command(self, command): """ Handles the Kernel-Commands `show`, `clean, `export` and `help` 'command': str; the command """ name = get_name(command) args = get_args(command) if name == 'show': graph = ' '.join(args) return to_message_format(graph=graph) elif name == 'clean': return self.clean_up() elif name == 'export': return self.do_export(args[0]) elif name == 'help': if not self.messages: return "No help available" if args: name = args[0] if name in GF_commands: return self.gfRepl.handle_gf_command('h %s' % (name)) if name in self.messages.keys(): return self.messages[name] else: return "No help available on %s" % (name) else: return self.messages['help'] def convert_to_png(self, graph): """ Converts the given `graph` into a png Returns the file name of the picture `graph`: str """ out_dot = os.path.join(self.td.name, 'out%s.dot' % (self.out_count)) out_png = os.path.join(self.td.name, 'out%s.png' % (self.out_count)) with open(out_dot, 'w') as f: f.write(graph) DOT_ARGS = ['dot', '-Tpng', out_dot, '-o', out_png] p = Popen(DOT_ARGS, shell=False) p.communicate()[0] p.kill() self.out_count += 1 return out_png def clean_up(self): """Removes all files whose extensions are contained in `self.to_clean_up`""" removed = [] files = os.listdir('.') for file in files: _, file_extension = os.path.splitext(file) if file_extension in self.to_clean_up: removed.append(file) os.remove(file) if removed: s = map(lambda x: 'Removed: %s' % (x), removed) return "\n".join(s) else: return "No files removed" def do_export(self, file_name): """ Handles an export command Copies the specified Grammar to the current working directory `file_name`: str; the name of the file to export """ args = get_args(file_name) if len(args) > 1: return "export only takes one argument!" source_path = os.path.join(self.mmtInterface.content_path, self.mmtInterface.archive, 'source') files = os.listdir(source_path) file_reg = re.compile('^%s.gf$' % (file_name)) for file in files: if file_reg.match(file): from shutil import copy2 copy2(os.path.join(source_path, file), file) return 'Exported %s' % (file) return 'Could not find %s' % (file_name) # ---------------------------------------------------------------------------- # # MMT Commands # # ---------------------------------------------------------------------------- # def handle_mmt_command(self, command): """ Handles the MMT-Commands 'archive', 'construct' and 'subdir' 'command': str; the command """ name = get_name(command) args = get_args(command) if name == 'archive': if not args: # TODO make this into a sring so output order doesn't get screwed tree(dir=self.mmtInterface.get_archive_path(), archive_name=self.mmtInterface.get_archive()) return '' if len(args) > 1: return 'archive takes only one argument!' return self.mmtInterface.handle_archive(args[0]) if name == 'archives': return ', '.join(self.mmtInterface.get_archives()) elif name == 'construct': view = None if (args[0] == '-v'): view = args[1] ASTsStr = ' '.join(args[2:]) else: ASTsStr = ' '.join(args) h = ASTsStr.split('|') ASTs = list(map(str.strip, h)) return self.mmtInterface.construct(ASTs, view) elif name == 'subdir': if args and len(args) == 1: return self.mmtInterface.create_subdir(args[0]) elif not args: return os.path.relpath( self.mmtInterface.get_cwd(), os.path.join(self.mmtInterface.get_archive_path(), 'source')) # ---------------------------------------------------------------------------- # # GF Content # # ---------------------------------------------------------------------------- # def handle_grammar(self, content, name): """ Handles grammar input `content`: str; the content of the grammar `name`: str; the name of the grammar """ file_name = "%s.gf" % (name) file_path = os.path.join(self.mmtInterface.get_cwd(), file_name) try: with open(file_path, 'w') as f: f.write(content) f.close() except OSError: return 'Failed to create grammar %s' % (name) out = self.gfRepl.handle_gf_command("import %s" % (file_path)) if out == 'success' or out.startswith('Abstract changed'): build_result = self.mmtInterface.build_file( file_name) # build the Grammar with the GlfBuild extension if build_result['isSuccessful']: self.grammars[name] = file_path return "Defined %s" % (name) else: return '\n'.join(build_result['errors']) return out def search_grammars(self): grammars = {} cwd = self.mmtInterface.get_cwd() for file in os.listdir(cwd): if file.endswith(".gf"): path = os.path.join(cwd, file) name = os.path.splitext(file) grammars[name] = path return grammars def get_grammars(self): return self.grammars
class TestLinkOrCopy(object): def setUp(self): self.tempdir = TemporaryDirectory() self.src = self.dst("src") with open(self.src, "w") as f: f.write("Hello, world!") def tearDown(self): self.tempdir.cleanup() def dst(self, *args): return os.path.join(self.tempdir.name, *args) def assert_inode_not_equal(self, a, b): nt.assert_not_equals( os.stat(a).st_ino, os.stat(b).st_ino, "%r and %r do reference the same indoes" % (a, b)) def assert_inode_equal(self, a, b): nt.assert_equals( os.stat(a).st_ino, os.stat(b).st_ino, "%r and %r do not reference the same indoes" % (a, b)) def assert_content_equal(self, a, b): with open(a) as a_f: with open(b) as b_f: nt.assert_equals(a_f.read(), b_f.read()) @skip_win32 def test_link_successful(self): dst = self.dst("target") path.link_or_copy(self.src, dst) self.assert_inode_equal(self.src, dst) @skip_win32 def test_link_into_dir(self): dst = self.dst("some_dir") os.mkdir(dst) path.link_or_copy(self.src, dst) expected_dst = self.dst("some_dir", os.path.basename(self.src)) self.assert_inode_equal(self.src, expected_dst) @skip_win32 def test_target_exists(self): dst = self.dst("target") open(dst, "w").close() path.link_or_copy(self.src, dst) self.assert_inode_equal(self.src, dst) @skip_win32 def test_no_link(self): real_link = os.link try: del os.link dst = self.dst("target") path.link_or_copy(self.src, dst) self.assert_content_equal(self.src, dst) self.assert_inode_not_equal(self.src, dst) finally: os.link = real_link @skip_if_not_win32 def test_windows(self): dst = self.dst("target") path.link_or_copy(self.src, dst) self.assert_content_equal(self.src, dst)
class TestContentsManager(TestCase): def setUp(self): self._temp_dir = TemporaryDirectory() self.td = self._temp_dir.name self.contents_manager = FileContentsManager(root_dir=self.td, ) def tearDown(self): self._temp_dir.cleanup() def make_dir(self, api_path): """make a subdirectory at api_path override in subclasses if contents are not on the filesystem. """ _make_dir(self.contents_manager, api_path) def add_code_cell(self, nb): output = nbformat.new_output( "display_data", {'application/javascript': "alert('hi');"}) cell = nbformat.new_code_cell("print('hi')", outputs=[output]) nb.cells.append(cell) def new_notebook(self): cm = self.contents_manager model = cm.new_untitled(type='notebook') name = model['name'] path = model['path'] full_model = cm.get(path) nb = full_model['content'] nb['metadata']['counter'] = int(1e6 * time.time()) self.add_code_cell(nb) cm.save(full_model, path) return nb, name, path def test_new_untitled(self): cm = self.contents_manager # Test in root directory model = cm.new_untitled(type='notebook') assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertIn('type', model) self.assertEqual(model['type'], 'notebook') self.assertEqual(model['name'], 'Untitled.ipynb') self.assertEqual(model['path'], 'Untitled.ipynb') # Test in sub-directory model = cm.new_untitled(type='directory') assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertIn('type', model) self.assertEqual(model['type'], 'directory') self.assertEqual(model['name'], 'Untitled Folder') self.assertEqual(model['path'], 'Untitled Folder') sub_dir = model['path'] model = cm.new_untitled(path=sub_dir) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertIn('type', model) self.assertEqual(model['type'], 'file') self.assertEqual(model['name'], 'untitled') self.assertEqual(model['path'], '%s/untitled' % sub_dir) def test_modified_date(self): cm = self.contents_manager # Create a new notebook. nb, name, path = self.new_notebook() model = cm.get(path) # Add a cell and save. self.add_code_cell(model['content']) cm.save(model, path) # Reload notebook and verify that last_modified incremented. saved = cm.get(path) self.assertGreaterEqual(saved['last_modified'], model['last_modified']) # Move the notebook and verify that last_modified stayed the same. # (The frontend fires a warning if last_modified increases on the # renamed file.) new_path = 'renamed.ipynb' cm.rename(path, new_path) renamed = cm.get(new_path) self.assertGreaterEqual( renamed['last_modified'], saved['last_modified'], ) def test_get(self): cm = self.contents_manager # Create a notebook model = cm.new_untitled(type='notebook') name = model['name'] path = model['path'] # Check that we 'get' on the notebook we just created model2 = cm.get(path) assert isinstance(model2, dict) self.assertIn('name', model2) self.assertIn('path', model2) self.assertEqual(model['name'], name) self.assertEqual(model['path'], path) nb_as_file = cm.get(path, content=True, type='file') self.assertEqual(nb_as_file['path'], path) self.assertEqual(nb_as_file['type'], 'file') self.assertEqual(nb_as_file['format'], 'text') self.assertNotIsInstance(nb_as_file['content'], dict) nb_as_bin_file = cm.get(path, content=True, type='file', format='base64') self.assertEqual(nb_as_bin_file['format'], 'base64') # Test in sub-directory sub_dir = '/foo/' self.make_dir('foo') model = cm.new_untitled(path=sub_dir, ext='.ipynb') model2 = cm.get(sub_dir + name) assert isinstance(model2, dict) self.assertIn('name', model2) self.assertIn('path', model2) self.assertIn('content', model2) self.assertEqual(model2['name'], 'Untitled.ipynb') self.assertEqual(model2['path'], '{0}/{1}'.format(sub_dir.strip('/'), name)) # Test with a regular file. file_model_path = cm.new_untitled(path=sub_dir, ext='.txt')['path'] file_model = cm.get(file_model_path) self.assertDictContainsSubset( { 'content': u'', 'format': u'text', 'mimetype': u'text/plain', 'name': u'untitled.txt', 'path': u'foo/untitled.txt', 'type': u'file', 'writable': True, }, file_model, ) self.assertIn('created', file_model) self.assertIn('last_modified', file_model) # Test getting directory model # Create a sub-sub directory to test getting directory contents with a # subdir. self.make_dir('foo/bar') dirmodel = cm.get('foo') self.assertEqual(dirmodel['type'], 'directory') self.assertIsInstance(dirmodel['content'], list) self.assertEqual(len(dirmodel['content']), 3) self.assertEqual(dirmodel['path'], 'foo') self.assertEqual(dirmodel['name'], 'foo') # Directory contents should match the contents of each individual entry # when requested with content=False. model2_no_content = cm.get(sub_dir + name, content=False) file_model_no_content = cm.get(u'foo/untitled.txt', content=False) sub_sub_dir_no_content = cm.get('foo/bar', content=False) self.assertEqual(sub_sub_dir_no_content['path'], 'foo/bar') self.assertEqual(sub_sub_dir_no_content['name'], 'bar') for entry in dirmodel['content']: # Order isn't guaranteed by the spec, so this is a hacky way of # verifying that all entries are matched. if entry['path'] == sub_sub_dir_no_content['path']: self.assertEqual(entry, sub_sub_dir_no_content) elif entry['path'] == model2_no_content['path']: self.assertEqual(entry, model2_no_content) elif entry['path'] == file_model_no_content['path']: self.assertEqual(entry, file_model_no_content) else: self.fail("Unexpected directory entry: %s" % entry()) with self.assertRaises(HTTPError): cm.get('foo', type='file') def test_update(self): cm = self.contents_manager # Create a notebook model = cm.new_untitled(type='notebook') name = model['name'] path = model['path'] # Change the name in the model for rename model['path'] = 'test.ipynb' model = cm.update(model, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'test.ipynb') # Make sure the old name is gone self.assertRaises(HTTPError, cm.get, path) # Test in sub-directory # Create a directory and notebook in that directory sub_dir = '/foo/' self.make_dir('foo') model = cm.new_untitled(path=sub_dir, type='notebook') path = model['path'] # Change the name in the model for rename d = path.rsplit('/', 1)[0] new_path = model['path'] = d + '/test_in_sub.ipynb' model = cm.update(model, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'test_in_sub.ipynb') self.assertEqual(model['path'], new_path) # Make sure the old name is gone self.assertRaises(HTTPError, cm.get, path) def test_save(self): cm = self.contents_manager # Create a notebook model = cm.new_untitled(type='notebook') name = model['name'] path = model['path'] # Get the model with 'content' full_model = cm.get(path) # Save the notebook model = cm.save(full_model, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], name) self.assertEqual(model['path'], path) # Test in sub-directory # Create a directory and notebook in that directory sub_dir = '/foo/' self.make_dir('foo') model = cm.new_untitled(path=sub_dir, type='notebook') name = model['name'] path = model['path'] model = cm.get(path) # Change the name in the model for rename model = cm.save(model, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'Untitled.ipynb') self.assertEqual(model['path'], 'foo/Untitled.ipynb') def test_delete(self): cm = self.contents_manager # Create a notebook nb, name, path = self.new_notebook() # Delete the notebook cm.delete(path) # Check that deleting a non-existent path raises an error. self.assertRaises(HTTPError, cm.delete, path) # Check that a 'get' on the deleted notebook raises and error self.assertRaises(HTTPError, cm.get, path) def test_delete_root(self): cm = self.contents_manager with self.assertRaises(HTTPError) as err: cm.delete('') self.assertEqual(err.exception.status_code, 400) def test_copy(self): cm = self.contents_manager parent = u'å b' name = u'nb √.ipynb' path = u'{0}/{1}'.format(parent, name) self.make_dir(parent) orig = cm.new(path=path) # copy with unspecified name copy = cm.copy(path) self.assertEqual(copy['name'], orig['name'].replace('.ipynb', '-Copy1.ipynb')) # copy with specified name copy2 = cm.copy(path, u'å b/copy 2.ipynb') self.assertEqual(copy2['name'], u'copy 2.ipynb') self.assertEqual(copy2['path'], u'å b/copy 2.ipynb') # copy with specified path copy2 = cm.copy(path, u'/') self.assertEqual(copy2['name'], name) self.assertEqual(copy2['path'], name) def test_trust_notebook(self): cm = self.contents_manager nb, name, path = self.new_notebook() untrusted = cm.get(path)['content'] assert not cm.notary.check_cells(untrusted) # print(untrusted) cm.trust_notebook(path) trusted = cm.get(path)['content'] # print(trusted) assert cm.notary.check_cells(trusted) def test_mark_trusted_cells(self): cm = self.contents_manager nb, name, path = self.new_notebook() cm.mark_trusted_cells(nb, path) for cell in nb.cells: if cell.cell_type == 'code': assert not cell.metadata.trusted cm.trust_notebook(path) nb = cm.get(path)['content'] for cell in nb.cells: if cell.cell_type == 'code': assert cell.metadata.trusted def test_check_and_sign(self): cm = self.contents_manager nb, name, path = self.new_notebook() cm.mark_trusted_cells(nb, path) cm.check_and_sign(nb, path) assert not cm.notary.check_signature(nb) cm.trust_notebook(path) nb = cm.get(path)['content'] cm.mark_trusted_cells(nb, path) cm.check_and_sign(nb, path) assert cm.notary.check_signature(nb)
class TestContentsManager(TestCase): def setUp(self): self._temp_dir = TemporaryDirectory() self.td = self._temp_dir.name self.contents_manager = FileContentsManager(root_dir=self.td, ) def tearDown(self): self._temp_dir.cleanup() def make_dir(self, abs_path, rel_path): """make subdirectory, rel_path is the relative path to that directory from the location where the server started""" os_path = os.path.join(abs_path, rel_path) try: os.makedirs(os_path) except OSError: print("Directory already exists: %r" % os_path) return os_path def add_code_cell(self, nb): output = nbformat.new_output( "display_data", {'application/javascript': "alert('hi');"}) cell = nbformat.new_code_cell("print('hi')", outputs=[output]) nb.cells.append(cell) def new_notebook(self): cm = self.contents_manager model = cm.new_untitled(type='notebook') name = model['name'] path = model['path'] full_model = cm.get(path) nb = full_model['content'] self.add_code_cell(nb) cm.save(full_model, path) return nb, name, path def test_new_untitled(self): cm = self.contents_manager # Test in root directory model = cm.new_untitled(type='notebook') assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertIn('type', model) self.assertEqual(model['type'], 'notebook') self.assertEqual(model['name'], 'Untitled.ipynb') self.assertEqual(model['path'], 'Untitled.ipynb') # Test in sub-directory model = cm.new_untitled(type='directory') assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertIn('type', model) self.assertEqual(model['type'], 'directory') self.assertEqual(model['name'], 'Untitled Folder') self.assertEqual(model['path'], 'Untitled Folder') sub_dir = model['path'] model = cm.new_untitled(path=sub_dir) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertIn('type', model) self.assertEqual(model['type'], 'file') self.assertEqual(model['name'], 'untitled') self.assertEqual(model['path'], '%s/untitled' % sub_dir) def test_get(self): cm = self.contents_manager # Create a notebook model = cm.new_untitled(type='notebook') name = model['name'] path = model['path'] # Check that we 'get' on the notebook we just created model2 = cm.get(path) assert isinstance(model2, dict) self.assertIn('name', model2) self.assertIn('path', model2) self.assertEqual(model['name'], name) self.assertEqual(model['path'], path) nb_as_file = cm.get(path, content=True, type='file') self.assertEqual(nb_as_file['path'], path) self.assertEqual(nb_as_file['type'], 'file') self.assertEqual(nb_as_file['format'], 'text') self.assertNotIsInstance(nb_as_file['content'], dict) nb_as_bin_file = cm.get(path, content=True, type='file', format='base64') self.assertEqual(nb_as_bin_file['format'], 'base64') # Test in sub-directory sub_dir = '/foo/' self.make_dir(cm.root_dir, 'foo') model = cm.new_untitled(path=sub_dir, ext='.ipynb') model2 = cm.get(sub_dir + name) assert isinstance(model2, dict) self.assertIn('name', model2) self.assertIn('path', model2) self.assertIn('content', model2) self.assertEqual(model2['name'], 'Untitled.ipynb') self.assertEqual(model2['path'], '{0}/{1}'.format(sub_dir.strip('/'), name)) # Test getting directory model dirmodel = cm.get('foo') self.assertEqual(dirmodel['type'], 'directory') with self.assertRaises(HTTPError): cm.get('foo', type='file') @dec.skip_win32 def test_bad_symlink(self): cm = self.contents_manager path = 'test bad symlink' os_path = self.make_dir(cm.root_dir, path) file_model = cm.new_untitled(path=path, ext='.txt') # create a broken symlink os.symlink("target", os.path.join(os_path, "bad symlink")) model = cm.get(path) self.assertEqual(model['content'], [file_model]) @dec.skip_win32 def test_good_symlink(self): cm = self.contents_manager parent = 'test good symlink' name = 'good symlink' path = '{0}/{1}'.format(parent, name) os_path = self.make_dir(cm.root_dir, parent) file_model = cm.new(path=parent + '/zfoo.txt') # create a good symlink os.symlink(file_model['name'], os.path.join(os_path, name)) symlink_model = cm.get(path, content=False) dir_model = cm.get(parent) self.assertEqual( sorted(dir_model['content'], key=lambda x: x['name']), [symlink_model, file_model], ) def test_update(self): cm = self.contents_manager # Create a notebook model = cm.new_untitled(type='notebook') name = model['name'] path = model['path'] # Change the name in the model for rename model['path'] = 'test.ipynb' model = cm.update(model, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'test.ipynb') # Make sure the old name is gone self.assertRaises(HTTPError, cm.get, path) # Test in sub-directory # Create a directory and notebook in that directory sub_dir = '/foo/' self.make_dir(cm.root_dir, 'foo') model = cm.new_untitled(path=sub_dir, type='notebook') name = model['name'] path = model['path'] # Change the name in the model for rename d = path.rsplit('/', 1)[0] new_path = model['path'] = d + '/test_in_sub.ipynb' model = cm.update(model, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'test_in_sub.ipynb') self.assertEqual(model['path'], new_path) # Make sure the old name is gone self.assertRaises(HTTPError, cm.get, path) def test_save(self): cm = self.contents_manager # Create a notebook model = cm.new_untitled(type='notebook') name = model['name'] path = model['path'] # Get the model with 'content' full_model = cm.get(path) # Save the notebook model = cm.save(full_model, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], name) self.assertEqual(model['path'], path) # Test in sub-directory # Create a directory and notebook in that directory sub_dir = '/foo/' self.make_dir(cm.root_dir, 'foo') model = cm.new_untitled(path=sub_dir, type='notebook') name = model['name'] path = model['path'] model = cm.get(path) # Change the name in the model for rename model = cm.save(model, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'Untitled.ipynb') self.assertEqual(model['path'], 'foo/Untitled.ipynb') def test_delete(self): cm = self.contents_manager # Create a notebook nb, name, path = self.new_notebook() # Delete the notebook cm.delete(path) # Check that a 'get' on the deleted notebook raises and error self.assertRaises(HTTPError, cm.get, path) def test_copy(self): cm = self.contents_manager parent = u'å b' name = u'nb √.ipynb' path = u'{0}/{1}'.format(parent, name) os.mkdir(os.path.join(cm.root_dir, parent)) orig = cm.new(path=path) # copy with unspecified name copy = cm.copy(path) self.assertEqual(copy['name'], orig['name'].replace('.ipynb', '-Copy1.ipynb')) # copy with specified name copy2 = cm.copy(path, u'å b/copy 2.ipynb') self.assertEqual(copy2['name'], u'copy 2.ipynb') self.assertEqual(copy2['path'], u'å b/copy 2.ipynb') # copy with specified path copy2 = cm.copy(path, u'/') self.assertEqual(copy2['name'], name) self.assertEqual(copy2['path'], name) def test_trust_notebook(self): cm = self.contents_manager nb, name, path = self.new_notebook() untrusted = cm.get(path)['content'] assert not cm.notary.check_cells(untrusted) # print(untrusted) cm.trust_notebook(path) trusted = cm.get(path)['content'] # print(trusted) assert cm.notary.check_cells(trusted) def test_mark_trusted_cells(self): cm = self.contents_manager nb, name, path = self.new_notebook() cm.mark_trusted_cells(nb, path) for cell in nb.cells: if cell.cell_type == 'code': assert not cell.metadata.trusted cm.trust_notebook(path) nb = cm.get(path)['content'] for cell in nb.cells: if cell.cell_type == 'code': assert cell.metadata.trusted def test_check_and_sign(self): cm = self.contents_manager nb, name, path = self.new_notebook() cm.mark_trusted_cells(nb, path) cm.check_and_sign(nb, path) assert not cm.notary.check_signature(nb) cm.trust_notebook(path) nb = cm.get(path)['content'] cm.mark_trusted_cells(nb, path) cm.check_and_sign(nb, path) assert cm.notary.check_signature(nb)
class TestMagicRunWithPackage(unittest.TestCase): def writefile(self, name, content): path = os.path.join(self.tempdir.name, name) d = os.path.dirname(path) if not os.path.isdir(d): os.makedirs(d) with open(path, 'w') as f: f.write(textwrap.dedent(content)) def setUp(self): self.package = package = 'tmp{0}'.format(repr(random.random())[2:]) """Temporary valid python package name.""" self.value = int(random.random() * 10000) self.tempdir = TemporaryDirectory() self.__orig_cwd = py3compat.getcwd() sys.path.insert(0, self.tempdir.name) self.writefile(os.path.join(package, '__init__.py'), '') self.writefile(os.path.join(package, 'sub.py'), """ x = {0!r} """.format(self.value)) self.writefile(os.path.join(package, 'relative.py'), """ from .sub import x """) self.writefile( os.path.join(package, 'absolute.py'), """ from {0}.sub import x """.format(package)) def tearDown(self): os.chdir(self.__orig_cwd) sys.path[:] = [p for p in sys.path if p != self.tempdir.name] self.tempdir.cleanup() def check_run_submodule(self, submodule, opts=''): _ip.user_ns.pop('x', None) _ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts)) self.assertEqual( _ip.user_ns['x'], self.value, 'Variable `x` is not loaded from module `{0}`.'.format(submodule)) def test_run_submodule_with_absolute_import(self): self.check_run_submodule('absolute') def test_run_submodule_with_relative_import(self): """Run submodule that has a relative import statement (#2727).""" self.check_run_submodule('relative') def test_prun_submodule_with_absolute_import(self): self.check_run_submodule('absolute', '-p') def test_prun_submodule_with_relative_import(self): self.check_run_submodule('relative', '-p') def with_fake_debugger(func): @functools.wraps(func) def wrapper(*args, **kwds): with tt.monkeypatch(debugger.Pdb, 'run', staticmethod(eval)): return func(*args, **kwds) return wrapper @with_fake_debugger def test_debug_run_submodule_with_absolute_import(self): self.check_run_submodule('absolute', '-d') @with_fake_debugger def test_debug_run_submodule_with_relative_import(self): self.check_run_submodule('relative', '-d')
class TestContentsManager(TestCase): def setUp(self): self._temp_dir = TemporaryDirectory() self.td = self._temp_dir.name self.contents_manager = FileContentsManager( root_dir=self.td, ) def tearDown(self): self._temp_dir.cleanup() def make_dir(self, api_path): """make a subdirectory at api_path override in subclasses if contents are not on the filesystem. """ _make_dir(self.contents_manager, api_path) def add_code_cell(self, nb): output = nbformat.new_output("display_data", {'application/javascript': "alert('hi');"}) cell = nbformat.new_code_cell("print('hi')", outputs=[output]) nb.cells.append(cell) def new_notebook(self): cm = self.contents_manager model = cm.new_untitled(type='notebook') name = model['name'] path = model['path'] full_model = cm.get(path) nb = full_model['content'] nb['metadata']['counter'] = int(1e6 * time.time()) self.add_code_cell(nb) cm.save(full_model, path) return nb, name, path def test_new_untitled(self): cm = self.contents_manager # Test in root directory model = cm.new_untitled(type='notebook') assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertIn('type', model) self.assertEqual(model['type'], 'notebook') self.assertEqual(model['name'], 'Untitled.ipynb') self.assertEqual(model['path'], 'Untitled.ipynb') # Test in sub-directory model = cm.new_untitled(type='directory') assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertIn('type', model) self.assertEqual(model['type'], 'directory') self.assertEqual(model['name'], 'Untitled Folder') self.assertEqual(model['path'], 'Untitled Folder') sub_dir = model['path'] model = cm.new_untitled(path=sub_dir) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertIn('type', model) self.assertEqual(model['type'], 'file') self.assertEqual(model['name'], 'untitled') self.assertEqual(model['path'], '%s/untitled' % sub_dir) def test_get(self): cm = self.contents_manager # Create a notebook model = cm.new_untitled(type='notebook') name = model['name'] path = model['path'] # Check that we 'get' on the notebook we just created model2 = cm.get(path) assert isinstance(model2, dict) self.assertIn('name', model2) self.assertIn('path', model2) self.assertEqual(model['name'], name) self.assertEqual(model['path'], path) nb_as_file = cm.get(path, content=True, type='file') self.assertEqual(nb_as_file['path'], path) self.assertEqual(nb_as_file['type'], 'file') self.assertEqual(nb_as_file['format'], 'text') self.assertNotIsInstance(nb_as_file['content'], dict) nb_as_bin_file = cm.get(path, content=True, type='file', format='base64') self.assertEqual(nb_as_bin_file['format'], 'base64') # Test in sub-directory sub_dir = '/foo/' self.make_dir('foo') model = cm.new_untitled(path=sub_dir, ext='.ipynb') model2 = cm.get(sub_dir + name) assert isinstance(model2, dict) self.assertIn('name', model2) self.assertIn('path', model2) self.assertIn('content', model2) self.assertEqual(model2['name'], 'Untitled.ipynb') self.assertEqual(model2['path'], '{0}/{1}'.format(sub_dir.strip('/'), name)) # Test with a regular file. file_model_path = cm.new_untitled(path=sub_dir, ext='.txt')['path'] file_model = cm.get(file_model_path) self.assertDictContainsSubset( { 'content': u'', 'format': u'text', 'mimetype': u'text/plain', 'name': u'untitled.txt', 'path': u'foo/untitled.txt', 'type': u'file', 'writable': True, }, file_model, ) self.assertIn('created', file_model) self.assertIn('last_modified', file_model) # Test getting directory model # Create a sub-sub directory to test getting directory contents with a # subdir. self.make_dir('foo/bar') dirmodel = cm.get('foo') self.assertEqual(dirmodel['type'], 'directory') self.assertIsInstance(dirmodel['content'], list) self.assertEqual(len(dirmodel['content']), 3) self.assertEqual(dirmodel['path'], 'foo') self.assertEqual(dirmodel['name'], 'foo') # Directory contents should match the contents of each individual entry # when requested with content=False. model2_no_content = cm.get(sub_dir + name, content=False) file_model_no_content = cm.get(u'foo/untitled.txt', content=False) sub_sub_dir_no_content = cm.get('foo/bar', content=False) self.assertEqual(sub_sub_dir_no_content['path'], 'foo/bar') self.assertEqual(sub_sub_dir_no_content['name'], 'bar') for entry in dirmodel['content']: # Order isn't guaranteed by the spec, so this is a hacky way of # verifying that all entries are matched. if entry['path'] == sub_sub_dir_no_content['path']: self.assertEqual(entry, sub_sub_dir_no_content) elif entry['path'] == model2_no_content['path']: self.assertEqual(entry, model2_no_content) elif entry['path'] == file_model_no_content['path']: self.assertEqual(entry, file_model_no_content) else: self.fail("Unexpected directory entry: %s" % entry()) with self.assertRaises(HTTPError): cm.get('foo', type='file') def test_update(self): cm = self.contents_manager # Create a notebook model = cm.new_untitled(type='notebook') name = model['name'] path = model['path'] # Change the name in the model for rename model['path'] = 'test.ipynb' model = cm.update(model, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'test.ipynb') # Make sure the old name is gone self.assertRaises(HTTPError, cm.get, path) # Test in sub-directory # Create a directory and notebook in that directory sub_dir = '/foo/' self.make_dir('foo') model = cm.new_untitled(path=sub_dir, type='notebook') path = model['path'] # Change the name in the model for rename d = path.rsplit('/', 1)[0] new_path = model['path'] = d + '/test_in_sub.ipynb' model = cm.update(model, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'test_in_sub.ipynb') self.assertEqual(model['path'], new_path) # Make sure the old name is gone self.assertRaises(HTTPError, cm.get, path) def test_save(self): cm = self.contents_manager # Create a notebook model = cm.new_untitled(type='notebook') name = model['name'] path = model['path'] # Get the model with 'content' full_model = cm.get(path) # Save the notebook model = cm.save(full_model, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], name) self.assertEqual(model['path'], path) # Test in sub-directory # Create a directory and notebook in that directory sub_dir = '/foo/' self.make_dir('foo') model = cm.new_untitled(path=sub_dir, type='notebook') name = model['name'] path = model['path'] model = cm.get(path) # Change the name in the model for rename model = cm.save(model, path) assert isinstance(model, dict) self.assertIn('name', model) self.assertIn('path', model) self.assertEqual(model['name'], 'Untitled.ipynb') self.assertEqual(model['path'], 'foo/Untitled.ipynb') def test_delete(self): cm = self.contents_manager # Create a notebook nb, name, path = self.new_notebook() # Delete the notebook cm.delete(path) # Check that deleting a non-existent path raises an error. self.assertRaises(HTTPError, cm.delete, path) # Check that a 'get' on the deleted notebook raises and error self.assertRaises(HTTPError, cm.get, path) def test_copy(self): cm = self.contents_manager parent = u'å b' name = u'nb √.ipynb' path = u'{0}/{1}'.format(parent, name) self.make_dir(parent) orig = cm.new(path=path) # copy with unspecified name copy = cm.copy(path) self.assertEqual(copy['name'], orig['name'].replace('.ipynb', '-Copy1.ipynb')) # copy with specified name copy2 = cm.copy(path, u'å b/copy 2.ipynb') self.assertEqual(copy2['name'], u'copy 2.ipynb') self.assertEqual(copy2['path'], u'å b/copy 2.ipynb') # copy with specified path copy2 = cm.copy(path, u'/') self.assertEqual(copy2['name'], name) self.assertEqual(copy2['path'], name) def test_trust_notebook(self): cm = self.contents_manager nb, name, path = self.new_notebook() untrusted = cm.get(path)['content'] assert not cm.notary.check_cells(untrusted) # print(untrusted) cm.trust_notebook(path) trusted = cm.get(path)['content'] # print(trusted) assert cm.notary.check_cells(trusted) def test_mark_trusted_cells(self): cm = self.contents_manager nb, name, path = self.new_notebook() cm.mark_trusted_cells(nb, path) for cell in nb.cells: if cell.cell_type == 'code': assert not cell.metadata.trusted cm.trust_notebook(path) nb = cm.get(path)['content'] for cell in nb.cells: if cell.cell_type == 'code': assert cell.metadata.trusted def test_check_and_sign(self): cm = self.contents_manager nb, name, path = self.new_notebook() cm.mark_trusted_cells(nb, path) cm.check_and_sign(nb, path) assert not cm.notary.check_signature(nb) cm.trust_notebook(path) nb = cm.get(path)['content'] cm.mark_trusted_cells(nb, path) cm.check_and_sign(nb, path) assert cm.notary.check_signature(nb)