Skip to content

Commit

Permalink
Merge pull request #7079 from vidartf/commands-options
Browse files Browse the repository at this point in the history
Commands options
  • Loading branch information
blink1073 committed Sep 9, 2019
2 parents c027a58 + 4a9807c commit 735dffc
Show file tree
Hide file tree
Showing 10 changed files with 394 additions and 237 deletions.
35 changes: 35 additions & 0 deletions conftest.py
@@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-

# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.

import pytest

def pytest_addoption(parser):
"""
Adds flags for py.test.
This is called by the pytest API
"""
group = parser.getgroup("general")
group.addoption('--quick', action='store_true',
help="Skip slow tests")
group.addoption('--slow', action='store_true',
help="Run only slow tests")


def pytest_configure(config):
config.addinivalue_line("markers", "slow: mark test as slow to run")


def pytest_collection_modifyitems(config, items):
if config.getoption("--quick"):
skip_slow = pytest.mark.skip(reason="skipping slow test")
for item in items:
if "slow" in item.keywords:
item.add_marker(skip_slow)
elif config.getoption("--slow"):
skip_quick = pytest.mark.skip(reason="skipping non-slow test")
for item in items:
if "slow" not in item.keywords:
item.add_marker(skip_quick)
186 changes: 129 additions & 57 deletions jupyterlab/commands.py
Expand Up @@ -22,14 +22,16 @@
from threading import Event
from urllib.request import Request, urlopen, urljoin, quote
from urllib.error import URLError
import warnings

from jupyter_core.paths import jupyter_config_path
from jupyterlab_server.process import which, Process, WatchHelper, list2cmdline
from notebook.nbextensions import GREEN_ENABLED, GREEN_OK, RED_DISABLED, RED_X
from traitlets import HasTraits, Bool, Unicode, Instance, default

from .semver import Range, gte, lt, lte, gt, make_semver
from .jlpmapp import YARN_PATH, HERE
from .coreconfig import _get_default_core_data
from .coreconfig import _get_default_core_data, CoreConfig


