Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jupyter-server/jupyter_server
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.15.1
Choose a base ref
...
head repository: jupyter-server/jupyter_server
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 9711822e157bd2ff2d4f8abe4c12a013223230e0
Choose a head ref
  • 3 commits
  • 6 files changed
  • 3 contributors

Commits on Mar 14, 2022

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    deb3d90 View commit details
  2. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    0d8227a View commit details
  3. Server extension paths (#730)

    minrk authored Mar 14, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    9711822 View commit details
10 changes: 5 additions & 5 deletions .github/workflows/downstream.yml
Original file line number Diff line number Diff line change
@@ -16,11 +16,11 @@ jobs:
- name: Base Setup
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1

- name: Test nbclassic
uses: jupyterlab/maintainer-tools/.github/actions/downstream-test@v1
with:
package_name: nbclassic
test_command: pytest --pyargs nbclassic
# - name: Test nbclassic
# uses: jupyterlab/maintainer-tools/.github/actions/downstream-test@v1
# with:
# package_name: nbclassic
# test_command: pytest --pyargs nbclassic

- name: Test jupyterlab_server
uses: jupyterlab/maintainer-tools/.github/actions/downstream-test@v1
21 changes: 20 additions & 1 deletion jupyter_server/auth/decorator.py
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
"""
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
import warnings
from functools import wraps
from typing import Callable
from typing import Optional
@@ -13,6 +14,20 @@
from .utils import HTTP_METHOD_TO_AUTH_ACTION


def raise_no_authorizer_warning():
warnings.warn(
"The Tornado web application does not have an 'authorizer' defined "
"in its settings. In future releases of jupyter_server, this will "
"be a required key for all subclasses of `JupyterHandler`. For an "
"example, see the jupyter_server source code for how to "
"add an authorizer to the tornado settings: "
"https://github.com/jupyter-server/jupyter_server/blob/"
"653740cbad7ce0c8a8752ce83e4d3c2c754b13cb/jupyter_server/serverapp.py"
"#L234-L256",
# stacklevel=2
)


def authorized(
action: Optional[Union[str, Callable]] = None,
resource: Optional[str] = None,
@@ -61,7 +76,11 @@ def inner(self, *args, **kwargs):
raise HTTPError(status_code=403, log_message=message)
# If the user is allowed to do this action,
# call the method.
if self.authorizer.is_authorized(self, user, action, resource):
if not self.authorizer:
with warnings.catch_warnings():
warnings.simplefilter("once")
raise_no_authorizer_warning()
elif self.authorizer.is_authorized(self, user, action, resource):
return method(self, *args, **kwargs)
# else raise an exception.
else:
2 changes: 1 addition & 1 deletion jupyter_server/base/handlers.py
Original file line number Diff line number Diff line change
@@ -193,7 +193,7 @@ def login_available(self):

@property
def authorizer(self):
return self.settings["authorizer"]
return self.settings.get("authorizer")


class JupyterHandler(AuthenticatedHandler):
21 changes: 19 additions & 2 deletions jupyter_server/extension/application.py
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@
from traitlets import default
from traitlets import Dict
from traitlets import HasTraits
from traitlets import Instance
from traitlets import List
from traitlets import Unicode
from traitlets.config import Config
@@ -103,7 +104,7 @@ def _prepare_templates(self):
loader=FileSystemLoader(self.template_paths),
extensions=["jinja2.ext.i18n"],
autoescape=True,
**self.jinja2_options
**self.jinja2_options,
)

# Add the jinja2 environment for this extension to the tornado settings.
@@ -162,6 +163,12 @@ class method. This method can be set as a entry_point in
def _default_open_browser(self):
return self.serverapp.config["ServerApp"].get("open_browser", True)

@property
def config_file_paths(self):
"""Look on the same path as our parent for config files"""
# rely on parent serverapp, which should control all config loading
return self.serverapp.config_file_paths

# The extension name used to name the jupyter config
# file, jupyter_{name}_config.
# This should also match the jupyter subcommand used to launch
@@ -200,7 +207,17 @@ def _default_url(self):
]

# A ServerApp is not defined yet, but will be initialized below.
serverapp = None
serverapp = Instance(ServerApp)

@default("serverapp")
def _default_serverapp(self):
# load the current global instance, if any
if ServerApp.initialized():
return ServerApp.instance()
else:
# serverapp accessed before it was defined,
# declare an empty one
return ServerApp()

_log_formatter_cls = LogFormatter

7 changes: 1 addition & 6 deletions jupyter_server/serverapp.py
Original file line number Diff line number Diff line change
@@ -104,7 +104,6 @@
base_flags,
base_aliases,
)
from jupyter_core.paths import jupyter_config_path
from jupyter_client import KernelManager
from jupyter_client.kernelspec import KernelSpecManager
from jupyter_client.session import Session
@@ -2154,11 +2153,7 @@ def find_server_extensions(self):
# This enables merging on keys, which we want for extension enabling.
# Regular config loading only merges at the class level,
# so each level clobbers the previous.
config_paths = jupyter_config_path()
if self.config_dir not in config_paths:
# add self.config_dir to the front, if set manually
config_paths.insert(0, self.config_dir)
manager = ExtensionConfigManager(read_config_path=config_paths)
manager = ExtensionConfigManager(read_config_path=self.config_file_paths)
extensions = manager.get_jpserver_extensions()

for modulename, enabled in sorted(extensions.items()):
8 changes: 8 additions & 0 deletions tests/extension/test_app.py
Original file line number Diff line number Diff line change
@@ -69,6 +69,14 @@ def test_extensionapp_load_config_file(
assert mock_extension.mock_trait == "config from file"


def test_extensionapp_no_parent():
# make sure we can load config files, even when serverapp is not passed
# relevant for e.g. shortcuts to config-loading
app = MockExtensionApp()
assert isinstance(app.config_file_paths, list)
assert app.serverapp is not None


OPEN_BROWSER_COMBINATIONS = (
(True, {}),
(True, {"ServerApp": {"open_browser": True}}),