Selaa lähdekoodia

Refactor commands.py to use `options`

Makes it easier to add new kwargs later on without having to update all functions. Con: Lack of args checking. Possible solution: Use a namedtuple (with `defaults`) to specify all supported options.

Also: Possibly too generic name. Maybe `apphandler_options` or `app_options`?
Vidar Tonaas Fauske 5 vuotta sitten
vanhempi
commit
102c53303b

+ 86 - 51
jupyterlab/commands.py

@@ -22,6 +22,7 @@ from tempfile import TemporaryDirectory
 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
@@ -287,7 +288,24 @@ def watch_dev(logger=None):
     return package_procs + [wp_proc]
 
 
-def watch(app_dir=None, logger=None, core_config=None):
+def _ensure_options(options, **kwargs):
+    if kwargs and any(v is not None for v in kwargs.values()):
+        warnings.warn(
+            "Direct keyword args to jupyterlab.commands functions are "
+            "deprecated, use the options dict instead: %r" % (kwargs,),
+            DeprecationWarning)
+    logger = kwargs.pop('logger', None)
+    if options:
+        logger = options.pop('logger', logger)
+    logger = _ensure_logger(logger)
+    if options is None:
+        return dict(logger=logger, **kwargs)
+    ret = dict(logger=logger, **kwargs)
+    ret.update(**options)
+    return ret
+
+
+def watch(app_dir=None, logger=None, core_config=None, options=None):
     """Watch the application.
 
     Parameters
@@ -301,40 +319,43 @@ 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)
+    options = _ensure_options(
+        options, app_dir=app_dir, logger=logger, core_config=core_config)
+    _node_check(options['logger'])
+    handler = _AppHandler(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, 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)
+    options = _ensure_options(
+        options, app_dir=app_dir, logger=logger, core_config=core_config)
+    _node_check(options['logger'])
+    handler = _AppHandler(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, 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)
+    options = _ensure_options(
+        options, app_dir=app_dir, logger=logger, core_config=core_config)
+    _node_check(options['logger'])
+    handler = _AppHandler(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, options=None):
     """Update an extension by name, or all extensions.
 
     Either `name` must be given as a string, or `all_` must be `True`.
@@ -342,18 +363,22 @@ def update_extension(name=None, all_=False, app_dir=None, logger=None, core_conf
 
     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)
+    options = _ensure_options(
+        options, app_dir=app_dir, logger=logger, core_config=core_config)
+    _node_check(options['logger'])
+    handler = _AppHandler(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, options=None):
     """Clean the JupyterLab application directory."""
-    logger = _ensure_logger(logger)
-    app_dir = app_dir or get_app_dir()
+    options = _ensure_options(
+        options, app_dir=app_dir, logger=logger)
+    handler = _AppHandler(options)
+    logger = options['logger']
+    app_dir = options.get('app_dir', None) or get_app_dir()
     logger.info('Cleaning %s...', app_dir)
     if app_dir == pjoin(HERE, 'dev'):
         raise ValueError('Cannot clean the dev app')
@@ -368,96 +393,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, 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)
+    options = _ensure_options(
+        options, app_dir=app_dir, logger=logger, core_config=core_config)
+    _node_check(options['logger'])
+    handler = _AppHandler(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, options=None):
     """Get a dictionary of information about the app.
     """
