def list_profile_dirs(self): profiles = list_bundled_profiles() if profiles: print() print("Available profiles in IPython:") self._print_profiles(profiles) print() print(" The first request for a bundled profile will copy it") print(" into your IPython directory (%s)," % self.ipython_dir) print(" where you can customize it.") profiles = list_profiles_in(self.ipython_dir) if profiles: print() print("Available profiles in %s:" % self.ipython_dir) self._print_profiles(profiles) profiles = list_profiles_in(py3compat.getcwd()) if profiles: print() print("Available profiles in current directory (%s):" % py3compat.getcwd()) self._print_profiles(profiles) print() print("To use any of the above profiles, start IPython with:") print(" ipython --profile=<name>") print()
def test_render_unicode_cwd(self): save = py3compat.getcwd() with TemporaryDirectory(u'ünicødé') as td: os.chdir(td) self.pm.in_template = r'\w [\#]' p = self.pm.render('in', color=False) self.assertEqual(p, u"%s [%i]" % (py3compat.getcwd(), ip.execution_count)) os.chdir(save)
def __init__(self, **kwargs): super(BaseIPythonApplication, self).__init__(**kwargs) # ensure current working directory exists try: py3compat.getcwd() except: # exit if cwd doesn't exist self.log.error("Current working directory doesn't exist.") self.exit(1)
def __call__(self, etype, evalue, etb): """Handle an exception, call for compatible with sys.excepthook""" # do not allow the crash handler to be called twice without reinstalling it # this prevents unlikely errors in the crash handling from entering an # infinite loop. sys.excepthook = sys.__excepthook__ # Report tracebacks shouldn't use color in general (safer for users) color_scheme = 'NoColor' # Use this ONLY for developer debugging (keep commented out for release) #color_scheme = 'Linux' # dbg try: rptdir = self.app.ipython_dir except: rptdir = getcwd() if rptdir is None or not os.path.isdir(rptdir): rptdir = getcwd() report_name = os.path.join(rptdir, self.crash_report_fname) # write the report filename into the instance dict so it can get # properly expanded out in the user message template self.crash_report_fname = report_name self.info['crash_report_fname'] = report_name TBhandler = ultratb.VerboseTB( color_scheme=color_scheme, long_header=1, call_pdb=self.call_pdb, ) if self.call_pdb: TBhandler(etype, evalue, etb) return else: traceback = TBhandler.text(etype, evalue, etb, context=31) # print traceback to screen if self.show_crash_traceback: print(traceback, file=sys.stderr) # and generate a complete report on disk try: report = open(report_name, 'w') except: print('Could not create crash report on disk.', file=sys.stderr) return # Inform user on stderr of what happened print('\n' + '*' * 70 + '\n', file=sys.stderr) print(self.message_template.format(**self.info), file=sys.stderr) # Construct report on disk report.write(self.make_report(traceback)) report.close() input("Hit <Enter> to quit (your terminal may close):")
def __call__(self, etype, evalue, etb): """Handle an exception, call for compatible with sys.excepthook""" # do not allow the crash handler to be called twice without reinstalling it # this prevents unlikely errors in the crash handling from entering an # infinite loop. sys.excepthook = sys.__excepthook__ # Report tracebacks shouldn't use color in general (safer for users) color_scheme = 'NoColor' # Use this ONLY for developer debugging (keep commented out for release) #color_scheme = 'Linux' # dbg try: rptdir = self.app.ipython_dir except: rptdir = getcwd() if rptdir is None or not os.path.isdir(rptdir): rptdir = getcwd() report_name = os.path.join(rptdir,self.crash_report_fname) # write the report filename into the instance dict so it can get # properly expanded out in the user message template self.crash_report_fname = report_name self.info['crash_report_fname'] = report_name TBhandler = ultratb.VerboseTB( color_scheme=color_scheme, long_header=1, call_pdb=self.call_pdb, ) if self.call_pdb: TBhandler(etype,evalue,etb) return else: traceback = TBhandler.text(etype,evalue,etb,context=31) # print traceback to screen if self.show_crash_traceback: print(traceback, file=sys.stderr) # and generate a complete report on disk try: report = open(report_name,'w') except: print('Could not create crash report on disk.', file=sys.stderr) return # Inform user on stderr of what happened print('\n'+'*'*70+'\n', file=sys.stderr) print(self.message_template.format(**self.info), file=sys.stderr) # Construct report on disk report.write(self.make_report(traceback)) report.close() input("Hit <Enter> to quit (your terminal may close):")
def find_profile_dir_by_name(cls, ipython_dir, name=u'default', config=None): """Find an existing profile dir by profile name, return its ProfileDir. This searches through a sequence of paths for a profile dir. If it is not found, a :class:`ProfileDirError` exception will be raised. The search path algorithm is: 1. ``py3compat.getcwd()`` 2. ``ipython_dir`` Parameters ---------- ipython_dir : unicode or str The IPython directory to use. name : unicode or str The name of the profile. The name of the profile directory will be "profile_<profile>". """ dirname = u'profile_' + name paths = [py3compat.getcwd(), ipython_dir] for p in paths: profile_dir = os.path.join(p, dirname) if os.path.isdir(profile_dir): return cls(location=profile_dir, config=config) else: raise ProfileDirError('Profile directory not found in paths: %s' % dirname)
def in_tempdir(cls): save = py3compat.getcwd() try: os.chdir(cls.tempdir.name) yield finally: os.chdir(save)
def find_profile_dir_by_name(cls, ipython_dir, name=u'default', config=None): """Find an existing profile dir by profile name, return its ProfileDir. This searches through a sequence of paths for a profile dir. If it is not found, a :class:`ProfileDirError` exception will be raised. The search path algorithm is: 1. ``py3compat.getcwd()`` 2. ``ipython_dir`` Parameters ---------- ipython_dir : unicode or str The IPython directory to use. name : unicode or str The name of the profile. The name of the profile directory will be "profile_<profile>". """ dirname = u'profile_' + name paths = [py3compat.getcwd(), ipython_dir] for p in paths: profile_dir = os.path.join(p, dirname) if os.path.isdir(profile_dir): return cls(location=profile_dir, config=config) else: raise ProfileDirError( 'Profile directory not found in paths: %s' % dirname)
def bookmark(self, parameter_s=''): """Manage IPython's bookmark system. %bookmark <name> - set bookmark to current dir %bookmark <name> <dir> - set bookmark to <dir> %bookmark -l - list all bookmarks %bookmark -d <name> - remove bookmark %bookmark -r - remove all bookmarks You can later on access a bookmarked folder with:: %cd -b <name> or simply '%cd <name>' if there is no directory called <name> AND there is such a bookmark defined. Your bookmarks persist through IPython sessions, but they are associated with each profile.""" opts, args = self.parse_options(parameter_s, 'drl', mode='list') if len(args) > 2: raise UsageError("%bookmark: too many arguments") bkms = self.shell.db.get('bookmarks', {}) if 'd' in opts: try: todel = args[0] except IndexError: raise UsageError( "%bookmark -d: must provide a bookmark to delete") else: try: del bkms[todel] except KeyError: raise UsageError( "%%bookmark -d: Can't delete bookmark '%s'" % todel) elif 'r' in opts: bkms = {} elif 'l' in opts: bks = bkms.keys() bks.sort() if bks: size = max(map(len, bks)) else: size = 0 fmt = '%-' + str(size) + 's -> %s' print('Current bookmarks:') for bk in bks: print(fmt % (bk, bkms[bk])) else: if not args: raise UsageError( "%bookmark: You must specify the bookmark name") elif len(args) == 1: bkms[args[0]] = py3compat.getcwd() elif len(args) == 2: bkms[args[0]] = args[1] self.shell.db['bookmarks'] = bkms
def to_work_dir(self): wd = self.work_dir if unicode_type(wd) != py3compat.getcwd(): os.chdir(wd) self.log.info("Changing to working dir: %s" % wd) # This is the working dir by now. sys.path.insert(0, '')
def runTest(self): test = self._dt_test runner = self._dt_runner old = sys.stdout new = StringIO() optionflags = self._dt_optionflags if not (optionflags & REPORTING_FLAGS): # The option flags don't include any reporting flags, # so add the default reporting flags optionflags |= _unittest_reportflags try: # Save our current directory and switch out to the one where the # test was originally created, in case another doctest did a # directory change. We'll restore this in the finally clause. curdir = getcwd() #print 'runTest in dir:', self._ori_dir # dbg os.chdir(self._ori_dir) runner.DIVIDER = "-"*70 failures, tries = runner.run(test,out=new.write, clear_globs=False) finally: sys.stdout = old os.chdir(curdir) if failures: raise self.failureException(self.format_failure(new.getvalue()))
def setUp(self): self.BASETESTDIR = tempfile.mkdtemp() for fil in [u"aaø.py", u"a.py", u"b.py"]: with open(join(self.BASETESTDIR, fil), "w") as sfile: sfile.write("pass\n") self.oldpath = py3compat.getcwd() os.chdir(self.BASETESTDIR)
def _git_dir_default(self): try: return self.parent.parent.notebook_dir except AttributeError: try: return self.parent.root_dir except AttributeError: return getcwd()
def setUp(self): self.BASETESTDIR = tempfile.mkdtemp() self.TESTDIR = join(self.BASETESTDIR, u"åäö") os.mkdir(self.TESTDIR) with open(join(self.TESTDIR, u"åäötestscript.py"), "w") as sfile: sfile.write("pass\n") self.oldpath = py3compat.getcwd() os.chdir(self.TESTDIR) self.fname = u"åäötestscript.py"
def cwd_filt(depth): """Return the last depth elements of the current working directory. $HOME is always replaced with '~'. If depth==0, the full path is returned.""" cwd = py3compat.getcwd().replace(HOME,"~") out = os.sep.join(cwd.split(os.sep)[-depth:]) return out or os.sep
def test_cwd_x(self): self.pm.in_template = r"\X0" save = py3compat.getcwd() os.chdir(os.path.expanduser("~")) p = self.pm.render("in", color=False) try: self.assertEqual(p, "~") finally: os.chdir(save)
def test_cwd_x(self): self.pm.in_template = r"\X0" save = py3compat.getcwd() os.chdir(os.path.expanduser('~')) p = self.pm.render('in', color=False) try: self.assertEqual(p, '~') finally: os.chdir(save)
def cwd_filt(depth): """Return the last depth elements of the current working directory. $HOME is always replaced with '~'. If depth==0, the full path is returned.""" cwd = py3compat.getcwd().replace(HOME, "~") out = os.sep.join(cwd.split(os.sep)[-depth:]) return out or os.sep
def setUp(self): self.BASETESTDIR = tempfile.mkdtemp() for fil in self.files: with open(join(self.BASETESTDIR, fil), "w") as sfile: sfile.write("pass\n") for d in self.dirs: os.mkdir(join(self.BASETESTDIR, d)) self.oldpath = py3compat.getcwd() os.chdir(self.BASETESTDIR)
def pwd(self, parameter_s=""): """Return the current working directory path. Examples -------- :: In [9]: pwd Out[9]: '/home/tsuser/sprint/ipython' """ return py3compat.getcwd()
def pwd(self, parameter_s=''): """Return the current working directory path. Examples -------- :: In [9]: pwd Out[9]: '/home/tsuser/sprint/ipython' """ return py3compat.getcwd()
def filefind(filename, path_dirs=None): """Find a file by looking through a sequence of paths. This iterates through a sequence of paths looking for a file and returns the full, absolute path of the first occurence of the file. If no set of path dirs is given, the filename is tested as is, after running through :func:`expandvars` and :func:`expanduser`. Thus a simple call:: filefind('myfile.txt') will find the file in the current working dir, but:: filefind('~/myfile.txt') Will find the file in the users home directory. This function does not automatically try any paths, such as the cwd or the user's home directory. Parameters ---------- filename : str The filename to look for. path_dirs : str, None or sequence of str The sequence of paths to look for the file in. If None, the filename need to be absolute or be in the cwd. If a string, the string is put into a sequence and the searched. If a sequence, walk through each element and join with ``filename``, calling :func:`expandvars` and :func:`expanduser` before testing for existence. Returns ------- Raises :exc:`IOError` or returns absolute path to file. """ # If paths are quoted, abspath gets confused, strip them... filename = filename.strip('"').strip("'") # If the input is an absolute path, just check it exists if os.path.isabs(filename) and os.path.isfile(filename): return filename if path_dirs is None: path_dirs = ("",) elif isinstance(path_dirs, py3compat.string_types): path_dirs = (path_dirs,) for path in path_dirs: if path == '.': path = py3compat.getcwd() testname = expand_path(os.path.join(path, filename)) if os.path.isfile(testname): return os.path.abspath(testname) raise IOError("File %r does not exist in any of the search paths: %r" % (filename, path_dirs) )
def reset(self, new_session=True): """Clear the session history, releasing all object references, and optionally open a new session.""" self.output_hist.clear() # The directory history can't be completely empty self.dir_hist[:] = [py3compat.getcwd()] if new_session: if self.session_number: self.end_session() self.input_hist_parsed[:] = [""] self.input_hist_raw[:] = [""] self.new_session()
def update_profiles(self): """List all profiles in the ipython_dir and cwd. """ for path in [get_ipython_dir(), py3compat.getcwd()]: for profile in list_profiles_in(path): pd = self.get_profile_dir(profile, path) if profile not in self.profiles: self.log.debug("Adding cluster profile '%s'" % profile) self.profiles[profile] = { 'profile': profile, 'profile_dir': pd, 'status': 'stopped' }
def __call__(self, parameter_s=''): """ verbatim from core.magic.osm.pushd, except it calls mycd instead. without this patch, function is noisy because it is using the ipython cd function and "-q" is not appended to parameter_s """ dir_s = self.shell.dir_stack tgt = os.path.expanduser(unquote_filename(parameter_s)) cwd = py3compat.getcwd().replace( self.shell.home_dir, '~') if tgt: self.mycd(parameter_s) dir_s.insert(0, cwd) return self.shell.magic('dirs')
def pushd(self, parameter_s=''): """Place the current dir on stack and change directory. Usage:\\ %pushd ['dirname'] """ dir_s = self.shell.dir_stack tgt = os.path.expanduser(parameter_s) cwd = py3compat.getcwd().replace(self.shell.home_dir, '~') if tgt: self.cd(parameter_s) dir_s.insert(0, cwd) return self.shell.magic('dirs')
def pushd(self, parameter_s=""): """Place the current dir on stack and change directory. Usage:\\ %pushd ['dirname'] """ dir_s = self.shell.dir_stack tgt = os.path.expanduser(unquote_filename(parameter_s)) cwd = py3compat.getcwd().replace(self.shell.home_dir, "~") if tgt: self.cd(parameter_s) dir_s.insert(0, cwd) return self.shell.magic("dirs")
def test_unicode_cwd(): """Check that IPython starts with non-ascii characters in the path.""" wd = tempfile.mkdtemp(suffix=u"€") old_wd = py3compat.getcwd() os.chdir(wd) #raise Exception(repr(py3compat.getcwd())) try: app = BaseIPythonApplication() # The lines below are copied from Application.initialize() app.init_profile_dir() app.init_config_files() app.load_config_file(suppress_errors=False) finally: os.chdir(old_wd)
def cwd_filt2(depth): """Return the last depth elements of the current working directory. $HOME is always replaced with '~'. If depth==0, the full path is returned.""" full_cwd = py3compat.getcwd() cwd = full_cwd.replace(HOME,"~").split(os.sep) if '~' in cwd and len(cwd) == depth+1: depth += 1 drivepart = '' if sys.platform == 'win32' and len(cwd) > depth: drivepart = os.path.splitdrive(full_cwd)[0] out = drivepart + '/'.join(cwd[-depth:]) return out or os.sep
def cwd_filt2(depth): """Return the last depth elements of the current working directory. $HOME is always replaced with '~'. If depth==0, the full path is returned.""" full_cwd = py3compat.getcwd() cwd = full_cwd.replace(HOME, "~").split(os.sep) if '~' in cwd and len(cwd) == depth + 1: depth += 1 drivepart = '' if sys.platform == 'win32' and len(cwd) > depth: drivepart = os.path.splitdrive(full_cwd)[0] out = drivepart + '/'.join(cwd[-depth:]) return out or os.sep
def reset(self, new_session=True): """Clear the session history, releasing all object references, and optionally open a new session.""" self.output_hist.clear() # The directory history can't be completely empty try: self.dir_hist[:] = [py3compat.getcwd()] except OSError: pass # happens when cwd is removed out from under the shell if new_session: if self.session_number: self.end_session() self.input_hist_parsed[:] = [""] self.input_hist_raw[:] = [""] self.new_session()
def test_dirops(): """Test various directory handling operations.""" # curpath = lambda :os.path.splitdrive(py3compat.getcwd())[1].replace('\\','/') curpath = py3compat.getcwd startdir = py3compat.getcwd() ipdir = os.path.realpath(_ip.ipython_dir) try: _ip.magic('cd "%s"' % ipdir) nt.assert_equal(curpath(), ipdir) _ip.magic('cd -') nt.assert_equal(curpath(), startdir) _ip.magic('pushd "%s"' % ipdir) nt.assert_equal(curpath(), ipdir) _ip.magic('popd') nt.assert_equal(curpath(), startdir) finally: os.chdir(startdir)
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 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 = 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 update_profiles(self): """List all profiles in the ipython_dir and cwd. """ stale = set(self.profiles) for path in [get_ipython_dir(), py3compat.getcwd()]: for profile in list_profiles_in(path): if profile in stale: stale.remove(profile) pd = self.get_profile_dir(profile, path) if profile not in self.profiles: self.log.debug("Adding cluster profile '%s'", profile) self.profiles[profile] = { 'profile': profile, 'profile_dir': pd, 'status': 'stopped' } for profile in stale: # remove profiles that no longer exist self.log.debug("Profile '%s' no longer exists", profile) self.profiles.pop(stale)
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 = 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 test_local_file_completions(): ip = get_ipython() cwd = py3compat.getcwd() try: with TemporaryDirectory() as tmpdir: os.chdir(tmpdir) prefix = './foo' suffixes = ['1', '2'] names = [prefix + s for s in suffixes] for n in names: open(n, 'w').close() # Check simple completion c = ip.complete(prefix)[1] nt.assert_equal(c, names) # Now check with a function call cmd = 'a = f("%s' % prefix c = ip.complete(prefix, cmd)[1] comp = [prefix + s for s in suffixes] nt.assert_equal(c, comp) finally: # prevent failures from making chdir stick os.chdir(cwd)
def test_local_file_completions(): ip = get_ipython() cwd = py3compat.getcwd() try: with TemporaryDirectory() as tmpdir: os.chdir(tmpdir) prefix = './foo' suffixes = ['1', '2'] names = [prefix+s for s in suffixes] for n in names: open(n, 'w').close() # Check simple completion c = ip.complete(prefix)[1] nt.assert_equal(c, names) # Now check with a function call cmd = 'a = f("%s' % prefix c = ip.complete(prefix, cmd)[1] comp = [prefix+s for s in suffixes] nt.assert_equal(c, comp) finally: # prevent failures from making chdir stick os.chdir(cwd)
def _notebook_dir_default(self): if self.file_to_run: return os.path.dirname(os.path.abspath(self.file_to_run)) else: return py3compat.getcwd()
class FileNotebookManager(NotebookManager): save_script = Bool( False, config=True, help="""Automatically create a Python script when saving the notebook. For easier use of import, %run and %load across notebooks, a <notebook-name>.py script will be created next to any <notebook-name>.ipynb on each save. This can also be set with the short `--script` flag. """) notebook_dir = Unicode(getcwd(), config=True) def _notebook_dir_changed(self, name, old, new): """Do a bit of validation of the notebook dir.""" if not os.path.isabs(new): # If we receive a non-absolute path, make it absolute. self.notebook_dir = os.path.abspath(new) return if not os.path.exists(new) or not os.path.isdir(new): raise TraitError("notebook dir %r is not a directory" % new) checkpoint_dir = Unicode( config=True, help="""The location in which to keep notebook checkpoints By default, it is notebook-dir/.ipynb_checkpoints """) def _checkpoint_dir_default(self): return os.path.join(self.notebook_dir, '.ipynb_checkpoints') def _checkpoint_dir_changed(self, name, old, new): """do a bit of validation of the checkpoint dir""" if not os.path.isabs(new): # If we receive a non-absolute path, make it absolute. abs_new = os.path.abspath(new) self.checkpoint_dir = abs_new return if os.path.exists(new) and not os.path.isdir(new): raise TraitError("checkpoint dir %r is not a directory" % new) if not os.path.exists(new): self.log.info("Creating checkpoint dir %s", new) try: os.mkdir(new) except: raise TraitError("Couldn't create checkpoint dir %r" % new) def _copy(self, src, dest): """copy src to dest like shutil.copy2, but log errors in copystat """ shutil.copyfile(src, dest) try: shutil.copystat(src, dest) except OSError as e: self.log.debug("copystat on %s failed", dest, exc_info=True) def get_notebook_names(self, path=''): """List all notebook names in the notebook dir and path.""" path = path.strip('/') if not os.path.isdir(self._get_os_path(path=path)): raise web.HTTPError(404, 'Directory not found: ' + path) names = glob.glob(self._get_os_path('*' + self.filename_ext, path)) names = [os.path.basename(name) for name in names] return names def path_exists(self, path): """Does the API-style path (directory) actually exist? Parameters ---------- path : string The path to check. This is an API path (`/` separated, relative to base notebook-dir). Returns ------- exists : bool Whether the path is indeed a directory. """ path = path.strip('/') os_path = self._get_os_path(path=path) return os.path.isdir(os_path) def is_hidden(self, path): """Does the API style path correspond to a hidden directory or file? Parameters ---------- path : string The path to check. This is an API path (`/` separated, relative to base notebook-dir). Returns ------- exists : bool Whether the path is hidden. """ path = path.strip('/') os_path = self._get_os_path(path=path) return is_hidden(os_path, self.notebook_dir) def _get_os_path(self, name=None, path=''): """Given a notebook name and a URL path, return its file system path. Parameters ---------- name : string The name of a notebook file with the .ipynb extension path : string The relative URL path (with '/' as separator) to the named notebook. Returns ------- path : string A file system path that combines notebook_dir (location where server started), the relative path, and the filename with the current operating system's url. """ if name is not None: path = path + '/' + name return to_os_path(path, self.notebook_dir) def notebook_exists(self, name, path=''): """Returns a True if the notebook exists. Else, returns False. Parameters ---------- name : string The name of the notebook you are checking. path : string The relative path to the notebook (with '/' as separator) Returns ------- bool """ path = path.strip('/') nbpath = self._get_os_path(name, path=path) return os.path.isfile(nbpath) # TODO: Remove this after we create the contents web service and directories are # no longer listed by the notebook web service. def list_dirs(self, path): """List the directories for a given API style path.""" path = path.strip('/') os_path = self._get_os_path('', path) if not os.path.isdir(os_path): raise web.HTTPError(404, u'directory does not exist: %r' % os_path) elif is_hidden(os_path, self.notebook_dir): self.log.info("Refusing to serve hidden directory, via 404 Error") raise web.HTTPError(404, u'directory does not exist: %r' % os_path) dir_names = os.listdir(os_path) dirs = [] for name in dir_names: os_path = self._get_os_path(name, path) if os.path.isdir(os_path) and not is_hidden(os_path, self.notebook_dir)\ and self.should_list(name): try: model = self.get_dir_model(name, path) except IOError: pass dirs.append(model) dirs = sorted(dirs, key=sort_key) return dirs # TODO: Remove this after we create the contents web service and directories are # no longer listed by the notebook web service. def get_dir_model(self, name, path=''): """Get the directory model given a directory name and its API style path""" path = path.strip('/') os_path = self._get_os_path(name, path) if not os.path.isdir(os_path): raise IOError('directory does not exist: %r' % os_path) info = os.stat(os_path) last_modified = tz.utcfromtimestamp(info.st_mtime) created = tz.utcfromtimestamp(info.st_ctime) # Create the notebook model. model = {} model['name'] = name model['path'] = path model['last_modified'] = last_modified model['created'] = created model['type'] = 'directory' return model def list_notebooks(self, path): """Returns a list of dictionaries that are the standard model for all notebooks in the relative 'path'. Parameters ---------- path : str the URL path that describes the relative path for the listed notebooks Returns ------- notebooks : list of dicts a list of the notebook models without 'content' """ path = path.strip('/') notebook_names = self.get_notebook_names(path) notebooks = [ self.get_notebook(name, path, content=False) for name in notebook_names if self.should_list(name) ] notebooks = sorted(notebooks, key=sort_key) return notebooks def get_notebook(self, name, path='', content=True): """ Takes a path and name for a notebook and returns its model Parameters ---------- name : str the name of the notebook path : str the URL path that describes the relative path for the notebook Returns ------- model : dict the notebook model. If contents=True, returns the 'contents' dict in the model as well. """ path = path.strip('/') if not self.notebook_exists(name=name, path=path): raise web.HTTPError(404, u'Notebook does not exist: %s' % name) os_path = self._get_os_path(name, path) info = os.stat(os_path) last_modified = tz.utcfromtimestamp(info.st_mtime) created = tz.utcfromtimestamp(info.st_ctime) # Create the notebook model. model = {} model['name'] = name model['path'] = path model['last_modified'] = last_modified model['created'] = created model['type'] = 'notebook' if content: with io.open(os_path, 'r', encoding='utf-8') as f: try: nb = current.read(f, u'json') except Exception as e: raise web.HTTPError( 400, u"Unreadable Notebook: %s %s" % (os_path, e)) self.mark_trusted_cells(nb, name, path) model['content'] = nb return model def save_notebook(self, model, name='', path=''): """Save the notebook model and return the model with no content.""" path = path.strip('/') if 'content' not in model: raise web.HTTPError(400, u'No notebook JSON data provided') # One checkpoint should always exist if self.notebook_exists( name, path) and not self.list_checkpoints(name, path): self.create_checkpoint(name, path) new_path = model.get('path', path).strip('/') new_name = model.get('name', name) if path != new_path or name != new_name: self.rename_notebook(name, path, new_name, new_path) # Save the notebook file os_path = self._get_os_path(new_name, new_path) nb = current.to_notebook_json(model['content']) self.check_and_sign(nb, new_name, new_path) if 'name' in nb['metadata']: nb['metadata']['name'] = u'' try: self.log.debug("Autosaving notebook %s", os_path) with io.open(os_path, 'w', encoding='utf-8') as f: current.write(nb, f, u'json') except Exception as e: raise web.HTTPError( 400, u'Unexpected error while autosaving notebook: %s %s' % (os_path, e)) # Save .py script as well if self.save_script: py_path = os.path.splitext(os_path)[0] + '.py' self.log.debug("Writing script %s", py_path) try: with io.open(py_path, 'w', encoding='utf-8') as f: current.write(nb, f, u'py') except Exception as e: raise web.HTTPError( 400, u'Unexpected error while saving notebook as script: %s %s' % (py_path, e)) model = self.get_notebook(new_name, new_path, content=False) return model def update_notebook(self, model, name, path=''): """Update the notebook's path and/or name""" path = path.strip('/') new_name = model.get('name', name) new_path = model.get('path', path).strip('/') if path != new_path or name != new_name: self.rename_notebook(name, path, new_name, new_path) model = self.get_notebook(new_name, new_path, content=False) return model def delete_notebook(self, name, path=''): """Delete notebook by name and path.""" path = path.strip('/') os_path = self._get_os_path(name, path) if not os.path.isfile(os_path): raise web.HTTPError(404, u'Notebook does not exist: %s' % os_path) # clear checkpoints for checkpoint in self.list_checkpoints(name, path): checkpoint_id = checkpoint['id'] cp_path = self.get_checkpoint_path(checkpoint_id, name, path) if os.path.isfile(cp_path): self.log.debug("Unlinking checkpoint %s", cp_path) os.unlink(cp_path) self.log.debug("Unlinking notebook %s", os_path) os.unlink(os_path) def rename_notebook(self, old_name, old_path, new_name, new_path): """Rename a notebook.""" old_path = old_path.strip('/') new_path = new_path.strip('/') if new_name == old_name and new_path == old_path: return new_os_path = self._get_os_path(new_name, new_path) old_os_path = self._get_os_path(old_name, old_path) # Should we proceed with the move? if os.path.isfile(new_os_path): raise web.HTTPError( 409, u'Notebook with name already exists: %s' % new_os_path) if self.save_script: old_py_path = os.path.splitext(old_os_path)[0] + '.py' new_py_path = os.path.splitext(new_os_path)[0] + '.py' if os.path.isfile(new_py_path): raise web.HTTPError( 409, u'Python script with name already exists: %s' % new_py_path) # Move the notebook file try: shutil.move(old_os_path, new_os_path) except Exception as e: raise web.HTTPError( 500, u'Unknown error renaming notebook: %s %s' % (old_os_path, e)) # Move the checkpoints old_checkpoints = self.list_checkpoints(old_name, old_path) for cp in old_checkpoints: checkpoint_id = cp['id'] old_cp_path = self.get_checkpoint_path(checkpoint_id, old_name, old_path) new_cp_path = self.get_checkpoint_path(checkpoint_id, new_name, new_path) if os.path.isfile(old_cp_path): self.log.debug("Renaming checkpoint %s -> %s", old_cp_path, new_cp_path) shutil.move(old_cp_path, new_cp_path) # Move the .py script if self.save_script: shutil.move(old_py_path, new_py_path) # Checkpoint-related utilities def get_checkpoint_path(self, checkpoint_id, name, path=''): """find the path to a checkpoint""" path = path.strip('/') basename, _ = os.path.splitext(name) filename = u"{name}-{checkpoint_id}{ext}".format( name=basename, checkpoint_id=checkpoint_id, ext=self.filename_ext, ) cp_path = os.path.join(path, self.checkpoint_dir, filename) return cp_path def get_checkpoint_model(self, checkpoint_id, name, path=''): """construct the info dict for a given checkpoint""" path = path.strip('/') cp_path = self.get_checkpoint_path(checkpoint_id, name, path) stats = os.stat(cp_path) last_modified = tz.utcfromtimestamp(stats.st_mtime) info = dict( id=checkpoint_id, last_modified=last_modified, ) return info # public checkpoint API def create_checkpoint(self, name, path=''): """Create a checkpoint from the current state of a notebook""" path = path.strip('/') nb_path = self._get_os_path(name, path) # only the one checkpoint ID: checkpoint_id = u"checkpoint" cp_path = self.get_checkpoint_path(checkpoint_id, name, path) self.log.debug("creating checkpoint for notebook %s", name) if not os.path.exists(self.checkpoint_dir): os.mkdir(self.checkpoint_dir) self._copy(nb_path, cp_path) # return the checkpoint info return self.get_checkpoint_model(checkpoint_id, name, path) def list_checkpoints(self, name, path=''): """list the checkpoints for a given notebook This notebook manager currently only supports one checkpoint per notebook. """ path = path.strip('/') checkpoint_id = "checkpoint" path = self.get_checkpoint_path(checkpoint_id, name, path) if not os.path.exists(path): return [] else: return [self.get_checkpoint_model(checkpoint_id, name, path)] def restore_checkpoint(self, checkpoint_id, name, path=''): """restore a notebook to a checkpointed state""" path = path.strip('/') self.log.info("restoring Notebook %s from checkpoint %s", name, checkpoint_id) nb_path = self._get_os_path(name, path) cp_path = self.get_checkpoint_path(checkpoint_id, name, path) if not os.path.isfile(cp_path): self.log.debug("checkpoint file does not exist: %s", cp_path) raise web.HTTPError( 404, u'Notebook checkpoint does not exist: %s-%s' % (name, checkpoint_id)) # ensure notebook is readable (never restore from an unreadable notebook) with io.open(cp_path, 'r', encoding='utf-8') as f: current.read(f, u'json') self._copy(cp_path, nb_path) self.log.debug("copying %s -> %s", cp_path, nb_path) def delete_checkpoint(self, checkpoint_id, name, path=''): """delete a notebook's checkpoint""" path = path.strip('/') cp_path = self.get_checkpoint_path(checkpoint_id, name, path) if not os.path.isfile(cp_path): raise web.HTTPError( 404, u'Notebook checkpoint does not exist: %s%s-%s' % (path, name, checkpoint_id)) self.log.debug("unlinking %s", cp_path) os.unlink(cp_path) def info_string(self): return "Serving notebooks from local directory: %s" % self.notebook_dir
def cd(self, parameter_s=""): """Change the current working directory. This command automatically maintains an internal list of directories you visit during your IPython session, in the variable _dh. The command %dhist shows this history nicely formatted. You can also do 'cd -<tab>' to see directory history conveniently. Usage: cd 'dir': changes to directory 'dir'. cd -: changes to the last visited directory. cd -<n>: changes to the n-th directory in the directory history. cd --foo: change to directory that matches 'foo' in history cd -b <bookmark_name>: jump to a bookmark set by %bookmark (note: cd <bookmark_name> is enough if there is no directory <bookmark_name>, but a bookmark with the name exists.) 'cd -b <tab>' allows you to tab-complete bookmark names. Options: -q: quiet. Do not print the working directory after the cd command is executed. By default IPython's cd command does print this directory, since the default prompts do not display path information. Note that !cd doesn't work for this purpose because the shell where !command runs is immediately discarded after executing 'command'. Examples -------- :: In [10]: cd parent/child /home/tsuser/parent/child """ oldcwd = py3compat.getcwd() numcd = re.match(r"(-)(\d+)$", parameter_s) # jump in directory history by number if numcd: nn = int(numcd.group(2)) try: ps = self.shell.user_ns["_dh"][nn] except IndexError: print("The requested directory does not exist in history.") return else: opts = {} elif parameter_s.startswith("--"): ps = None fallback = None pat = parameter_s[2:] dh = self.shell.user_ns["_dh"] # first search only by basename (last component) for ent in reversed(dh): if pat in os.path.basename(ent) and os.path.isdir(ent): ps = ent break if fallback is None and pat in ent and os.path.isdir(ent): fallback = ent # if we have no last part match, pick the first full path match if ps is None: ps = fallback if ps is None: print("No matching entry in directory history") return else: opts = {} else: # turn all non-space-escaping backslashes to slashes, # for c:\windows\directory\names\ parameter_s = re.sub(r"\\(?! )", "/", parameter_s) opts, ps = self.parse_options(parameter_s, "qb", mode="string") # jump to previous if ps == "-": try: ps = self.shell.user_ns["_dh"][-2] except IndexError: raise UsageError("%cd -: No previous directory to change to.") # jump to bookmark if needed else: if not os.path.isdir(ps) or "b" in opts: bkms = self.shell.db.get("bookmarks", {}) if ps in bkms: target = bkms[ps] print("(bookmark:%s) -> %s" % (ps, target)) ps = target else: if "b" in opts: raise UsageError("Bookmark '%s' not found. " "Use '%%bookmark -l' to see your bookmarks." % ps) # strip extra quotes on Windows, because os.chdir doesn't like them ps = unquote_filename(ps) # at this point ps should point to the target dir if ps: try: os.chdir(os.path.expanduser(ps)) if hasattr(self.shell, "term_title") and self.shell.term_title: set_term_title("IPython: " + abbrev_cwd()) except OSError: print(sys.exc_info()[1]) else: cwd = py3compat.getcwd() dhist = self.shell.user_ns["_dh"] if oldcwd != cwd: dhist.append(cwd) self.shell.db["dhist"] = compress_dhist(dhist)[-100:] else: os.chdir(self.shell.home_dir) if hasattr(self.shell, "term_title") and self.shell.term_title: set_term_title("IPython: " + "~") cwd = py3compat.getcwd() dhist = self.shell.user_ns["_dh"] if oldcwd != cwd: dhist.append(cwd) self.shell.db["dhist"] = compress_dhist(dhist)[-100:] if not "q" in opts and self.shell.user_ns["_dh"]: print(self.shell.user_ns["_dh"][-1])
def _dir_hist_default(self): try: return [py3compat.getcwd()] except OSError: return []