# The regex for expecting the webpack output.
Expand Down Expand Up @@ -67,7 +69,7 @@ def __init__(self, cmd, logger=None, cwd=None, kill_event=None,
if kill_event and kill_event.is_set():
raise ValueError('Process aborted')

self.logger = logger = logger or logging.getLogger('jupyterlab')
self.logger = _ensure_logger(logger)
self._last_line = ''
self.cmd = cmd
self.logger.debug('> ' + list2cmdline(cmd))
Expand Down Expand Up @@ -287,7 +289,63 @@ def watch_dev(logger=None):
return package_procs + [wp_proc]


def watch(app_dir=None, logger=None, core_config=None):
class AppOptions(HasTraits):
"""Options object for build system"""

def __init__(self, logger=None, core_config=None, **kwargs):
if core_config is not None:
kwargs['core_config'] = core_config
if logger is not None:
kwargs['logger'] = logger
super(AppOptions, self).__init__(**kwargs)

app_dir = Unicode(help='The application directory')

use_sys_dir = Bool(
True,
help=('Whether to shadow the default app_dir if that is set to a '
'non-default value'))

logger = Instance(logging.Logger, help='The logger to use')

core_config = Instance(CoreConfig, help='Configuration for core data')

kill_event = Instance(Event, args=(), help='Event for aborting call')

@default('logger')
def _default_logger(self):
return logging.getLogger('jupyterlab')

# These defaults need to be dynamic to pick up
# any changes to env vars:
@default('app_dir')
def _default_app_dir(self):
return get_app_dir()

@default('core_config')
def _default_core_config(self):
return CoreConfig()


def _ensure_options(options, **kwargs):
"""Helper to use deprecated kwargs for AppOption"""
# Filter out default-value kwargs
kwargs = dict(filter(lambda item: item[1] is not None, kwargs.items()))
# Warn for deprecated kwargs usage
if kwargs:
warnings.warn(
"Direct keyword args to jupyterlab.commands functions are "
"deprecated, use the options argument instead: %r" % (kwargs,),
DeprecationWarning)
if options is None:
return AppOptions(**kwargs)
# Also support mixed use of options and kwargs:
opt_args = {name: getattr(options, name) for name in options.trait_names()}
kwargs.update(**opt_args)
return AppOptions(**kwargs)


def watch(app_dir=None, logger=None, core_config=None, app_options=None):
"""Watch the application.
Parameters
Expand All @@ -301,59 +359,66 @@ def watch(app_dir=None, logger=None, core_config=None):
-------
A list of processes to run asynchronously.
"""
logger = _ensure_logger(logger)
_node_check(logger)
handler = _AppHandler(app_dir, logger, core_config=core_config)
app_options = _ensure_options(
app_options, app_dir=app_dir, logger=logger, core_config=core_config)
_node_check(app_options.logger)
handler = _AppHandler(app_options)
return handler.watch()



def install_extension(extension, app_dir=None, logger=None, core_config=None, pin=None):
def install_extension(extension, app_dir=None, logger=None, core_config=None, pin=None, app_options=None):
"""Install an extension package into JupyterLab.
The extension is first validated.
Returns `True` if a rebuild is recommended, `False` otherwise.
"""
logger = _ensure_logger(logger)
_node_check(logger)
handler = _AppHandler(app_dir, logger, core_config=core_config)
app_options = _ensure_options(
app_options, app_dir=app_dir, logger=logger, core_config=core_config)
_node_check(app_options.logger)
handler = _AppHandler(app_options)
return handler.install_extension(extension, pin=pin)


def uninstall_extension(name=None, app_dir=None, logger=None, all_=False, core_config=None):
def uninstall_extension(name=None, app_dir=None, logger=None, all_=False, core_config=None, app_options=None):
"""Uninstall an extension by name or path.
Returns `True` if a rebuild is recommended, `False` otherwise.
"""
logger = _ensure_logger(logger)
_node_check(logger)
handler = _AppHandler(app_dir, logger, core_config=core_config)
app_options = _ensure_options(
app_options, app_dir=app_dir, logger=logger, core_config=core_config)
_node_check(app_options.logger)
handler = _AppHandler(app_options)
if all_ is True:
return handler.uninstall_all_extensions()
return handler.uninstall_extension(name)


def update_extension(name=None, all_=False, app_dir=None, logger=None, core_config=None):
def update_extension(name=None, all_=False, app_dir=None, logger=None, core_config=None, app_options=None):
"""Update an extension by name, or all extensions.
Either `name` must be given as a string, or `all_` must be `True`.
If `all_` is `True`, the value of `name` is ignored.
Returns `True` if a rebuild is recommended, `False` otherwise.
"""
logger = _ensure_logger(logger)
_node_check(logger)
handler = _AppHandler(app_dir, logger, core_config=core_config)
app_options = _ensure_options(
app_options, app_dir=app_dir, logger=logger, core_config=core_config)
_node_check(app_options.logger)
handler = _AppHandler(app_options)
if all_ is True:
return handler.update_all_extensions()
return handler.update_extension(name)


def clean(app_dir=None, logger=None):
def clean(app_dir=None, logger=None, app_options=None):
"""Clean the JupyterLab application directory."""
logger = _ensure_logger(logger)
app_dir = app_dir or get_app_dir()
app_options = _ensure_options(
app_options, app_dir=app_dir, logger=logger)
handler = _AppHandler(app_options)
logger = app_options.logger
app_dir = app_options.app_dir
logger.info('Cleaning %s...', app_dir)
if app_dir == pjoin(HERE, 'dev'):
raise ValueError('Cannot clean the dev app')
Expand All @@ -368,96 +433,105 @@ def clean(app_dir=None, logger=None):

def build(app_dir=None, name=None, version=None, static_url=None,
logger=None, command='build:prod', kill_event=None,
clean_staging=False, core_config=None):
clean_staging=False, core_config=None, app_options=None):
"""Build the JupyterLab application.
"""
logger = _ensure_logger(logger)
_node_check(logger)
handler = _AppHandler(app_dir, logger, kill_event=kill_event, core_config=core_config)
app_options = _ensure_options(
app_options, app_dir=app_dir, logger=logger, core_config=core_config)
_node_check(app_options.logger)
handler = _AppHandler(app_options)
return handler.build(name=name, version=version, static_url=static_url,
command=command, clean_staging=clean_staging)


def get_app_info(app_dir=None, logger=None, core_config=None):
def get_app_info(app_dir=None, logger=None, core_config=None, app_options=None):
"""Get a dictionary of information about the app.
"""
handler = _AppHandler(app_dir, logger, core_config=core_config)
handler = _AppHandler(_ensure_options(
app_options, app_dir=app_dir, logger=logger, core_config=core_config))
return handler.info


def enable_extension(extension, app_dir=None, logger=None, core_config=None):
def enable_extension(extension, app_dir=None, logger=None, core_config=None, app_options=None):
"""Enable a JupyterLab extension.
Returns `True` if a rebuild is recommended, `False` otherwise.
"""
handler = _AppHandler(app_dir, logger, core_config=core_config)
handler = _AppHandler(_ensure_options(
app_options, app_dir=app_dir, logger=logger, core_config=core_config))
return handler.toggle_extension(extension, False)