-    handler = _AppHandler(app_dir, logger, core_config=core_config)
+    handler = _AppHandler(_ensure_options(
+        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, 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(
+        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, 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(
+        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, options=None):
     """Check if a JupyterLab extension is enabled or disabled.
     """
-    handler = _AppHandler(app_dir, logger, core_config=core_config)
+    handler = _AppHandler(_ensure_options(
+        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, 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)
+    options = _ensure_options(
+        options, app_dir=app_dir, logger=logger, core_config=core_config)
+    _node_check(options['logger'])
+    handler = _AppHandler(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, options=None):
     """List the extensions.
     """
-    handler = _AppHandler(app_dir, logger, core_config=core_config)
+    handler = _AppHandler(_ensure_options(
+        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, 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(
+        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, 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(
+        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, 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(
+        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, 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(
+        options, app_dir=app_dir, logger=logger, core_config=core_config))
     return handler.latest_compatible_package_versions(names)
 
 
@@ -481,17 +515,18 @@ 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.app_dir = options.get('app_dir', None) or get_app_dir()
+        self.logger = _ensure_logger(options.get('logger'))
+        core_config = options.get('core_config', None)
         self.core_data = (
             core_config._data if core_config else _get_default_core_data()
         )
         self.info = self._get_app_info()
-        self.kill_event = kill_event or Event()
+        self.kill_event = options.get('kill_event', None) or Event()
         # TODO: Make this configurable
         self.registry = 'https://registry.npmjs.org'
 

+ 2 - 2
jupyterlab/extension.py

@@ -38,7 +38,7 @@ def load_config(nbapp):
     )
 
     app_dir = getattr(nbapp, 'app_dir', get_app_dir())
-    info = get_app_info(app_dir)
+    info = get_app_info(options=dict(app_dir=app_dir))
     static_url = info['staticUrl']
     user_settings_dir = getattr(
         nbapp, 'user_settings_dir', get_user_settings_dir()
@@ -188,7 +188,7 @@ def load_jupyter_server_extension(nbapp):
         if dev_mode:
             watch_dev(logger)
         else:
-            watch(app_dir, logger)
+            watch(options=dict(app_dir=app_dir, logger=logger))
             page_config['buildAvailable'] = False
 
         config.cache_files = False

+ 7 - 7
jupyterlab/handlers/build_handler.py

@@ -88,22 +88,22 @@ class Builder(object):
 
     @run_on_executor
     def _run_build_check(self, app_dir, logger, core_config):
-        return build_check(
-            app_dir=app_dir, logger=logger, core_config=core_config)
+        return build_check(options=dict(
+            app_dir=app_dir, logger=logger, core_config=core_config))
 
     @run_on_executor
     def _run_build(self, app_dir, logger, kill_event, core_config):
-        kwargs = dict(
+        options = dict(
             app_dir=app_dir, logger=logger, kill_event=kill_event,
-            core_config=core_config, command='build')
+            core_config=core_config)
         try:
-            return build(**kwargs)
+            return build(command='build', options=options)
         except Exception as e:
             if self._kill_event.is_set():
                 return
             self.log.warn('Build failed, running a clean and rebuild')
-            clean(app_dir)
-            return build(**kwargs)
+            clean(options=options)
+            return build(command='build', options=options)
 
 
 class BuildHandler(APIHandler):

+ 27 - 19
jupyterlab/handlers/extension_manager_handler.py

@@ -37,9 +37,9 @@ def _make_extension_entry(name, description, url, enabled, core, latest_version,
     return ret
 
 
-def _ensure_compat_errors(info, app_dir, logger):
+def _ensure_compat_errors(info, options):
     """Ensure that the app info has compat_errors field"""
-    handler = _AppHandler(app_dir, logger)
+    handler = _AppHandler(options)
     info['compat_errors'] = handler._get_extension_compat()
 
 
@@ -49,9 +49,9 @@ _message_map = {
     'update': re.compile(r'(?P<name>.*) changed from (?P<oldver>.*) to (?P<newver>.*)'),
 }
 
-def _build_check_info(app_dir, logger):
+def _build_check_info(options):
     """Get info about packages scheduled for (un)install/update"""
-    handler = _AppHandler(app_dir, logger)
+    handler = _AppHandler(options)
     messages = handler.build_check(fast=True)
     # Decode the messages into a dict:
     status = {'install': [], 'uninstall': [], 'update': []}
@@ -77,9 +77,10 @@ class ExtensionManager(object):
     @gen.coroutine
     def list_extensions(self):
         """Handle a request for all installed extensions"""
-        info = get_app_info(app_dir=self.app_dir, logger=self.log)
-        build_check_info = _build_check_info(self.app_dir, self.log)
-        _ensure_compat_errors(info, self.app_dir, self.log)
+        options = dict(app_dir=self.app_dir, logger=self.log)
+        info = get_app_info(options=options)
+        build_check_info = _build_check_info(options)
+        _ensure_compat_errors(info, options)
         extensions = []
         # TODO: Ensure loops can run in parallel
         for name, data in info['extensions'].items():
@@ -124,8 +125,9 @@ class ExtensionManager(object):
         """Handle an install/update request"""
         try:
             install_extension(
-                extension, app_dir=self.app_dir, logger=self.log,
-                core_config=self.core_config)
+                extension, options=dict(
+                    app_dir=self.app_dir, logger=self.log,
+                    core_config=self.core_config))
         except ValueError as e:
             raise gen.Return(dict(status='error', message=str(e)))
         raise gen.Return(dict(status='ok',))
@@ -134,24 +136,27 @@ class ExtensionManager(object):
     def uninstall(self, extension):
         """Handle an uninstall request"""
         did_uninstall = uninstall_extension(
-            extension, app_dir=self.app_dir, logger=self.log,
-            core_config=self.core_config)
+            extension, options=dict(
+                app_dir=self.app_dir, logger=self.log,
+                core_config=self.core_config))
         raise gen.Return(dict(status='ok' if did_uninstall else 'error',))
 
     @gen.coroutine
     def enable(self, extension):
         """Handle an enable request"""
         enable_extension(
-            extension, app_dir=self.app_dir, logger=self.log,
-            core_config=self.core_config)
+            extension, options=dict(
+                app_dir=self.app_dir, logger=self.log,
+                core_config=self.core_config))
         raise gen.Return(dict(status='ok',))
 
     @gen.coroutine
     def disable(self, extension):
         """Handle a disable request"""
         disable_extension(
-            extension, app_dir=self.app_dir, logger=self.log,
-            core_config=self.core_config)
+            extension, options=dict(
+                app_dir=self.app_dir, logger=self.log,
+                core_config=self.core_config))
         raise gen.Return(dict(status='ok',))
 
     @gen.coroutine
@@ -189,14 +194,17 @@ class ExtensionManager(object):
     @gen.coroutine
     def _load_outdated(self):
         """Get the latest compatible version"""
-        info = get_app_info(app_dir=self.app_dir, logger=self.log)
+        options = dict(
+            app_dir=self.app_dir,
+            logger=self.log,
+            core_config=self.core_config
+        )
+        info = get_app_info(options=options)
         names = tuple(info['extensions'].keys())
         data = yield self.executor.submit(
             get_latest_compatible_package_versions,
             names,
-            app_dir=self.app_dir,
-            logger=self.log,
-            core_config=self.core_config,
+            options=options
         )
         raise gen.Return(data)
 

+ 7 - 5
jupyterlab/labapp.py

@@ -85,15 +85,17 @@ class LabBuildApp(JupyterApp, DebugLogFileMixin):
         command = ':'.join(parts)
 
         app_dir = self.app_dir or get_app_dir()
+        options = dict(
+            app_dir=app_dir, logger=self.log, core_config=self.core_config
+        )
         self.log.info('JupyterLab %s', version)
         with self.debug_logging():
             if self.pre_clean:
                 self.log.info('Cleaning %s' % app_dir)
-                clean(self.app_dir)
+                clean(options=options)
             self.log.info('Building in %s', app_dir)
-            build(app_dir=app_dir, name=self.name, version=self.version,
-                  command=command, logger=self.log,
-                  core_config=self.core_config)
+            build(name=self.name, version=self.version,
+                  command=command, options=options)
 
 
 clean_aliases = dict(base_aliases)
@@ -116,7 +118,7 @@ class LabCleanApp(JupyterApp):
     app_dir = Unicode('', config=True, help='The app directory to clean')
 
     def start(self):
-        clean(self.app_dir, logger=self.log)
+        clean(options=dict(self.app_dir, logger=self.log))
 
 
 class LabPathApp(JupyterApp):

+ 42 - 35
jupyterlab/labextensions.py

@@ -99,10 +99,10 @@ class BaseExtensionApp(JupyterApp, DebugLogFileMixin):
                 if self.minimize:
                     parts.append('minimize')
                 command = ':'.join(parts)
-
-                build(app_dir=self.app_dir, clean_staging=self.should_clean,
-                      logger=self.log, command=command,
+                options = dict(app_dir=self.app_dir, logger=self.log,
                       core_config=self.core_config)
+                build(clean_staging=self.should_clean,
+                      command=command, options=options)
 
     def run_task(self):
         pass
@@ -114,13 +114,13 @@ class BaseExtensionApp(JupyterApp, DebugLogFileMixin):
 
 class InstallLabExtensionApp(BaseExtensionApp):
     description = """Install labextension(s)
-    
+
      Usage
-    
+
         jupyter labextension install [--pin-version-as <alias,...>] <package...>
-    
+
     This installs JupyterLab extensions similar to yarn add or npm install.
-    
+
     Pass a list of comma seperate names to the --pin-version-as flag
     to use as alises for the packages providers. This is useful to
     install multiple versions of the same extension.
@@ -138,11 +138,13 @@ class InstallLabExtensionApp(BaseExtensionApp):
         return any([
             install_extension(
                 arg,
-                self.app_dir,
-                logger=self.log,
-                core_config=self.core_config,
                 # Pass in pinned alias if we have it
-                pin=pinned_versions[i] if i < len(pinned_versions) else None
+                pin=pinned_versions[i] if i < len(pinned_versions) else None,
+                options=dict(
+                    app_dir=self.app_dir,
+                    logger=self.log,
+                    core_config=self.core_config,
+                )
             )
             for i, arg in enumerate(self.extra_args)
         ])
@@ -159,14 +161,12 @@ class UpdateLabExtensionApp(BaseExtensionApp):
         if not self.all and not self.extra_args:
             self.log.warn('Specify an extension to update, or use --all to update all extensions')
             return False
+        options = dict(app_dir=self.app_dir, logger=self.log,
+            core_config=self.core_config)
         if self.all:
-            return update_extension(
-                all_=True, app_dir=self.app_dir, logger=self.log,
-                core_config=self.core_config)
+            return update_extension(all_=True, options=options)
         return any([
-            update_extension(
-                name=arg, app_dir=self.app_dir, logger=self.log,
-                core_config=self.core_config)
+            update_extension(name=arg, options=options)
             for arg in self.extra_args
         ])
 
@@ -186,8 +186,10 @@ class LinkLabExtensionApp(BaseExtensionApp):
         self.extra_args = self.extra_args or [os.getcwd()]
         return any([
             link_package(
-                arg, self.app_dir, logger=self.log,
-                core_config=self.core_config)
+                arg,
+                options=dict(
+                    self.app_dir, logger=self.log,
+                    core_config=self.core_config))
             for arg in self.extra_args
         ])
 
@@ -199,8 +201,10 @@ class UnlinkLabExtensionApp(BaseExtensionApp):
         self.extra_args = self.extra_args or [os.getcwd()]
         return any([
             unlink_package(
-                arg, self.app_dir, logger=self.log,
-                core_config=self.core_config)
+                arg,
+                options=dict(
+                    self.app_dir, logger=self.log,
+                    core_config=self.core_config))
             for arg in self.extra_args
         ])
 
@@ -216,8 +220,10 @@ class UninstallLabExtensionApp(BaseExtensionApp):
         self.extra_args = self.extra_args or [os.getcwd()]
         return any([
             uninstall_extension(
-                arg, all_=self.all, app_dir=self.app_dir, logger=self.log,
-                core_config=self.core_config)
+                arg, all_=self.all,
+                options=dict(
+                    app_dir=self.app_dir, logger=self.log,
+                    core_config=self.core_config))
             for arg in self.extra_args
         ])
 
@@ -226,26 +232,26 @@ class ListLabExtensionsApp(BaseExtensionApp):
     description = "List the installed labextensions"
 
     def run_task(self):
-        list_extensions(
-            self.app_dir, logger=self.log, core_config=self.core_config)
+        list_extensions(options=dict(
+            self.app_dir, logger=self.log, core_config=self.core_config))
 
 
 class EnableLabExtensionsApp(BaseExtensionApp):
     description = "Enable labextension(s) by name"
 
     def run_task(self):
-        [enable_extension(
-            arg, self.app_dir, logger=self.log, core_config=self.core_config)
-         for arg in self.extra_args]
+        options = dict(
+            app_dir=self.app_dir, logger=self.log, core_config=self.core_config)
+        [enable_extension(arg, options=options) for arg in self.extra_args]
 
 
 class DisableLabExtensionsApp(BaseExtensionApp):
     description = "Disable labextension(s) by name"
 
     def run_task(self):
-        [disable_extension(
-            arg, self.app_dir, logger=self.log, core_config=self.core_config)
-         for arg in self.extra_args]
+        options = dict(
+            app_dir=self.app_dir, logger=self.log, core_config=self.core_config)
+        [disable_extension(arg, options=options) for arg in self.extra_args]
 
 
 class CheckLabExtensionsApp(BaseExtensionApp):
@@ -256,12 +262,13 @@ class CheckLabExtensionsApp(BaseExtensionApp):
         help="Whether it should check only if the extensions is installed")
 
     def run_task(self):
+        options = dict(
+            app_dir=self.app_dir, logger=self.log, core_config=self.core_config)
         all_enabled = all(
             check_extension(
-                arg, self.app_dir,
-                self.should_check_installed_only,
-                logger=self.log,
-                core_config=self.core_config)
+                arg,
+                installed=self.should_check_installed_only,
+                options=options)
             for arg in self.extra_args)
         if not all_enabled:
             self.exit(1)

+ 80 - 72
jupyterlab/tests/test_jupyterlab.py

@@ -138,17 +138,17 @@ class TestExtension(TestCase):
         assert install_extension(self.mock_extension) is True
         path = pjoin(self.app_dir, 'extensions', '*.tgz')
         assert glob.glob(path)
-        extensions = get_app_info(self.app_dir)['extensions']
+        extensions = get_app_info()['extensions']
         name = self.pkg_names['extension']
         assert name in extensions
         assert check_extension(name)
 
     def test_install_twice(self):
         assert install_extension(self.mock_extension) is True
-        path = pjoin(commands.get_app_dir(), 'extensions', '*.tgz')
+        path = pjoin(self.app_dir, 'extensions', '*.tgz')
         assert install_extension(self.mock_extension) is True
         assert glob.glob(path)
-        extensions = get_app_info(self.app_dir)['extensions']
+        extensions = get_app_info()['extensions']
         name = self.pkg_names['extension']
         assert name in extensions
         assert check_extension(name)
@@ -156,11 +156,11 @@ class TestExtension(TestCase):
     def test_install_mime_renderer(self):
         install_extension(self.mock_mimeextension)
         name = self.pkg_names['mimeextension']
-        assert name in get_app_info(self.app_dir)['extensions']
+        assert name in get_app_info()['extensions']
         assert check_extension(name)
 
         assert uninstall_extension(name) is True
-        assert name not in get_app_info(self.app_dir)['extensions']
+        assert name not in get_app_info()['extensions']
         assert not check_extension(name)
 
     def test_install_incompatible(self):
@@ -175,7 +175,7 @@ class TestExtension(TestCase):
             install_extension(path)
         with open(pjoin(path, 'package.json')) as fid:
             data = json.load(fid)
-        extensions = get_app_info(self.app_dir)['extensions']
+        extensions = get_app_info()['extensions']
         name = data['name']
         assert name not in extensions
         assert not check_extension(name)
@@ -200,7 +200,7 @@ class TestExtension(TestCase):
         assert uninstall_extension(self.pkg_names['extension']) is True
         path = pjoin(self.app_dir, 'extensions', '*.tgz')
         assert not glob.glob(path)
-        extensions = get_app_info(self.app_dir)['extensions']
+        extensions = get_app_info()['extensions']
         assert name not in extensions
         assert not check_extension(name)
 
@@ -212,7 +212,7 @@ class TestExtension(TestCase):
         assert check_extension(ext_name) is True
         assert check_extension(mime_ext_name) is True
         assert uninstall_extension(all_=True) is True
-        extensions = get_app_info(self.app_dir)['extensions']
+        extensions = get_app_info()['extensions']
         assert ext_name not in extensions
         assert mime_ext_name not in extensions
 
@@ -221,7 +221,7 @@ class TestExtension(TestCase):
     def test_uninstall_core_extension(self):
         assert uninstall_extension('@jupyterlab/console-extension') is True
         app_dir = self.app_dir
-        build(app_dir)
+        build()
         with open(pjoin(app_dir, 'staging', 'package.json')) as fid:
             data = json.load(fid)
         extensions = data['jupyterlab']['extensions']
@@ -229,7 +229,7 @@ class TestExtension(TestCase):
         assert not check_extension('@jupyterlab/console-extension')
 
         assert install_extension('@jupyterlab/console-extension') is True
-        build(app_dir)
+        build()
         with open(pjoin(app_dir, 'staging', 'package.json')) as fid:
             data = json.load(fid)
         extensions = data['jupyterlab']['extensions']
@@ -245,7 +245,7 @@ class TestExtension(TestCase):
         assert install_extension(self.pinned_packages[0], pin=NAMES[0])
         assert install_extension(self.pinned_packages[1], pin=NAMES[1])
 
-        extensions = get_app_info(self.app_dir)['extensions']
+        extensions = get_app_info()['extensions']
         assert NAMES[0] in extensions
         assert NAMES[1] in extensions
         assert check_extension(NAMES[0])
@@ -255,7 +255,7 @@ class TestExtension(TestCase):
         assert uninstall_extension(NAMES[0])
         assert uninstall_extension(NAMES[1])
 
-        extensions = get_app_info(self.app_dir)['extensions']
+        extensions = get_app_info()['extensions']
         assert NAMES[0] not in extensions
         assert NAMES[1] not in extensions
         assert not check_extension(NAMES[0])
@@ -292,28 +292,26 @@ class TestExtension(TestCase):
         path = self.mock_extension
         name = self.pkg_names['extension']
         link_package(path)
-        app_dir = self.app_dir
-        linked = get_app_info(app_dir)['linked_packages']
+        linked = get_app_info()['linked_packages']
         assert name not in linked
-        assert name in get_app_info(app_dir)['extensions']
+        assert name in get_app_info()['extensions']
         assert check_extension(name)
         assert unlink_package(path) is True
-        linked = get_app_info(app_dir)['linked_packages']
+        linked = get_app_info()['linked_packages']
         assert name not in linked
-        assert name not in get_app_info(app_dir)['extensions']
+        assert name not in get_app_info()['extensions']
         assert not check_extension(name)
 
     def test_link_package(self):
         path = self.mock_package
         name = self.pkg_names['package']
         assert link_package(path) is True
-        app_dir = self.app_dir
-        linked = get_app_info(app_dir)['linked_packages']
+        linked = get_app_info()['linked_packages']
         assert name in linked
-        assert name not in get_app_info(app_dir)['extensions']
+        assert name not in get_app_info()['extensions']
         assert check_extension(name)
         assert unlink_package(path)
-        linked = get_app_info(app_dir)['linked_packages']
+        linked = get_app_info()['linked_packages']
         assert name not in linked
         assert not check_extension(name)
 
@@ -321,7 +319,7 @@ class TestExtension(TestCase):
         target = self.mock_package
         assert link_package(target) is True
         assert unlink_package(target) is True
-        linked = get_app_info(self.app_dir)['linked_packages']
+        linked = get_app_info()['linked_packages']
         name = self.pkg_names['package']
         assert name not in linked
         assert not check_extension(name)
@@ -332,49 +330,52 @@ class TestExtension(TestCase):
 
     def test_app_dir(self):
         app_dir = self.tempdir()
+        options = dict(app_dir=app_dir)
 
-        assert install_extension(self.mock_extension, app_dir) is True
+        assert install_extension(self.mock_extension, options=options) is True
         path = pjoin(app_dir, 'extensions', '*.tgz')
         assert glob.glob(path)
-        extensions = get_app_info(app_dir)['extensions']
+        extensions = get_app_info(options=options)['extensions']
         ext_name = self.pkg_names['extension']
         assert ext_name in extensions
-        assert check_extension(ext_name, app_dir)
+        assert check_extension(ext_name, options=options)
 
-        assert uninstall_extension(self.pkg_names['extension'], app_dir) is True
+        assert uninstall_extension(self.pkg_names['extension'], options=options) is True
         path = pjoin(app_dir, 'extensions', '*.tgz')
         assert not glob.glob(path)
-        extensions = get_app_info(app_dir)['extensions']
+        extensions = get_app_info(options=options)['extensions']
         assert ext_name not in extensions
-        assert not check_extension(ext_name, app_dir)
+        assert not check_extension(ext_name, options=options)
 
-        assert link_package(self.mock_package, app_dir) is True
-        linked = get_app_info(app_dir)['linked_packages']
+        assert link_package(self.mock_package, options=options) is True
+        linked = get_app_info(options=options)['linked_packages']
         pkg_name = self.pkg_names['package']
         assert pkg_name in linked
-        assert check_extension(pkg_name, app_dir)
+        assert check_extension(pkg_name, options=options)
 
-        assert unlink_package(self.mock_package, app_dir) is True
-        linked = get_app_info(app_dir)['linked_packages']
+        assert unlink_package(self.mock_package, options=options) is True
+        linked = get_app_info(options=options)['linked_packages']
         assert pkg_name not in linked
-        assert not check_extension(pkg_name, app_dir)
+        assert not check_extension(pkg_name, options=options)
 
     def test_app_dir_use_sys_prefix(self):
         app_dir = self.tempdir()
+        options = dict(app_dir=app_dir)
         if os.path.exists(self.app_dir):
             os.removedirs(self.app_dir)
 
         assert install_extension(self.mock_extension) is True
         path = pjoin(app_dir, 'extensions', '*.tgz')
         assert not glob.glob(path)
-        extensions = get_app_info(app_dir)['extensions']
+        extensions = get_app_info(options=options)['extensions']
         ext_name = self.pkg_names['extension']
         assert ext_name in extensions
-        assert check_extension(ext_name, app_dir)
+        assert check_extension(ext_name, options=options)
 
     def test_app_dir_shadowing(self):
         app_dir = self.tempdir()
         sys_dir = self.app_dir
+        app_options = dict(app_dir=app_dir)
         if os.path.exists(sys_dir):
             os.removedirs(sys_dir)
 
@@ -383,30 +384,30 @@ class TestExtension(TestCase):
         assert glob.glob(sys_path)
         app_path = pjoin(app_dir, 'extensions', '*.tgz')
         assert not glob.glob(app_path)
-        extensions = get_app_info(app_dir)['extensions']
+        extensions = get_app_info(options=app_options)['extensions']
         ext_name = self.pkg_names['extension']
         assert ext_name in extensions
-        assert check_extension(ext_name, app_dir)
+        assert check_extension(ext_name, options=app_options)
 
-        assert install_extension(self.mock_extension, app_dir) is True
+        assert install_extension(self.mock_extension, options=app_options) is True
         assert glob.glob(app_path)
-        extensions = get_app_info(app_dir)['extensions']
+        extensions = get_app_info(options=app_options)['extensions']
         assert ext_name in extensions
-        assert check_extension(ext_name, app_dir)
+        assert check_extension(ext_name, options=app_options)
 
-        assert uninstall_extension(self.pkg_names['extension'], app_dir) is True
+        assert uninstall_extension(self.pkg_names['extension'], options=app_options) is True
         assert not glob.glob(app_path)
         assert glob.glob(sys_path)
-        extensions = get_app_info(app_dir)['extensions']
+        extensions = get_app_info(options=app_options)['extensions']
         assert ext_name in extensions
-        assert check_extension(ext_name, app_dir)
+        assert check_extension(ext_name, options=app_options)
 
-        assert uninstall_extension(self.pkg_names['extension'], app_dir) is True
+        assert uninstall_extension(self.pkg_names['extension'], options=app_options) is True
         assert not glob.glob(app_path)
         assert not glob.glob(sys_path)
-        extensions = get_app_info(app_dir)['extensions']
+        extensions = get_app_info(options=app_options)['extensions']
         assert ext_name not in extensions
-        assert not check_extension(ext_name, app_dir)
+        assert not check_extension(ext_name, options=app_options)
 
     @pytest.mark.slow
     def test_build(self):
@@ -449,6 +450,13 @@ class TestExtension(TestCase):
         core_config.clear_packages()
         logger = logging.getLogger('jupyterlab_test_logger')
         logger.setLevel('DEBUG')
+        app_dir = self.tempdir()
+        options = dict(
+            app_dir=app_dir,
+            core_config=core_config,
+            logger=logger,
+        )
+
         extensions = (
             '@jupyterlab/application-extension',
             '@jupyterlab/apputils-extension',
@@ -466,16 +474,16 @@ class TestExtension(TestCase):
             semver = default_config.singletons[name]
             core_config.add(name, semver)
 
-        assert install_extension(self.mock_extension) is True
-        build(core_config=core_config, logger=logger)
+        assert install_extension(self.mock_extension, options=options) is True
+        build(options=options)
 
         # check static directory.
-        entry = pjoin(self.app_dir, 'static', 'index.out.js')
+        entry = pjoin(app_dir, 'static', 'index.out.js')
         with open(entry) as fid:
             data = fid.read()
         assert self.pkg_names['extension'] in data
 
-        pkg = pjoin(self.app_dir, 'static', 'package.json')
+        pkg = pjoin(app_dir, 'static', 'package.json')
         with open(pkg) as fid:
             data = json.load(fid)
         assert list(data['jupyterlab']['extensions'].keys()) == [
@@ -497,37 +505,37 @@ class TestExtension(TestCase):
         load_jupyter_server_extension(app)
 
     def test_disable_extension(self):
-        app_dir = self.tempdir()
-        assert install_extension(self.mock_extension, app_dir) is True
-        assert disable_extension(self.pkg_names['extension'], app_dir) is True
-        info = get_app_info(app_dir)
+        options = dict(app_dir=self.tempdir())
+        assert install_extension(self.mock_extension, options=options) is True
+        assert disable_extension(self.pkg_names['extension'], options=options) is True
+        info = get_app_info(options=options)
         name = self.pkg_names['extension']
         assert name in info['disabled']
-        assert not check_extension(name, app_dir)
-        assert check_extension(name, app_dir, True)
-        assert disable_extension('@jupyterlab/notebook-extension', app_dir) is True
-        info = get_app_info(app_dir)
+        assert not check_extension(name, options=options)
+        assert check_extension(name, installed=True, options=options)
+        assert disable_extension('@jupyterlab/notebook-extension', options=options) is True
+        info = get_app_info(options=options)
         assert '@jupyterlab/notebook-extension' in info['disabled']
-        assert not check_extension('@jupyterlab/notebook-extension', app_dir)
-        assert check_extension('@jupyterlab/notebook-extension', app_dir, True)
+        assert not check_extension('@jupyterlab/notebook-extension', options=options)
+        assert check_extension('@jupyterlab/notebook-extension', installed=True, options=options)
         assert name in info['disabled']
-        assert not check_extension(name, app_dir)
-        assert check_extension(name, app_dir, True)
+        assert not check_extension(name, options=options)
+        assert check_extension(name, installed=True, options=options)
 
     def test_enable_extension(self):
-        app_dir = self.tempdir()
-        assert install_extension(self.mock_extension, app_dir) is True
-        assert disable_extension(self.pkg_names['extension'], app_dir) is True
-        assert enable_extension(self.pkg_names['extension'], app_dir) is True
-        info = get_app_info(app_dir)
+        options = dict(app_dir=self.tempdir())
+        assert install_extension(self.mock_extension, options=options) is True
+        assert disable_extension(self.pkg_names['extension'], options=options) is True
+        assert enable_extension(self.pkg_names['extension'], options=options) is True
+        info = get_app_info(options=options)
         name = self.pkg_names['extension']
         assert name not in info['disabled']
-        assert check_extension(name, app_dir)
-        assert disable_extension('@jupyterlab/notebook-extension', app_dir) is True
+        assert check_extension(name, options=options)
+        assert disable_extension('@jupyterlab/notebook-extension', options=options) is True
         assert name not in info['disabled']
-        assert check_extension(name, app_dir)
+        assert check_extension(name, options=options)
         assert '@jupyterlab/notebook-extension' not in info['disabled']
-        assert not check_extension('@jupyterlab/notebook-extension', app_dir)
+        assert not check_extension('@jupyterlab/notebook-extension', options=options)
 
     @pytest.mark.slow
     def test_build_check(self):