mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-13 04:53:01 +00:00
use traitlets-4.1 observe/default decorators
This commit is contained in:
@@ -36,6 +36,7 @@ from tornado import gen, web
|
|||||||
from traitlets import (
|
from traitlets import (
|
||||||
Unicode, Integer, Dict, TraitError, List, Bool, Any,
|
Unicode, Integer, Dict, TraitError, List, Bool, Any,
|
||||||
Type, Set, Instance, Bytes, Float,
|
Type, Set, Instance, Bytes, Float,
|
||||||
|
observe, default,
|
||||||
)
|
)
|
||||||
from traitlets.config import Application, catch_config_error
|
from traitlets.config import Application, catch_config_error
|
||||||
|
|
||||||
@@ -209,6 +210,7 @@ class JupyterHub(Application):
|
|||||||
help="Paths to search for jinja templates.",
|
help="Paths to search for jinja templates.",
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
|
@default('template_paths')
|
||||||
def _template_paths_default(self):
|
def _template_paths_default(self):
|
||||||
return [os.path.join(self.data_files_path, 'templates')]
|
return [os.path.join(self.data_files_path, 'templates')]
|
||||||
|
|
||||||
@@ -262,6 +264,8 @@ class JupyterHub(Application):
|
|||||||
logo_file = Unicode('',
|
logo_file = Unicode('',
|
||||||
help="Specify path to a logo image to override the Jupyter logo in the banner."
|
help="Specify path to a logo image to override the Jupyter logo in the banner."
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
|
@default('logo_file')
|
||||||
def _logo_file_default(self):
|
def _logo_file_default(self):
|
||||||
return os.path.join(self.data_files_path, 'static', 'images', 'jupyter.png')
|
return os.path.join(self.data_files_path, 'static', 'images', 'jupyter.png')
|
||||||
|
|
||||||
@@ -284,6 +288,8 @@ class JupyterHub(Application):
|
|||||||
Loaded from the CONFIGPROXY_AUTH_TOKEN env variable by default.
|
Loaded from the CONFIGPROXY_AUTH_TOKEN env variable by default.
|
||||||
"""
|
"""
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
|
@default('proxy_auth_token')
|
||||||
def _proxy_auth_token_default(self):
|
def _proxy_auth_token_default(self):
|
||||||
token = os.environ.get('CONFIGPROXY_AUTH_TOKEN', None)
|
token = os.environ.get('CONFIGPROXY_AUTH_TOKEN', None)
|
||||||
if not token:
|
if not token:
|
||||||
@@ -302,6 +308,8 @@ class JupyterHub(Application):
|
|||||||
proxy_api_port = Integer(
|
proxy_api_port = Integer(
|
||||||
help="The port for the proxy API handlers"
|
help="The port for the proxy API handlers"
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
|
@default('proxy_api_port')
|
||||||
def _proxy_api_port_default(self):
|
def _proxy_api_port_default(self):
|
||||||
return self.port + 1
|
return self.port + 1
|
||||||
|
|
||||||
@@ -314,21 +322,27 @@ class JupyterHub(Application):
|
|||||||
hub_prefix = URLPrefix('/hub/',
|
hub_prefix = URLPrefix('/hub/',
|
||||||
help="The prefix for the hub server. Must not be '/'"
|
help="The prefix for the hub server. Must not be '/'"
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
|
@default('hub_prefix')
|
||||||
def _hub_prefix_default(self):
|
def _hub_prefix_default(self):
|
||||||
return url_path_join(self.base_url, '/hub/')
|
return url_path_join(self.base_url, '/hub/')
|
||||||
|
|
||||||
|
@observe('hub_prefix')
|
||||||
def _hub_prefix_changed(self, name, old, new):
|
def _hub_prefix_changed(self, name, old, new):
|
||||||
if new == '/':
|
if new == '/':
|
||||||
raise TraitError("'/' is not a valid hub prefix")
|
raise TraitError("'/' is not a valid hub prefix")
|
||||||
if not new.startswith(self.base_url):
|
if not new.startswith(self.base_url):
|
||||||
self.hub_prefix = url_path_join(self.base_url, new)
|
self.hub_prefix = url_path_join(self.base_url, new)
|
||||||
|
|
||||||
cookie_secret = Bytes(env='JPY_COOKIE_SECRET',
|
cookie_secret = Bytes(
|
||||||
help="""The cookie secret to use to encrypt cookies.
|
help="""The cookie secret to use to encrypt cookies.
|
||||||
|
|
||||||
Loaded from the JPY_COOKIE_SECRET env variable by default.
|
Loaded from the JPY_COOKIE_SECRET env variable by default.
|
||||||
"""
|
"""
|
||||||
).tag(config=True)
|
).tag(
|
||||||
|
config=True,
|
||||||
|
env='JPY_COOKIE_SECRET',
|
||||||
|
)
|
||||||
|
|
||||||
cookie_secret_file = Unicode('jupyterhub_cookie_secret',
|
cookie_secret_file = Unicode('jupyterhub_cookie_secret',
|
||||||
help="""File in which to store the cookie secret."""
|
help="""File in which to store the cookie secret."""
|
||||||
@@ -350,6 +364,8 @@ class JupyterHub(Application):
|
|||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
authenticator = Instance(Authenticator)
|
authenticator = Instance(Authenticator)
|
||||||
|
|
||||||
|
@default('authenticator')
|
||||||
def _authenticator_default(self):
|
def _authenticator_default(self):
|
||||||
return self.authenticator_class(parent=self, db=self.db)
|
return self.authenticator_class(parent=self, db=self.db)
|
||||||
|
|
||||||
@@ -364,7 +380,10 @@ class JupyterHub(Application):
|
|||||||
db_url = Unicode('sqlite:///jupyterhub.sqlite',
|
db_url = Unicode('sqlite:///jupyterhub.sqlite',
|
||||||
help="url for the database. e.g. `sqlite:///jupyterhub.sqlite`"
|
help="url for the database. e.g. `sqlite:///jupyterhub.sqlite`"
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
def _db_url_changed(self, name, old, new):
|
|
||||||
|
@observe('db_url')
|
||||||
|
def _db_url_changed(self, change):
|
||||||
|
new = change['new']
|
||||||
if '://' not in new:
|
if '://' not in new:
|
||||||
# assume sqlite, if given as a plain filename
|
# assume sqlite, if given as a plain filename
|
||||||
self.db_url = 'sqlite:///%s' % new
|
self.db_url = 'sqlite:///%s' % new
|
||||||
@@ -384,6 +403,8 @@ class JupyterHub(Application):
|
|||||||
session_factory = Any()
|
session_factory = Any()
|
||||||
|
|
||||||
users = Instance(UserDict)
|
users = Instance(UserDict)
|
||||||
|
|
||||||
|
@default('users')
|
||||||
def _users_default(self):
|
def _users_default(self):
|
||||||
assert self.tornado_settings
|
assert self.tornado_settings
|
||||||
return UserDict(db_factory=lambda : self.db, settings=self.tornado_settings)
|
return UserDict(db_factory=lambda : self.db, settings=self.tornado_settings)
|
||||||
@@ -435,13 +456,16 @@ class JupyterHub(Application):
|
|||||||
proxy_process = None
|
proxy_process = None
|
||||||
io_loop = None
|
io_loop = None
|
||||||
|
|
||||||
|
@default('log_level')
|
||||||
def _log_level_default(self):
|
def _log_level_default(self):
|
||||||
return logging.INFO
|
return logging.INFO
|
||||||
|
|
||||||
|
@default('log_datefmt')
|
||||||
def _log_datefmt_default(self):
|
def _log_datefmt_default(self):
|
||||||
"""Exclude date from default date format"""
|
"""Exclude date from default date format"""
|
||||||
return "%Y-%m-%d %H:%M:%S"
|
return "%Y-%m-%d %H:%M:%S"
|
||||||
|
|
||||||
|
@default('log_format')
|
||||||
def _log_format_default(self):
|
def _log_format_default(self):
|
||||||
"""override default log format to include time"""
|
"""override default log format to include time"""
|
||||||
return "%(color)s[%(levelname)1.1s %(asctime)s.%(msecs).03d %(name)s %(module)s:%(lineno)d]%(end_color)s %(message)s"
|
return "%(color)s[%(levelname)1.1s %(asctime)s.%(msecs).03d %(name)s %(module)s:%(lineno)d]%(end_color)s %(message)s"
|
||||||
@@ -537,7 +561,7 @@ class JupyterHub(Application):
|
|||||||
def init_secrets(self):
|
def init_secrets(self):
|
||||||
trait_name = 'cookie_secret'
|
trait_name = 'cookie_secret'
|
||||||
trait = self.traits()[trait_name]
|
trait = self.traits()[trait_name]
|
||||||
env_name = trait.get_metadata('env')
|
env_name = trait.metadata.get('env')
|
||||||
secret_file = os.path.abspath(
|
secret_file = os.path.abspath(
|
||||||
os.path.expanduser(self.cookie_secret_file)
|
os.path.expanduser(self.cookie_secret_file)
|
||||||
)
|
)
|
||||||
|
@@ -15,7 +15,7 @@ from tornado import gen
|
|||||||
import pamela
|
import pamela
|
||||||
|
|
||||||
from traitlets.config import LoggingConfigurable
|
from traitlets.config import LoggingConfigurable
|
||||||
from traitlets import Bool, Set, Unicode, Dict, Any
|
from traitlets import Bool, Set, Unicode, Dict, Any, default, observe
|
||||||
|
|
||||||
from .handlers.login import LoginHandler
|
from .handlers.login import LoginHandler
|
||||||
from .utils import url_path_join
|
from .utils import url_path_join
|
||||||
@@ -61,10 +61,11 @@ class Authenticator(LoggingConfigurable):
|
|||||||
If not defined: allow any username.
|
If not defined: allow any username.
|
||||||
"""
|
"""
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
def _username_pattern_changed(self, name, old, new):
|
@observe('username_pattern')
|
||||||
if not new:
|
def _username_pattern_changed(self, change):
|
||||||
|
if not change['new']:
|
||||||
self.username_regex = None
|
self.username_regex = None
|
||||||
self.username_regex = re.compile(new)
|
self.username_regex = re.compile(change['new'])
|
||||||
|
|
||||||
username_regex = Any()
|
username_regex = Any()
|
||||||
|
|
||||||
@@ -272,6 +273,8 @@ class LocalAuthenticator(Authenticator):
|
|||||||
when the user 'river' is created.
|
when the user 'river' is created.
|
||||||
"""
|
"""
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
|
@default('add_user_cmd')
|
||||||
def _add_user_cmd_default(self):
|
def _add_user_cmd_default(self):
|
||||||
if sys.platform == 'darwin':
|
if sys.platform == 'darwin':
|
||||||
raise ValueError("I don't know how to create users on OS X")
|
raise ValueError("I don't know how to create users on OS X")
|
||||||
@@ -285,10 +288,10 @@ class LocalAuthenticator(Authenticator):
|
|||||||
group_whitelist = Set(
|
group_whitelist = Set(
|
||||||
help="Automatically whitelist anyone in this group.",
|
help="Automatically whitelist anyone in this group.",
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
@observe('group_whitelist')
|
||||||
def _group_whitelist_changed(self, name, old, new):
|
def _group_whitelist_changed(self, change):
|
||||||
if self.whitelist:
|
if self.whitelist:
|
||||||
self.log.warn(
|
self.log.warning(
|
||||||
"Ignoring username whitelist because group whitelist supplied!"
|
"Ignoring username whitelist because group whitelist supplied!"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -128,7 +128,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
cmd = Command(['jupyterhub-singleuser'],
|
cmd = Command(['jupyterhub-singleuser'],
|
||||||
help="""The command used for starting notebooks."""
|
help="""The command used for starting notebooks."""
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
args = List(Unicode,
|
args = List(Unicode(),
|
||||||
help="""Extra arguments to be passed to the single-user server"""
|
help="""Extra arguments to be passed to the single-user server"""
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
|
@@ -13,6 +13,8 @@ from tornado import gen
|
|||||||
from tornado.concurrent import Future
|
from tornado.concurrent import Future
|
||||||
from tornado.ioloop import IOLoop
|
from tornado.ioloop import IOLoop
|
||||||
|
|
||||||
|
from traitlets import default
|
||||||
|
|
||||||
from ..app import JupyterHub
|
from ..app import JupyterHub
|
||||||
from ..auth import PAMAuthenticator
|
from ..auth import PAMAuthenticator
|
||||||
from .. import orm
|
from .. import orm
|
||||||
@@ -44,7 +46,7 @@ class MockSpawner(LocalProcessSpawner):
|
|||||||
|
|
||||||
def user_env(self, env):
|
def user_env(self, env):
|
||||||
return env
|
return env
|
||||||
|
@default('cmd')
|
||||||
def _cmd_default(self):
|
def _cmd_default(self):
|
||||||
return [sys.executable, '-m', 'jupyterhub.tests.mocksu']
|
return [sys.executable, '-m', 'jupyterhub.tests.mocksu']
|
||||||
|
|
||||||
@@ -66,6 +68,7 @@ class SlowSpawner(MockSpawner):
|
|||||||
class NeverSpawner(MockSpawner):
|
class NeverSpawner(MockSpawner):
|
||||||
"""A spawner that will never start"""
|
"""A spawner that will never start"""
|
||||||
|
|
||||||
|
@default('start_timeout')
|
||||||
def _start_timeout_default(self):
|
def _start_timeout_default(self):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
@@ -90,6 +93,7 @@ class FormSpawner(MockSpawner):
|
|||||||
|
|
||||||
|
|
||||||
class MockPAMAuthenticator(PAMAuthenticator):
|
class MockPAMAuthenticator(PAMAuthenticator):
|
||||||
|
@default('admin_users')
|
||||||
def _admin_users_default(self):
|
def _admin_users_default(self):
|
||||||
return {'admin'}
|
return {'admin'}
|
||||||
|
|
||||||
@@ -113,15 +117,19 @@ class MockHub(JupyterHub):
|
|||||||
|
|
||||||
last_activity_interval = 2
|
last_activity_interval = 2
|
||||||
|
|
||||||
|
@default('subdomain_host')
|
||||||
def _subdomain_host_default(self):
|
def _subdomain_host_default(self):
|
||||||
return os.environ.get('JUPYTERHUB_TEST_SUBDOMAIN_HOST', '')
|
return os.environ.get('JUPYTERHUB_TEST_SUBDOMAIN_HOST', '')
|
||||||
|
|
||||||
|
@default('ip')
|
||||||
def _ip_default(self):
|
def _ip_default(self):
|
||||||
return '127.0.0.1'
|
return '127.0.0.1'
|
||||||
|
|
||||||
|
@default('authenticator_class')
|
||||||
def _authenticator_class_default(self):
|
def _authenticator_class_default(self):
|
||||||
return MockPAMAuthenticator
|
return MockPAMAuthenticator
|
||||||
|
|
||||||
|
@default('spawner_class')
|
||||||
def _spawner_class_default(self):
|
def _spawner_class_default(self):
|
||||||
return MockSpawner
|
return MockSpawner
|
||||||
|
|
||||||
|
@@ -21,7 +21,7 @@ class Command(List):
|
|||||||
kwargs.setdefault('minlen', 1)
|
kwargs.setdefault('minlen', 1)
|
||||||
if isinstance(default_value, str):
|
if isinstance(default_value, str):
|
||||||
default_value = [default_value]
|
default_value = [default_value]
|
||||||
super().__init__(Unicode, default_value, **kwargs)
|
super().__init__(Unicode(), default_value, **kwargs)
|
||||||
|
|
||||||
def validate(self, obj, value):
|
def validate(self, obj, value):
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
|
@@ -12,7 +12,7 @@ from sqlalchemy import inspect
|
|||||||
from .utils import url_path_join
|
from .utils import url_path_join
|
||||||
|
|
||||||
from . import orm
|
from . import orm
|
||||||
from traitlets import HasTraits, Any, Dict
|
from traitlets import HasTraits, Any, Dict, observe, default
|
||||||
from .spawner import LocalProcessSpawner
|
from .spawner import LocalProcessSpawner
|
||||||
|
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ class UserDict(dict):
|
|||||||
elif isinstance(key, str):
|
elif isinstance(key, str):
|
||||||
orm_user = self.db.query(orm.User).filter(orm.User.name==key).first()
|
orm_user = self.db.query(orm.User).filter(orm.User.name==key).first()
|
||||||
if orm_user is None:
|
if orm_user is None:
|
||||||
raise KeyError("No such user: %s" % name)
|
raise KeyError("No such user: %s" % key)
|
||||||
else:
|
else:
|
||||||
key = orm_user
|
key = orm_user
|
||||||
if isinstance(key, orm.User):
|
if isinstance(key, orm.User):
|
||||||
@@ -75,22 +75,24 @@ class UserDict(dict):
|
|||||||
|
|
||||||
class User(HasTraits):
|
class User(HasTraits):
|
||||||
|
|
||||||
|
@default('log')
|
||||||
def _log_default(self):
|
def _log_default(self):
|
||||||
return app_log
|
return app_log
|
||||||
|
|
||||||
settings = Dict()
|
settings = Dict()
|
||||||
|
|
||||||
db = Any(allow_none=True)
|
db = Any(allow_none=True)
|
||||||
|
@default('db')
|
||||||
def _db_default(self):
|
def _db_default(self):
|
||||||
if self.orm_user:
|
if self.orm_user:
|
||||||
return inspect(self.orm_user).session
|
return inspect(self.orm_user).session
|
||||||
|
@observe('db')
|
||||||
def _db_changed(self, name, old, new):
|
def _db_changed(self, change):
|
||||||
"""Changing db session reacquires ORM User object"""
|
"""Changing db session reacquires ORM User object"""
|
||||||
# db session changed, re-get orm User
|
# db session changed, re-get orm User
|
||||||
if self.orm_user:
|
if self.orm_user:
|
||||||
id = self.orm_user.id
|
id = self.orm_user.id
|
||||||
self.orm_user = new.query(orm.User).filter(orm.User.id==id).first()
|
self.orm_user = change['new'].query(orm.User).filter(orm.User.id==id).first()
|
||||||
self.spawner.db = self.db
|
self.spawner.db = self.db
|
||||||
|
|
||||||
orm_user = None
|
orm_user = None
|
||||||
|
Reference in New Issue
Block a user