-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Notebook server info files #4772
Changes from 3 commits
80efc81
bc19d4d
bdaf6ec
08e7c9f
29ff209
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,8 @@ | |
|
||
# stdlib | ||
import errno | ||
import io | ||
import json | ||
import logging | ||
import os | ||
import random | ||
|
@@ -72,6 +74,7 @@ | |
|
||
from IPython.config.application import catch_config_error, boolean_flag | ||
from IPython.core.application import BaseIPythonApplication | ||
from IPython.core.profiledir import ProfileDir | ||
from IPython.consoleapp import IPythonConsoleApp | ||
from IPython.kernel import swallow_argv | ||
from IPython.kernel.zmq.session import default_secure | ||
|
@@ -499,6 +502,12 @@ def _mathjax_url_changed(self, name, old, new): | |
"sent by the upstream reverse proxy. Neccesary if the proxy handles SSL") | ||
) | ||
|
||
info_file = Unicode() | ||
|
||
def _info_file_default(self): | ||
info_file = "nbserver-%s.json"%os.getpid() | ||
return os.path.join(self.profile_dir.security_dir, info_file) | ||
|
||
def parse_command_line(self, argv=None): | ||
super(NotebookApp, self).parse_command_line(argv) | ||
|
||
|
@@ -594,6 +603,20 @@ def init_webapp(self): | |
'no available port could be found.') | ||
self.exit(1) | ||
|
||
@property | ||
def display_url(self): | ||
ip = self.ip if self.ip else '[all ip addresses on your system]' | ||
return self._url(ip) | ||
|
||
@property | ||
def connection_url(self): | ||
ip = self.ip if self.ip else localhost() | ||
return self._url(ip) | ||
|
||
def _url(self, ip): | ||
proto = 'https' if self.certfile else 'http' | ||
return "%s://%s:%i%s" % (proto, ip, self.port, self.base_project_url) | ||
|
||
def init_signal(self): | ||
if not sys.platform.startswith('win'): | ||
signal.signal(signal.SIGINT, self._handle_sigint) | ||
|
@@ -666,7 +689,6 @@ def init_components(self): | |
elif status == 'unclean': | ||
self.log.warn("components submodule unclean, you may see 404s on static/components") | ||
self.log.warn("run `setup.py submodule` or `git submodule update` to update") | ||
|
||
|
||
@catch_config_error | ||
def initialize(self, argv=None): | ||
|
@@ -691,33 +713,56 @@ def notebook_info(self): | |
"Return the current working directory and the server url information" | ||
info = self.notebook_manager.info_string() + "\n" | ||
info += "%d active kernels \n" % len(self.kernel_manager._kernels) | ||
return info + "The IPython Notebook is running at: %s" % self._url | ||
return info + "The IPython Notebook is running at: %s" % self.display_url | ||
|
||
def server_info(self): | ||
"""Return a JSONable dict of information about this server.""" | ||
return {'url': self.connection_url, | ||
'hostname': self.ip if self.ip else 'localhost', | ||
'port': self.port, | ||
'secure': bool(self.certfile), | ||
'baseurlpath': self.base_project_url, | ||
'notebookdir': os.path.abspath(self.notebook_manager.notebook_dir), | ||
} | ||
|
||
def write_server_info_file(self): | ||
"""Write the result of server_info() to the JSON file info_file.""" | ||
with open(self.info_file, 'w') as f: | ||
json.dump(self.server_info(), f, indent=2) | ||
|
||
def remove_server_info_file(self): | ||
"""Remove the nbserver-<pid>.json file created for this server. | ||
|
||
Ignores the error raised when the file has already been removed. | ||
""" | ||
try: | ||
os.unlink(self.info_file) | ||
except OSError as e: | ||
if e.errno != errno.ENOENT: | ||
raise | ||
|
||
def start(self): | ||
""" Start the IPython Notebook server app, after initialization | ||
|
||
This method takes no arguments so all configuration and initialization | ||
must be done prior to calling this method.""" | ||
ip = self.ip if self.ip else '[all ip addresses on your system]' | ||
proto = 'https' if self.certfile else 'http' | ||
info = self.log.info | ||
self._url = "%s://%s:%i%s" % (proto, ip, self.port, | ||
self.base_project_url) | ||
for line in self.notebook_info().split("\n"): | ||
info(line) | ||
info("Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).") | ||
|
||
self.write_server_info_file() | ||
|
||
if self.open_browser or self.file_to_run: | ||
ip = self.ip or localhost() | ||
try: | ||
browser = webbrowser.get(self.browser or None) | ||
except webbrowser.Error as e: | ||
self.log.warn('No web browser found: %s.' % e) | ||
browser = None | ||
|
||
nbdir = os.path.abspath(self.notebook_manager.notebook_dir) | ||
f = self.file_to_run | ||
if f: | ||
nbdir = os.path.abspath(self.notebook_manager.notebook_dir) | ||
if f.startswith(nbdir): | ||
f = f[len(nbdir):] | ||
else: | ||
|
@@ -732,16 +777,30 @@ def start(self): | |
else: | ||
url = url_path_join('tree', f) | ||
if browser: | ||
b = lambda : browser.open("%s://%s:%i%s%s" % (proto, ip, | ||
self.port, self.base_project_url, url), new=2) | ||
b = lambda : browser.open("%s%s" % (self.connection_url, url), | ||
new=2) | ||
threading.Thread(target=b).start() | ||
try: | ||
ioloop.IOLoop.instance().start() | ||
except KeyboardInterrupt: | ||
info("Interrupted...") | ||
finally: | ||
self.cleanup_kernels() | ||
self.remove_server_info_file() | ||
|
||
|
||
def discover_running_servers(profile='default'): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it seems like this should be defined somewhere other than the notebookapp file, but I'm not sure where. Any idea? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had a brief look, but this seemed the most logical place I could see. I'd argue that it's effectively 'list instances of NotebookApp on this system', so it makes sense to define it near the NotebookApp class. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do you want to add an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am +1 on having a |
||
"""Iterate over the server info files of running notebook servers. | ||
|
||
Given a profile name, find nbserver-* files in the security directory of | ||
that profile, and yield dicts of their information, each one pertaining to | ||
a currently running notebook server instance. | ||
""" | ||
pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), name=profile) | ||
for file in os.listdir(pd.security_dir): | ||
if file.startswith('nbserver-'): | ||
with io.open(os.path.join(pd.security_dir, file), encoding='utf-8') as f: | ||
yield json.load(f) | ||
|
||
#----------------------------------------------------------------------------- | ||
# Main entry point | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably keep the same names in JSON, so
base_project_url
andnotebook_dir
.