def disable_extension(extension, app_dir=None, logger=None, core_config=None):
def disable_extension(extension, app_dir=None, logger=None, core_config=None, app_options=None):
"""Disable a JupyterLab package.
Returns `True` if a rebuild is recommended, `False` otherwise.
"""
handler = _AppHandler(app_dir, logger, core_config=core_config)
handler = _AppHandler(_ensure_options(
app_options, app_dir=app_dir, logger=logger, core_config=core_config))
return handler.toggle_extension(extension, True)


def check_extension(extension, app_dir=None, installed=False, logger=None, core_config=None):
def check_extension(extension, app_dir=None, installed=False, logger=None, core_config=None, app_options=None):
"""Check if a JupyterLab extension is enabled or disabled.
"""
handler = _AppHandler(app_dir, logger, core_config=core_config)
handler = _AppHandler(_ensure_options(
app_options, app_dir=app_dir, logger=logger, core_config=core_config))
return handler.check_extension(extension, installed)


def build_check(app_dir=None, logger=None, core_config=None):
def build_check(app_dir=None, logger=None, core_config=None, app_options=None):
"""Determine whether JupyterLab should be built.
Returns a list of messages.
"""
logger = _ensure_logger(logger)
_node_check(logger)
handler = _AppHandler(app_dir, logger, core_config=core_config)
app_options = _ensure_options(
app_options, app_dir=app_dir, logger=logger, core_config=core_config)
_node_check(app_options.logger)
handler = _AppHandler(app_options)
return handler.build_check()


def list_extensions(app_dir=None, logger=None, core_config=None):
def list_extensions(app_dir=None, logger=None, core_config=None, app_options=None):
"""List the extensions.
"""
handler = _AppHandler(app_dir, logger, core_config=core_config)
handler = _AppHandler(_ensure_options(
app_options, app_dir=app_dir, logger=logger, core_config=core_config))
return handler.list_extensions()


def link_package(path, app_dir=None, logger=None, core_config=None):
def link_package(path, app_dir=None, logger=None, core_config=None, app_options=None):
"""Link a package against the JupyterLab build.
Returns `True` if a rebuild is recommended, `False` otherwise.
"""
handler = _AppHandler(app_dir, logger, core_config=core_config)
handler = _AppHandler(_ensure_options(
app_options, app_dir=app_dir, logger=logger, core_config=core_config))
return handler.link_package(path)


def unlink_package(package, app_dir=None, logger=None, core_config=None):
def unlink_package(package, app_dir=None, logger=None, core_config=None, app_options=None):
"""Unlink a package from JupyterLab by path or name.
Returns `True` if a rebuild is recommended, `False` otherwise.
"""
handler = _AppHandler(app_dir, logger, core_config=core_config)
handler = _AppHandler(_ensure_options(
app_options, app_dir=app_dir, logger=logger, core_config=core_config))
return handler.unlink_package(package)


def get_app_version(app_dir=None, core_config=None):
def get_app_version(app_dir=None, core_config=None, app_options=None):
"""Get the application version."""
app_dir = app_dir or get_app_dir()
handler = _AppHandler(app_dir, core_config=core_config)
handler = _AppHandler(_ensure_options(
app_options, app_dir=app_dir, core_config=core_config))
return handler.info['version']


def get_latest_compatible_package_versions(names, app_dir=None, logger=None, core_config=None):
def get_latest_compatible_package_versions(names, app_dir=None, logger=None, core_config=None, app_options=None):
"""Get the latest compatible version of a list of packages.
"""
app_dir = app_dir or get_app_dir()
handler = _AppHandler(app_dir, logger, core_config=core_config)
handler = _AppHandler(_ensure_options(
app_options, app_dir=app_dir, logger=logger, core_config=core_config))
return handler.latest_compatible_package_versions(names)


Expand All @@ -481,17 +555,15 @@ def read_package(target):

class _AppHandler(object):

def __init__(self, app_dir, logger=None, kill_event=None, core_config=None):
def __init__(self, options):
"""Create a new _AppHandler object
"""
self.app_dir = app_dir or get_app_dir()
self.sys_dir = get_app_dir()
self.logger = _ensure_logger(logger)
self.core_data = (
core_config._data if core_config else _get_default_core_data()
)
self.app_dir = options.app_dir
self.sys_dir = get_app_dir() if options.use_sys_dir else self.app_dir
self.logger = options.logger
self.core_data = options.core_config._data
self.info = self._get_app_info()
self.kill_event = kill_event or Event()
self.kill_event = options.kill_event
# TODO: Make this configurable
self.registry = 'https://registry.npmjs.org'

Expand Down

0 comments on commit 735dffc

Please sign in to comment.