mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-17 23:13:00 +00:00
sync with main
This commit is contained in:
7
.github/dependabot.yaml
vendored
7
.github/dependabot.yaml
vendored
@@ -53,5 +53,12 @@ updates:
|
||||
- "*-loader"
|
||||
update-types:
|
||||
- major
|
||||
# group major bumps of jest-related dependencies
|
||||
jsx-jest:
|
||||
patterns:
|
||||
- "*jest*"
|
||||
- "*test*"
|
||||
update-types:
|
||||
- major
|
||||
schedule:
|
||||
interval: monthly
|
||||
|
@@ -16,7 +16,7 @@ ci:
|
||||
repos:
|
||||
# autoformat and lint Python code
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.11.12
|
||||
rev: v0.12.7
|
||||
hooks:
|
||||
- id: ruff
|
||||
types_or:
|
||||
@@ -29,8 +29,8 @@ repos:
|
||||
- jupyter
|
||||
|
||||
# Autoformat: markdown, yaml, javascript (see the file .prettierignore)
|
||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||
rev: v4.0.0-alpha.8
|
||||
- repo: https://github.com/rbubley/mirrors-prettier
|
||||
rev: v3.6.2
|
||||
hooks:
|
||||
- id: prettier
|
||||
exclude: .*/templates/.*|docs/source/_static/rest-api.yml|docs/source/rbac/scope-table.md
|
||||
|
@@ -58,7 +58,6 @@ for administration of the Hub and its users.
|
||||
- A Linux/Unix based system
|
||||
- [Python](https://www.python.org/downloads/) 3.8 or greater
|
||||
- [nodejs/npm](https://www.npmjs.com/)
|
||||
|
||||
- If you are using **`conda`**, the nodejs and npm dependencies will be installed for
|
||||
you by conda.
|
||||
|
||||
|
@@ -62,18 +62,19 @@ paths:
|
||||
properties:
|
||||
class:
|
||||
type: string
|
||||
description: The Python class currently active for JupyterHub
|
||||
Authentication
|
||||
description: The Python class currently active for
|
||||
JupyterHub Authentication
|
||||
version:
|
||||
type: string
|
||||
description: The version of the currently active Authenticator
|
||||
description: The version of the currently active
|
||||
Authenticator
|
||||
spawner:
|
||||
type: object
|
||||
properties:
|
||||
class:
|
||||
type: string
|
||||
description: The Python class currently active for spawning
|
||||
single-user notebook servers
|
||||
description: The Python class currently active for
|
||||
spawning single-user notebook servers
|
||||
version:
|
||||
type: string
|
||||
description: The version of the currently active Spawner
|
||||
@@ -256,8 +257,8 @@ paths:
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/userName"
|
||||
requestBody:
|
||||
description: Updated user info. At least one key to be updated (name or admin)
|
||||
is required.
|
||||
description: Updated user info. At least one key to be updated (name or
|
||||
admin) is required.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@@ -265,12 +266,12 @@ paths:
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: the new name (optional, if another key is updated i.e.
|
||||
admin)
|
||||
description: the new name (optional, if another key is updated
|
||||
i.e. admin)
|
||||
admin:
|
||||
type: boolean
|
||||
description: update admin (optional, if another key is updated i.e.
|
||||
name)
|
||||
description: update admin (optional, if another key is updated
|
||||
i.e. name)
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
@@ -286,8 +287,8 @@ paths:
|
||||
post:
|
||||
operationId: post-user-activity
|
||||
summary: Notify Hub of activity for a given user
|
||||
description: Notify the Hub of activity by the user, e.g. accessing a service
|
||||
or (more likely) actively using a server.
|
||||
description: Notify the Hub of activity by the user, e.g. accessing a
|
||||
service or (more likely) actively using a server.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/userName"
|
||||
requestBody:
|
||||
@@ -366,8 +367,8 @@ paths:
|
||||
description: The user's notebook server has started
|
||||
content: {}
|
||||
202:
|
||||
description: The user's notebook server has not yet started, but has been
|
||||
requested
|
||||
description: The user's notebook server has not yet started, but has
|
||||
been requested
|
||||
content: {}
|
||||
security:
|
||||
- oauth2:
|
||||
@@ -380,8 +381,8 @@ paths:
|
||||
- $ref: "#/components/parameters/userName"
|
||||
responses:
|
||||
202:
|
||||
description: The user's notebook server has not yet stopped as it is taking
|
||||
a while to stop
|
||||
description: The user's notebook server has not yet stopped as it is
|
||||
taking a while to stop
|
||||
content: {}
|
||||
204:
|
||||
description: The user's notebook server has stopped
|
||||
@@ -412,8 +413,8 @@ paths:
|
||||
description: The user's notebook named-server has started
|
||||
content: {}
|
||||
202:
|
||||
description: The user's notebook named-server has not yet started, but has
|
||||
been requested
|
||||
description: The user's notebook named-server has not yet started, but
|
||||
has been requested
|
||||
content: {}
|
||||
security:
|
||||
- oauth2:
|
||||
@@ -448,8 +449,8 @@ paths:
|
||||
required: false
|
||||
responses:
|
||||
202:
|
||||
description: The user's notebook named-server has not yet stopped as it
|
||||
is taking a while to stop
|
||||
description: The user's notebook named-server has not yet stopped as
|
||||
it is taking a while to stop
|
||||
content: {}
|
||||
204:
|
||||
description: The user's notebook named-server has stopped
|
||||
@@ -462,8 +463,8 @@ paths:
|
||||
get:
|
||||
operationId: get-user-shared
|
||||
summary: List servers shared with user
|
||||
description: Returns list of Shares granting the user access to servers owned
|
||||
by others (new in 5.0)
|
||||
description: Returns list of Shares granting the user access to servers
|
||||
owned by others (new in 5.0)
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/userName"
|
||||
|
||||
@@ -576,11 +577,13 @@ paths:
|
||||
expires_in:
|
||||
type: number
|
||||
example: 3600
|
||||
description: lifetime (in seconds) after which the requested token
|
||||
will expire. Omit, or specify null or 0 for no expiration.
|
||||
description: lifetime (in seconds) after which the requested
|
||||
token will expire. Omit, or specify null or 0 for no
|
||||
expiration.
|
||||
note:
|
||||
type: string
|
||||
description: A note attached to the token for future bookkeeping
|
||||
description: A note attached to the token for future
|
||||
bookkeeping
|
||||
roles:
|
||||
type: array
|
||||
description: |
|
||||
@@ -758,7 +761,8 @@ paths:
|
||||
- $ref: "#/components/parameters/sharedServerName"
|
||||
responses:
|
||||
200:
|
||||
description: The permissions granted to members of `group` on `owner/server`
|
||||
description: The permissions granted to members of `group` on
|
||||
`owner/server`
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@@ -1173,7 +1177,8 @@ paths:
|
||||
description: |
|
||||
The full URL for accepting the code,
|
||||
if JupyterHub.public_url configuration is defined.
|
||||
example: https://hub.example.org/hub/accept-share?code=abc123
|
||||
example:
|
||||
https://hub.example.org/hub/accept-share?code=abc123
|
||||
security:
|
||||
- oauth2:
|
||||
- shares
|
||||
@@ -1250,8 +1255,8 @@ paths:
|
||||
get:
|
||||
operationId: get-proxy
|
||||
summary: Get the proxy's routing table
|
||||
description: A convenience alias for getting the routing table directly from
|
||||
the proxy
|
||||
description: A convenience alias for getting the routing table directly
|
||||
from the proxy
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/paginationOffset"
|
||||
- $ref: "#/components/parameters/paginationLimit"
|
||||
@@ -1262,8 +1267,8 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
description: configurable-http-proxy routing table (see configurable-http-proxy
|
||||
docs for details)
|
||||
description: configurable-http-proxy routing table (see
|
||||
configurable-http-proxy docs for details)
|
||||
security:
|
||||
- oauth2:
|
||||
- proxy
|
||||
@@ -1282,8 +1287,8 @@ paths:
|
||||
summary: Notify the Hub about a new proxy
|
||||
description: Notifies the Hub of a new proxy to use.
|
||||
requestBody:
|
||||
description: Any values that have changed for the new proxy. All keys are
|
||||
optional.
|
||||
description: Any values that have changed for the new proxy. All keys
|
||||
are optional.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@@ -1374,8 +1379,8 @@ paths:
|
||||
get:
|
||||
operationId: get-auth-cookie
|
||||
summary: Identify a user from a cookie
|
||||
description: Used by single-user notebook servers to hand off cookie authentication
|
||||
to the Hub
|
||||
description: Used by single-user notebook servers to hand off cookie
|
||||
authentication to the Hub
|
||||
parameters:
|
||||
- name: cookie_name
|
||||
in: path
|
||||
@@ -1499,12 +1504,12 @@ paths:
|
||||
properties:
|
||||
proxy:
|
||||
type: boolean
|
||||
description: Whether the proxy should be shutdown as well (default
|
||||
from Hub config)
|
||||
description: Whether the proxy should be shutdown as well
|
||||
(default from Hub config)
|
||||
servers:
|
||||
type: boolean
|
||||
description: Whether users' notebook servers should be shutdown
|
||||
as well (default from Hub config)
|
||||
description: Whether users' notebook servers should be
|
||||
shutdown as well (default from Hub config)
|
||||
required: false
|
||||
responses:
|
||||
202:
|
||||
@@ -1648,8 +1653,8 @@ components:
|
||||
type: string
|
||||
server:
|
||||
type: string
|
||||
description: The user's notebook server's base URL, if running; null if
|
||||
not.
|
||||
description: The user's notebook server's base URL, if running; null
|
||||
if not.
|
||||
pending:
|
||||
type: string
|
||||
description: The currently pending action, if any
|
||||
@@ -1680,8 +1685,8 @@ components:
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: The server's name. The user's default server has an empty name
|
||||
('')
|
||||
description: The server's name. The user's default server has an empty
|
||||
name ('')
|
||||
ready:
|
||||
type: boolean
|
||||
description: |
|
||||
@@ -1743,14 +1748,14 @@ components:
|
||||
state:
|
||||
type: object
|
||||
properties: {}
|
||||
description: Arbitrary internal state from this server's spawner. Only available
|
||||
on the hub's users list or get-user-by-name method, and only with admin:users:server_state
|
||||
scope. None otherwise.
|
||||
description: Arbitrary internal state from this server's spawner. Only
|
||||
available on the hub's users list or get-user-by-name method, and
|
||||
only with admin:users:server_state scope. None otherwise.
|
||||
user_options:
|
||||
type: object
|
||||
properties: {}
|
||||
description: User specified options for the user's spawned instance of a
|
||||
single-user server.
|
||||
description: User specified options for the user's spawned instance of
|
||||
a single-user server.
|
||||
RequestIdentity:
|
||||
description: |
|
||||
The model for the entity making the request.
|
||||
@@ -1918,8 +1923,8 @@ components:
|
||||
items:
|
||||
type: string
|
||||
group:
|
||||
description: the group being shared with (exactly one of 'user' or 'group'
|
||||
will be non-null, the other will be null)
|
||||
description: the group being shared with (exactly one of 'user' or
|
||||
'group' will be non-null, the other will be null)
|
||||
type:
|
||||
- object
|
||||
- "null"
|
||||
@@ -1927,8 +1932,8 @@ components:
|
||||
name:
|
||||
type: string
|
||||
user:
|
||||
description: the user being shared with (exactly one of 'user' or 'group'
|
||||
will be non-null, the other will be null)
|
||||
description: the user being shared with (exactly one of 'user' or
|
||||
'group' will be non-null, the other will be null)
|
||||
type:
|
||||
- object
|
||||
- "null"
|
||||
@@ -1941,8 +1946,8 @@ components:
|
||||
format: date-time
|
||||
|
||||
ShareCode:
|
||||
description: A single sharing code. There is at most one of these objects per
|
||||
(server, user) or (server, group) combination.
|
||||
description: A single sharing code. There is at most one of these objects
|
||||
per (server, user) or (server, group) combination.
|
||||
type: object
|
||||
properties:
|
||||
server:
|
||||
@@ -1977,37 +1982,41 @@ components:
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
description: The id of the API token. Used for modifying or deleting the
|
||||
token.
|
||||
description: The id of the API token. Used for modifying or deleting
|
||||
the token.
|
||||
user:
|
||||
type: string
|
||||
description: The user that owns a token (undefined if owned by a service)
|
||||
description: The user that owns a token (undefined if owned by a
|
||||
service)
|
||||
service:
|
||||
type: string
|
||||
description: The service that owns the token (undefined of owned by a user)
|
||||
description: The service that owns the token (undefined of owned by a
|
||||
user)
|
||||
roles:
|
||||
type: array
|
||||
description: Deprecated in JupyterHub 3, always an empty list. Tokens have
|
||||
'scopes' starting from JupyterHub 3.
|
||||
description: Deprecated in JupyterHub 3, always an empty list. Tokens
|
||||
have 'scopes' starting from JupyterHub 3.
|
||||
items:
|
||||
type: string
|
||||
scopes:
|
||||
type: array
|
||||
description: List of scopes this token has been assigned. New in JupyterHub
|
||||
3. In JupyterHub 2.x, tokens were assigned 'roles' instead of scopes.
|
||||
description: List of scopes this token has been assigned. New in
|
||||
JupyterHub 3. In JupyterHub 2.x, tokens were assigned 'roles'
|
||||
instead of scopes.
|
||||
items:
|
||||
type: string
|
||||
note:
|
||||
type: string
|
||||
description: A note about the token, typically describing what it was created
|
||||
for.
|
||||
description: A note about the token, typically describing what it was
|
||||
created for.
|
||||
created:
|
||||
type: string
|
||||
description: Timestamp when this token was created
|
||||
format: date-time
|
||||
expires_at:
|
||||
type: string
|
||||
description: Timestamp when this token expires. Null if there is no expiry.
|
||||
description: Timestamp when this token expires. Null if there is no
|
||||
expiry.
|
||||
format: date-time
|
||||
last_activity:
|
||||
type: string
|
||||
@@ -2030,41 +2039,45 @@ components:
|
||||
properties:
|
||||
token:
|
||||
type: string
|
||||
description: The token itself. Only present in responses to requests for
|
||||
a new token.
|
||||
description: The token itself. Only present in responses to requests
|
||||
for a new token.
|
||||
id:
|
||||
type: string
|
||||
description: The id of the API token. Used for modifying or deleting the
|
||||
token.
|
||||
description: The id of the API token. Used for modifying or deleting
|
||||
the token.
|
||||
user:
|
||||
type: string
|
||||
description: The user that owns a token (undefined if owned by a service)
|
||||
description: The user that owns a token (undefined if owned by a
|
||||
service)
|
||||
service:
|
||||
type: string
|
||||
description: The service that owns the token (undefined of owned by a user)
|
||||
description: The service that owns the token (undefined of owned by a
|
||||
user)
|
||||
roles:
|
||||
type: array
|
||||
description: Deprecated in JupyterHub 3, always an empty list. Tokens have
|
||||
'scopes' starting from JupyterHub 3.
|
||||
description: Deprecated in JupyterHub 3, always an empty list. Tokens
|
||||
have 'scopes' starting from JupyterHub 3.
|
||||
items:
|
||||
type: string
|
||||
scopes:
|
||||
type: array
|
||||
description: List of scopes this token has been assigned. New in JupyterHub
|
||||
3. In JupyterHub 2.x, tokens were assigned 'roles' instead of scopes.
|
||||
description: List of scopes this token has been assigned. New in
|
||||
JupyterHub 3. In JupyterHub 2.x, tokens were assigned 'roles'
|
||||
instead of scopes.
|
||||
items:
|
||||
type: string
|
||||
note:
|
||||
type: string
|
||||
description: A note about the token, typically describing what it was created
|
||||
for.
|
||||
description: A note about the token, typically describing what it was
|
||||
created for.
|
||||
created:
|
||||
type: string
|
||||
description: Timestamp when this token was created
|
||||
format: date-time
|
||||
expires_at:
|
||||
type: string
|
||||
description: Timestamp when this token expires. Null if there is no expiry.
|
||||
description: Timestamp when this token expires. Null if there is no
|
||||
expiry.
|
||||
format: date-time
|
||||
last_activity:
|
||||
type: string
|
||||
@@ -2094,22 +2107,23 @@ components:
|
||||
tokenUrl: /hub/api/oauth2/token
|
||||
scopes:
|
||||
(no_scope): Identify the owner of the requesting entity.
|
||||
self: The user’s own resources _(metascope for users, resolves to (no_scope)
|
||||
for services)_
|
||||
inherit: Everything that the token-owning entity can access _(metascope
|
||||
for tokens)_
|
||||
admin-ui: Access the admin page. Permission to take actions via the admin
|
||||
page granted separately.
|
||||
admin:users: Read, modify, create, and delete users and their authentication
|
||||
state, not including their servers or tokens. This is an extremely privileged
|
||||
scope and should be considered tantamount to superuser.
|
||||
self: The user’s own resources _(metascope for users, resolves to
|
||||
(no_scope) for services)_
|
||||
inherit: Everything that the token-owning entity can access
|
||||
_(metascope for tokens)_
|
||||
admin-ui: Access the admin page. Permission to take actions via the
|
||||
admin page granted separately.
|
||||
admin:users: Read, modify, create, and delete users and their
|
||||
authentication state, not including their servers or tokens. This
|
||||
is an extremely privileged scope and should be considered
|
||||
tantamount to superuser.
|
||||
admin:auth_state: Read a user’s authentication state.
|
||||
users: Read and write permissions to user models (excluding servers, tokens
|
||||
and authentication state).
|
||||
users: Read and write permissions to user models (excluding servers,
|
||||
tokens and authentication state).
|
||||
delete:users: Delete users.
|
||||
list:users: List users, including at least their names.
|
||||
read:users: Read user models (including the URL of the default server
|
||||
if it is running).
|
||||
read:users: Read user models (including the URL of the default
|
||||
server if it is running).
|
||||
read:users:name: Read names of users.
|
||||
read:users:groups: Read users’ group membership.
|
||||
read:users:activity: Read time of last user activity.
|
||||
@@ -2118,24 +2132,25 @@ components:
|
||||
read:roles:services: Read service role assignments.
|
||||
read:roles:groups: Read group role assignments.
|
||||
users:activity: Update time of last user activity.
|
||||
admin:servers: Read, start, stop, create and delete user servers and their
|
||||
state.
|
||||
admin:servers: Read, start, stop, create and delete user servers and
|
||||
their state.
|
||||
admin:server_state: Read and write users’ server state.
|
||||
servers: Start and stop user servers.
|
||||
read:servers: Read users’ names and their server models (excluding the
|
||||
server state).
|
||||
read:servers: Read users’ names and their server models (excluding
|
||||
the server state).
|
||||
delete:servers: Stop and delete users' servers.
|
||||
tokens: Read, write, create and delete user tokens.
|
||||
read:tokens: Read user tokens.
|
||||
admin:groups: Read and write group information, create and delete groups.
|
||||
admin:groups: Read and write group information, create and delete
|
||||
groups.
|
||||
groups: 'Read and write group information, including adding/removing any
|
||||
users to/from groups. Note: adding users to groups may affect permissions.'
|
||||
list:groups: List groups, including at least their names.
|
||||
read:groups: Read group models.
|
||||
read:groups:name: Read group names.
|
||||
delete:groups: Delete groups.
|
||||
admin:services: Create, read, update, delete services, not including services
|
||||
defined from config files.
|
||||
admin:services: Create, read, update, delete services, not including
|
||||
services defined from config files.
|
||||
list:services: List services, including at least their names.
|
||||
read:services: Read service models.
|
||||
read:services:name: Read service names.
|
||||
@@ -2148,7 +2163,7 @@ components:
|
||||
read:groups:shares: Read servers shared with a group.
|
||||
read:shares: Read information about shared access to servers.
|
||||
shares: Manage access to shared servers.
|
||||
proxy: Read information about the proxy’s routing table, sync the Hub
|
||||
with the proxy and notify the Hub about a new proxy.
|
||||
proxy: Read information about the proxy’s routing table, sync the
|
||||
Hub with the proxy and notify the Hub about a new proxy.
|
||||
shutdown: Shutdown the hub.
|
||||
read:metrics: Read prometheus metrics.
|
||||
|
@@ -262,6 +262,7 @@ html_static_path = ["_static"]
|
||||
|
||||
html_theme = "jupyterhub_sphinx_theme"
|
||||
html_theme_options = {
|
||||
"header_links_before_dropdown": 6,
|
||||
"icon_links": [
|
||||
{
|
||||
"name": "GitHub",
|
||||
@@ -297,7 +298,10 @@ linkcheck_ignore = [
|
||||
r"https://github.com/jupyterhub/jupyterhub/security/advisories/.*",
|
||||
# Occasionally blocks CI checks with 403
|
||||
r"https://www\.mysql\.com",
|
||||
# Occasionally blocks CI checks with SSL error
|
||||
r"https://mediaspace\.msu\.edu/.*",
|
||||
]
|
||||
|
||||
linkcheck_anchors_ignore = [
|
||||
"/#!",
|
||||
"/#%21",
|
||||
|
@@ -12,9 +12,9 @@ Everyone in the Jupyter community is welcome to bring ideas and questions there.
|
||||
|
||||
We recommend that you first use our Discourse as all past and current discussions on it are archived and searchable. Thus, all discussions remain useful and accessible to the whole community.
|
||||
|
||||
## Gitter
|
||||
## Zulip
|
||||
|
||||
We use [our Gitter channel](https://gitter.im/jupyterhub/jupyterhub) for online, real-time text chat; a place for more ephemeral discussions. When you're not on Discourse, you can stop here to have other discussions on the fly.
|
||||
We use [Jupyter instance](https://jupyter.zulipchat.com/) of [Zulip](https://zulip.com/) for online, real-time text chat; a place for more ephemeral discussions. When you're not on Discourse, you can stop at Zulip to have other discussions on the fly.
|
||||
|
||||
## Github Issues
|
||||
|
||||
|
@@ -8,7 +8,7 @@ you get set up on how to contribute to JupyterHub's documentation.
|
||||
## Building documentation locally
|
||||
|
||||
We use [sphinx](https://www.sphinx-doc.org) to build our documentation. It takes
|
||||
our documentation source files (written in [markdown](https://daringfireball.net/projects/markdown/) or [reStructuredText](https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html) &
|
||||
our documentation source files (written in [markdown](https://daringfireball.net/projects/markdown/) or [reStructuredText](https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html) and
|
||||
stored under the `docs/source` directory) and converts it into various
|
||||
formats for people to read. To make sure the documentation you write or
|
||||
change renders correctly, it is good practice to test it locally.
|
||||
|
@@ -3,7 +3,7 @@
|
||||
# Contributing
|
||||
|
||||
We want you to contribute to JupyterHub in ways that are most exciting
|
||||
and useful to you. We value documentation, testing, bug reporting & code equally,
|
||||
and useful to you. We value documentation, testing, bug reporting and code equally,
|
||||
and are glad to have your contributions in whatever form you wish.
|
||||
|
||||
Be sure to first check our [Code of Conduct](https://github.com/jupyter/governance/blob/HEAD/conduct/code_of_conduct.md)
|
||||
|
@@ -5,34 +5,34 @@
|
||||
## System requirements
|
||||
|
||||
JupyterHub can only run on macOS or Linux operating systems. If you are
|
||||
using Windows, we recommend using [VirtualBox](https://virtualbox.org)
|
||||
using Windows, we recommend using [VirtualBox](https://www.virtualbox.org)
|
||||
or a similar system to run [Ubuntu Linux](https://ubuntu.com) for
|
||||
development.
|
||||
|
||||
### Install Python
|
||||
|
||||
JupyterHub is written in the [Python](https://python.org) programming language and
|
||||
JupyterHub is written in the [Python](https://www.python.org) programming language and
|
||||
requires you have at least version {{python_min}} installed locally. If you haven’t
|
||||
installed Python before, the recommended way to install it is to use
|
||||
[Miniforge](https://github.com/conda-forge/miniforge#download).
|
||||
|
||||
### Install nodejs
|
||||
### Install NodeJS
|
||||
|
||||
[NodeJS {{node_min}}+](https://nodejs.org/en/) is required for building some JavaScript components.
|
||||
`configurable-http-proxy`, the default proxy implementation for JupyterHub, is written in Javascript.
|
||||
Some JavaScript components require you have at least version {{node_min}} of [NodeJS](https://nodejs.org/en/) installed locally.
|
||||
`configurable-http-proxy`, the default proxy implementation for JupyterHub, is written in JavaScript.
|
||||
If you have not installed NodeJS before, we recommend installing it in the `miniconda` environment you set up for Python.
|
||||
You can do so with `conda install nodejs`.
|
||||
|
||||
Many in the Jupyter community use [`nvm`](https://github.com/nvm-sh/nvm) to
|
||||
managing node dependencies.
|
||||
|
||||
### Install git
|
||||
### Install Git
|
||||
|
||||
JupyterHub uses [Git](https://git-scm.com) & [GitHub](https://github.com)
|
||||
for development & collaboration. You need to [install git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) to work on
|
||||
JupyterHub. We also recommend getting a free account on GitHub.com.
|
||||
JupyterHub uses [Git](https://git-scm.com) and [GitHub](https://github.com)
|
||||
for development and collaboration. You need to [install Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) to work on
|
||||
JupyterHub. We also recommend getting a free account on GitHub.
|
||||
|
||||
## Setting up a development install
|
||||
## Install JupyterHub for development
|
||||
|
||||
When developing JupyterHub, you would need to make changes and be able to instantly view the results of the changes. To achieve that, a developer install is required.
|
||||
|
||||
@@ -44,7 +44,7 @@ be achieved in many ways, for example, `tox`, `conda`, `docker`, etc. See this
|
||||
a more detailed discussion.
|
||||
:::
|
||||
|
||||
1. Clone the [JupyterHub git repository](https://github.com/jupyterhub/jupyterhub)
|
||||
1. Clone the [JupyterHub Git repository](https://github.com/jupyterhub/jupyterhub)
|
||||
to your computer.
|
||||
|
||||
```bash
|
||||
@@ -65,7 +65,7 @@ a more detailed discussion.
|
||||
npm -v
|
||||
```
|
||||
|
||||
This should return a version number greater than or equal to 5.0.
|
||||
This should return a version number greater than or equal to {{node_min}}.
|
||||
|
||||
3. Install `configurable-http-proxy` (required to run and test the default JupyterHub configuration):
|
||||
|
||||
@@ -92,7 +92,7 @@ a more detailed discussion.
|
||||
|
||||
4. Install an editable version of JupyterHub and its requirements for
|
||||
development and testing. This lets you edit JupyterHub code in a text editor
|
||||
& restart the JupyterHub process to see your code changes immediately.
|
||||
and restart the JupyterHub process to see your code changes immediately.
|
||||
|
||||
```bash
|
||||
python3 -m pip install --editable ".[test]"
|
||||
@@ -109,7 +109,7 @@ a more detailed discussion.
|
||||
|
||||
Happy developing!
|
||||
|
||||
## Using DummyAuthenticator & SimpleLocalProcessSpawner
|
||||
## Using DummyAuthenticator and SimpleLocalProcessSpawner
|
||||
|
||||
To simplify testing of JupyterHub, it is helpful to use
|
||||
{class}`~jupyterhub.auth.DummyAuthenticator` instead of the default JupyterHub
|
||||
@@ -132,17 +132,17 @@ The test configuration enables a few things to make testing easier:
|
||||
- disable caching of static files
|
||||
|
||||
The default JupyterHub [authenticator](PAMAuthenticator)
|
||||
& [spawner](LocalProcessSpawner)
|
||||
and [spawner](LocalProcessSpawner)
|
||||
require your system to have user accounts for each user you want to log in to
|
||||
JupyterHub as.
|
||||
|
||||
DummyAuthenticator allows you to log in with any username & password,
|
||||
DummyAuthenticator allows you to log in with any username and password,
|
||||
while SimpleLocalProcessSpawner allows you to start servers without having to
|
||||
create a Unix user for each JupyterHub user. Together, these make it
|
||||
much easier to test JupyterHub.
|
||||
|
||||
Tip: If you are working on parts of JupyterHub that are common to all
|
||||
authenticators & spawners, we recommend using both DummyAuthenticator &
|
||||
authenticators and spawners, we recommend using both DummyAuthenticator and
|
||||
SimpleLocalProcessSpawner. If you are working on just authenticator-related
|
||||
parts, use only SimpleLocalProcessSpawner. Similarly, if you are working on
|
||||
just spawner-related parts, use only DummyAuthenticator.
|
||||
|
@@ -98,7 +98,7 @@ the OAuth callback request.
|
||||
to retrieve information about the owner of the token (the user).
|
||||
This is the step where behavior diverges for different OAuth providers.
|
||||
Up to this point, all OAuth providers are the same, following the OAuth specification.
|
||||
However, OAuth does not define a standard for issuing tokens in exchange for information about their owner or permissions ([OpenID Connect](https://openid.net/connect/) does that),
|
||||
However, OAuth does not define a standard for issuing tokens in exchange for information about their owner or permissions ([OpenID Connect](https://openid.net/developers/how-connect-works/) does that),
|
||||
so this step may be different for each OAuth provider.
|
||||
- Finally, the OAuth client stores its own record that the user is authorized in a cookie.
|
||||
This could be the token itself, or any other appropriate representation of successful authentication.
|
||||
|
@@ -101,7 +101,7 @@ matching `*.jupyter.example.org`.
|
||||
Unfortunately, for many institutional domains, wildcard DNS and SSL may not be available.
|
||||
|
||||
We also **strongly encourage** serving JupyterHub and user content on a domain that is _not_ a subdomain of any sensitive content.
|
||||
For reasoning, see [GitHub's discussion of moving user content to github.io from \*.github.com](https://github.blog/2013-04-09-yummy-cookies-across-domains/).
|
||||
For reasoning, see [GitHub's discussion of moving user content to github.io from \*.github.com](https://github.blog/engineering/yummy-cookies-across-domains/).
|
||||
|
||||
**If you do plan to serve untrusted users, enabling subdomains is highly encouraged**,
|
||||
as it resolves many security issues, which are difficult to unavoidable when JupyterHub is on a single-domain.
|
||||
@@ -186,7 +186,6 @@ For example:
|
||||
|
||||
- `Content-Security-Policy` header must prohibit popups and iframes from the same origin.
|
||||
The following Content-Security-Policy rules are _insecure_ and readily enable users to access each others' servers:
|
||||
|
||||
- `frame-ancestors: 'self'`
|
||||
- `frame-ancestors: '*'`
|
||||
- `sandbox allow-popups`
|
||||
|
@@ -142,7 +142,7 @@ in a variety of deployment setups. This often entails connecting your JupyterHub
|
||||
in these cases, and the security of your JupyterHub deployment will often depend on these decisions.
|
||||
|
||||
If you are worried about security, don't hesitate to reach out to the JupyterHub community in the
|
||||
[Jupyter Community Forum](https://discourse.jupyter.org/c/jupyterhub). This community of practice has many
|
||||
[Jupyter Community Forum](https://discourse.jupyter.org/c/jupyterhub/10). This community of practice has many
|
||||
individuals with experience running secure JupyterHub deployments and will be very glad to help you out.
|
||||
|
||||
### Does JupyterHub provide computing or data infrastructure?
|
||||
|
@@ -35,7 +35,7 @@ This user shouldn't have a login shell or password (possible with -r).
|
||||
|
||||
## Set up sudospawner
|
||||
|
||||
Next, you will need [sudospawner](https://github.com/jupyter/sudospawner)
|
||||
Next, you will need [sudospawner](https://github.com/jupyterhub/sudospawner)
|
||||
to enable monitoring the single-user servers with sudo:
|
||||
|
||||
```bash
|
||||
@@ -72,7 +72,7 @@ rhea ALL=(JUPYTER_USERS) NOPASSWD:JUPYTER_CMD
|
||||
```
|
||||
|
||||
It might be useful to modify `secure_path` to add commands in path. (Search for
|
||||
`secure_path` in the [sudo docs](https://www.sudo.ws/man/1.8.14/sudoers.man.html)
|
||||
`secure_path` in the [sudo docs](https://www.sudo.ws)
|
||||
|
||||
As an alternative to adding every user to the `/etc/sudoers` file, you can
|
||||
use a group in the last line above, instead of `JUPYTER_USERS`:
|
||||
|
@@ -71,4 +71,4 @@ aligned, rather than as an indicator of an existing problem.
|
||||
Upgrade the version of the `jupyterhub` package in your user environment or image
|
||||
so that it matches the version of JupyterHub running your JupyterHub server! If you
|
||||
are using the [zero-to-jupyterhub](https://z2jh.jupyter.org) helm chart, you can find the appropriate
|
||||
version of the `jupyterhub` package to install in your user image [here](https://jupyterhub.github.io/helm-chart/)
|
||||
version of the `jupyterhub` package to install in your user image [here](https://hub.jupyter.org/helm-chart/)
|
||||
|
@@ -232,4 +232,4 @@ A list of the proxies that are currently available for JupyterHub (that we know
|
||||
|
||||
1. [`jupyterhub/configurable-http-proxy`](https://github.com/jupyterhub/configurable-http-proxy) The default proxy which uses node-http-proxy
|
||||
2. [`jupyterhub/traefik-proxy`](https://github.com/jupyterhub/traefik-proxy) The proxy which configures traefik proxy server for jupyterhub
|
||||
3. [`AbdealiJK/configurable-http-proxy`](https://github.com/AbdealiJK/configurable-http-proxy) A pure python implementation of the configurable-http-proxy
|
||||
3. [`AbdealiJK/configurable-http-proxy`](https://github.com/corridor/configurable-http-proxy) A pure python implementation of the configurable-http-proxy
|
||||
|
@@ -201,7 +201,7 @@ Authorization header.
|
||||
|
||||
### Use requests
|
||||
|
||||
Using the popular Python [requests](https://docs.python-requests.org)
|
||||
Using the popular Python [requests](https://requests.readthedocs.io)
|
||||
library, an API GET request is made to [/users](rest-api-get-users), and the request sends an API token for
|
||||
authorization. The response contains information about the users, here's example code to make an API request for the users of a JupyterHub deployment
|
||||
|
||||
|
@@ -27,7 +27,7 @@ For specific version migrations:
|
||||
The [changelog](changelog) contains information on what has
|
||||
changed with the new JupyterHub release and any deprecation warnings.
|
||||
Read these notes to familiarize yourself with the coming changes. There
|
||||
might be new releases of the authenticators & spawners you use, so
|
||||
might be new releases of the authenticators and spawners you use, so
|
||||
read the changelogs for those too!
|
||||
|
||||
## Notify your users
|
||||
@@ -41,7 +41,7 @@ If you use a different proxy or run `configurable-http-proxy`
|
||||
independent of JupyterHub, your users will be able to continue using notebook
|
||||
servers they had already launched, but will not be able to launch new servers or sign in.
|
||||
|
||||
## Backup database & config
|
||||
## Backup database and config
|
||||
|
||||
Before doing an upgrade, it is critical to back up:
|
||||
|
||||
@@ -90,7 +90,7 @@ with:
|
||||
conda install -c conda-forge jupyterhub==<version>
|
||||
```
|
||||
|
||||
You should also check for new releases of the authenticator & spawner you
|
||||
You should also check for new releases of the authenticator and spawner you
|
||||
are using. You might wish to upgrade those packages, too, along with JupyterHub
|
||||
or upgrade them separately.
|
||||
|
||||
|
@@ -17,7 +17,7 @@ It has two main distributions which are developed to serve the needs of each of
|
||||
|
||||
1. [The Littlest JupyterHub](https://github.com/jupyterhub/the-littlest-jupyterhub) distribution is suitable if you need a small number of users (1-100) and a single server with a simple environment.
|
||||
2. [Zero to JupyterHub with Kubernetes](https://github.com/jupyterhub/zero-to-jupyterhub-k8s) allows you to deploy dynamic servers on the cloud if you need even more users.
|
||||
This distribution runs JupyterHub on top of [Kubernetes](https://k8s.io).
|
||||
This distribution runs JupyterHub on top of [Kubernetes](https://kubernetes.io/).
|
||||
|
||||
```{note}
|
||||
It is important to evaluate these distributions before you can continue with the
|
||||
|
@@ -84,7 +84,6 @@ The passed scopes are compared to the scopes required to access the API as follo
|
||||
- if the API scopes are present within the set of passed scopes, the access is granted and the API returns its "full" response
|
||||
|
||||
- if that is not the case, another check is utilized to determine if subscopes of the required API scopes can be found in the passed scope set:
|
||||
|
||||
- if found, the RBAC framework employs the {ref}`filtering <vertical-filtering-target>` procedures to refine the API response to access only resource attributes corresponding to the passed scopes. For example, providing a scope `read:users:activity!group=class-C` for the `GET /users` API will return a list of user models from group `class-C` containing only the `last_activity` attribute for each user model
|
||||
|
||||
- if not found, the access to API is denied
|
||||
|
@@ -1831,7 +1831,7 @@ Highlights:
|
||||
- More configuration of page templates and service display
|
||||
- Pagination of the admin page improving performance with large numbers of users
|
||||
- Improved control of user redirect
|
||||
- Support for [jupyter-server](https://jupyter-server.readthedocs.io/en/latest/)-based single-user servers, such as [Voilà](https://voila-gallery.org) and latest JupyterLab.
|
||||
- Support for [jupyter-server](https://jupyter-server.readthedocs.io/en/latest/)-based single-user servers, such as [Voilà](https://voila.readthedocs.io) and latest JupyterLab.
|
||||
- Lots more improvements to documentation, HTML pages, and customizations
|
||||
|
||||
([full changelog](https://github.com/jupyterhub/jupyterhub/compare/1.1.0...1.2.0))
|
||||
|
@@ -16,17 +16,13 @@ Please submit pull requests to update information or to add new institutions or
|
||||
|
||||
- [BIDS - Berkeley Institute for Data Science](https://bids.berkeley.edu/)
|
||||
|
||||
- [Data 8](http://data8.org/)
|
||||
|
||||
- [Data 8](https://www.data8.org/)
|
||||
- [GitHub organization](https://github.com/data-8)
|
||||
|
||||
- [NERSC](https://www.nersc.gov/)
|
||||
|
||||
- [Press release on Jupyter and Cori](https://www.nersc.gov/news-publications/nersc-news/nersc-center-news/2016/jupyter-notebooks-will-open-up-new-possibilities-on-nerscs-cori-supercomputer/)
|
||||
- [Moving and sharing data](https://www.nersc.gov/assets/Uploads/03-MovingAndSharingData-Cholia.pdf)
|
||||
|
||||
- [Research IT](https://research-it.berkeley.edu)
|
||||
- [JupyterHub server supports campus research computation](https://research-it.berkeley.edu/blog/17/01/24/free-fully-loaded-jupyterhub-server-supports-campus-research-computation)
|
||||
- [JupyterHub server supports campus research computation](https://research-it.berkeley.edu/news/free-fully-loaded-jupyterhub-server-supports-campus-research-computation)
|
||||
|
||||
### University of California Davis
|
||||
|
||||
@@ -86,7 +82,7 @@ Within CERN, there are two noteworthy JupyterHub deployments in operation:
|
||||
|
||||
[ETH Zurich](https://ethz.ch/en.html), (Federal Institute of Technology Zurich), is a public research university in Zürich, Switzerland, with focus on science, technology, engineering, and mathematics, although its 16 departments span a variety of disciplines and subjects.
|
||||
|
||||
The [Educational Development and Technology](https://ethz.ch/en/the-eth-zurich/organisation/departments/educational-development-and-technology.html) unit provides JupyterHub exclusively for teaching and learning, integrated in the learning management system [Moodle](https://ethz.ch/staffnet/en/teaching/academic-support/it-services-teaching/teaching-applications/moodle-service.html). Each course gets its individually configured JupyterHub environment deployed on a on-premise Kubernetes cluster.
|
||||
The [Educational Development and Technology](https://ethz.ch/en/the-eth-zurich/organisation/departments/teaching-and-learning.html) unit provides JupyterHub exclusively for teaching and learning, integrated in the learning management system [Moodle](https://ethz.ch/staffnet/en/teaching/academic-support/it-services-teaching/teaching-applications/moodle-service.html). Each course gets its individually configured JupyterHub environment deployed on a on-premise Kubernetes cluster.
|
||||
|
||||
- [ETH JupyterHub](https://ethz.ch/staffnet/en/teaching/academic-support/it-services-teaching/teaching-applications/jupyterhub.html) for teaching and learning
|
||||
|
||||
@@ -125,16 +121,15 @@ The [Educational Development and Technology](https://ethz.ch/en/the-eth-zurich/o
|
||||
### Paderborn University
|
||||
|
||||
- [Data Science (DICE) group](https://dice-research.org)
|
||||
- [nbgraderutils](https://github.com/dice-group/nbgraderutils): Use JupyterHub + nbgrader + iJava kernel for online Java exercises. Used in lecture Statistical Natural Language Processing.
|
||||
- [JavaOnlineExercises](https://github.com/dice-group/JavaOnlineExercises): Use JupyterHub + nbgrader + iJava kernel for online Java exercises. Used in lecture Statistical Natural Language Processing.
|
||||
|
||||
### Penn State University
|
||||
|
||||
- [Press release](https://news.psu.edu/story/523093/2018/05/24/new-open-source-web-apps-available-students-and-faculty): "New open-source web apps available for students and faculty"
|
||||
- [Press release](https://www.psu.edu/news/academics/story/new-open-source-web-apps-available-students-and-faculty): "New open-source web apps available for students and faculty"
|
||||
|
||||
### University of California San Diego
|
||||
|
||||
- San Diego Supercomputer Center - Andrea Zonca
|
||||
|
||||
- [Deploy JupyterHub on a Supercomputer with SSH](https://zonca.github.io/2017/05/jupyterhub-hpc-batchspawner-ssh.html)
|
||||
- [Run Jupyterhub on a Supercomputer](https://zonca.github.io/2015/04/jupyterhub-hpc.html)
|
||||
- [Deploy JupyterHub on a VM for a Workshop](https://zonca.github.io/2016/04/jupyterhub-sdsc-cloud.html)
|
||||
@@ -154,7 +149,7 @@ The [Educational Development and Technology](https://ethz.ch/en/the-eth-zurich/o
|
||||
|
||||
### Elucidata
|
||||
|
||||
- What's new in Jupyter Notebooks @[Elucidata](https://elucidata.io/):
|
||||
- What's new in Jupyter Notebooks @[Elucidata](https://www.elucidata.io/):
|
||||
- [Using Jupyter Notebooks with Jupyterhub on GCP, managed by GKE](https://medium.com/elucidata/why-you-should-be-using-a-jupyter-notebook-8385a4ccd93d)
|
||||
|
||||
## Service Providers
|
||||
@@ -174,7 +169,7 @@ The [Educational Development and Technology](https://ethz.ch/en/the-eth-zurich/o
|
||||
|
||||
### Microsoft Azure
|
||||
|
||||
- [Azure Data Science Virtual Machine release notes](https://docs.microsoft.com/en-us/azure/machine-learning/machine-learning-data-science-linux-dsvm-intro)
|
||||
- [Azure Data Science Virtual Machine release notes](https://learn.microsoft.com/en-us/azure/machine-learning/machine-learning-data-science-linux-dsvm-intro)
|
||||
|
||||
### Rackspace Carina
|
||||
|
||||
@@ -202,5 +197,5 @@ The [Educational Development and Technology](https://ethz.ch/en/the-eth-zurich/o
|
||||
- https://www.walkingrandomly.com/?p=5734
|
||||
- https://wrdrd.com/docs/consulting/education-technology
|
||||
- https://bitbucket.org/jackhale/fenics-jupyter
|
||||
- [LinuxCluster blog](https://linuxcluster.wordpress.com/category/application/jupyterhub/)
|
||||
- [LinuxCluster blog](https://thelinuxcluster.com/category/application/jupyterhub/)
|
||||
- [Spark Cluster on OpenStack with Multi-User Jupyter Notebook](https://arnesund.com/2015/09/21/spark-cluster-on-openstack-with-multi-user-jupyter-notebook/)
|
||||
|
@@ -563,7 +563,7 @@ and an example of its configuration is found [here](https://github.com/jupyter/n
|
||||
nbviewer can also be run as a Hub-Managed Service as described [nbviewer README][nbviewer example]
|
||||
section on securing the notebook viewer.
|
||||
|
||||
[requests]: https://docs.python-requests.org/en/master/
|
||||
[requests]: https://requests.readthedocs.io
|
||||
[services_auth]: ../api/services.auth.html
|
||||
[nbviewer example]: https://github.com/jupyter/nbviewer#securing-the-notebook-viewer
|
||||
[fastapi example]: https://github.com/jupyterhub/jupyterhub/tree/HEAD/examples/service-fastapi
|
||||
|
@@ -467,7 +467,7 @@ spawner, does not support limits and guarantees. One of the spawners
|
||||
that supports limits and guarantees is the
|
||||
[`systemdspawner`](https://github.com/jupyterhub/systemdspawner).
|
||||
|
||||
### Memory Limits & Guarantees
|
||||
### Memory Limits and Guarantees
|
||||
|
||||
`c.Spawner.mem_limit`: A **limit** specifies the _maximum amount of memory_
|
||||
that may be allocated, though there is no promise that the maximum amount will
|
||||
@@ -487,7 +487,7 @@ available for the single-user notebook server to use. The environment variable
|
||||
limits and providing these guarantees.** If these values are set to `None`, no
|
||||
limits or guarantees are provided, and no environment values are set.
|
||||
|
||||
### CPU Limits & Guarantees
|
||||
### CPU Limits and Guarantees
|
||||
|
||||
`c.Spawner.cpu_limit`: In supported spawners, you can set
|
||||
`c.Spawner.cpu_limit` to limit the total number of cpu-cores that a
|
||||
|
@@ -46,7 +46,7 @@ If you want to run docker on a computer that has a public IP then you should
|
||||
(as in MUST) **secure it with ssl** by adding ssl options to your docker
|
||||
configuration or using an ssl enabled proxy.
|
||||
|
||||
[Mounting volumes](https://docs.docker.com/engine/admin/volumes/volumes/)
|
||||
[Mounting volumes](https://docs.docker.com/engine/storage/volumes/)
|
||||
enables you to persist and store the data generated by the docker container, even when you stop the container.
|
||||
The persistent data can be stored on the host system, outside the container.
|
||||
|
||||
|
@@ -11,7 +11,6 @@ Before installing JupyterHub, you will need:
|
||||
installing Python packages is helpful.
|
||||
- [Node.js {{node_min}}](https://www.npmjs.com/) or greater, along with npm. [Install Node.js/npm](https://docs.npmjs.com/getting-started/installing-node),
|
||||
using your operating system's package manager.
|
||||
|
||||
- If you are using **`conda`**, the nodejs and npm dependencies will be installed for
|
||||
you by conda.
|
||||
|
||||
|
6508
jsx/package-lock.json
generated
6508
jsx/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -35,45 +35,45 @@
|
||||
"testEnvironment": "jsdom"
|
||||
},
|
||||
"dependencies": {
|
||||
"bootstrap": "^5.3.6",
|
||||
"bootstrap": "^5.3.7",
|
||||
"history": "^5.3.0",
|
||||
"lodash": "^4.17.21",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^19.1.0",
|
||||
"react": "^19.1.1",
|
||||
"react-bootstrap": "^2.10.10",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-router": "^7.6.1",
|
||||
"react-router": "^7.7.1",
|
||||
"redux": "^5.0.1",
|
||||
"regenerator-runtime": "^0.14.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.27.4",
|
||||
"@babel/preset-env": "^7.27.2",
|
||||
"@babel/core": "^7.28.0",
|
||||
"@babel/preset-env": "^7.28.0",
|
||||
"@babel/preset-react": "^7.27.1",
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "^9.28.0",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@eslint/js": "^9.32.0",
|
||||
"@testing-library/jest-dom": "^6.6.4",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
"@webpack-cli/serve": "^3.0.1",
|
||||
"babel-jest": "^29.7.0",
|
||||
"babel-jest": "^30.0.5",
|
||||
"babel-loader": "^10.0.0",
|
||||
"css-loader": "^7.1.2",
|
||||
"eslint": "^9.28.0",
|
||||
"eslint-plugin-prettier": "^5.4.1",
|
||||
"eslint": "^9.32.0",
|
||||
"eslint-plugin-prettier": "^5.5.3",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-unused-imports": "^4.1.4",
|
||||
"file-loader": "^6.2.0",
|
||||
"globals": "^16.2.0",
|
||||
"globals": "^16.3.0",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jest": "^29.7.0",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"prettier": "^3.5.3",
|
||||
"jest": "^30.0.5",
|
||||
"jest-environment-jsdom": "^30.0.5",
|
||||
"prettier": "^3.6.2",
|
||||
"style-loader": "^4.0.0",
|
||||
"webpack": "^5.99.9",
|
||||
"webpack": "^5.101.0",
|
||||
"webpack-cli": "^6.0.1",
|
||||
"webpack-dev-server": "^5.2.1"
|
||||
"webpack-dev-server": "^5.2.2"
|
||||
}
|
||||
}
|
||||
|
@@ -139,7 +139,7 @@ test("Interacting with PaginationFooter causes page refresh", async () => {
|
||||
render(groupsJsx(updateGroupsSpy));
|
||||
});
|
||||
|
||||
expect(updateGroupsSpy).toBeCalledWith(0, 2);
|
||||
expect(updateGroupsSpy).toHaveBeenCalledWith(0, 2);
|
||||
|
||||
var lastState =
|
||||
mockReducers.mock.results[mockReducers.mock.results.length - 1].value;
|
||||
@@ -153,5 +153,5 @@ test("Interacting with PaginationFooter causes page refresh", async () => {
|
||||
});
|
||||
expect(searchParams.get("offset")).toEqual("2");
|
||||
// FIXME: useSelector mocks prevent updateGroups from being called
|
||||
// expect(updateGroupsSpy).toBeCalledWith(2, 2);
|
||||
// expect(updateGroupsSpy).toHaveBeenCalledWith(2, 2);
|
||||
});
|
||||
|
@@ -591,14 +591,14 @@ test("Search for user calls updateUsers with name filter", async () => {
|
||||
expect(searchParams.get("offset")).toEqual(null);
|
||||
// FIXME: useSelector mocks prevent updateUsers from being called
|
||||
// expect(mockUpdateUsers.mock.calls).toHaveLength(2);
|
||||
// expect(mockUpdateUsers).toBeCalledWith(0, 100, "a");
|
||||
// expect(mockUpdateUsers).toHaveBeenCalledWith(0, 100, "a");
|
||||
await user.type(search, "b");
|
||||
expect(search.value).toEqual("ab");
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect(searchParams.get("name_filter")).toEqual("ab");
|
||||
// expect(mockUpdateUsers).toBeCalledWith(0, 100, "ab");
|
||||
// expect(mockUpdateUsers).toHaveBeenCalledWith(0, 100, "ab");
|
||||
});
|
||||
|
||||
test("Interacting with PaginationFooter requests page update", async () => {
|
||||
@@ -606,7 +606,7 @@ test("Interacting with PaginationFooter requests page update", async () => {
|
||||
render(serverDashboardJsx());
|
||||
});
|
||||
|
||||
expect(mockUpdateUsers).toBeCalledWith(defaultUpdateUsersParams);
|
||||
expect(mockUpdateUsers).toHaveBeenCalledWith(defaultUpdateUsersParams);
|
||||
|
||||
var n = 3;
|
||||
expect(searchParams.get("offset")).toEqual(null);
|
||||
@@ -619,7 +619,7 @@ test("Interacting with PaginationFooter requests page update", async () => {
|
||||
});
|
||||
expect(searchParams.get("offset")).toEqual("2");
|
||||
// FIXME: useSelector mocks prevent updateUsers from being called
|
||||
// expect(mockUpdateUsers).toBeCalledWith({
|
||||
// expect(mockUpdateUsers).toHaveBeenCalledWith({
|
||||
// ...defaultUpdateUsersParams,
|
||||
// offset: 2,
|
||||
// });
|
||||
|
@@ -870,10 +870,10 @@ class SpawnProgressAPIHandler(APIHandler):
|
||||
html_message = getattr(exc, "jupyterhub_html_message", "")
|
||||
if html_message:
|
||||
failed_event['html_message'] = html_message
|
||||
await self.send_event(failed_event)
|
||||
return
|
||||
else:
|
||||
raise web.HTTPError(400, "%s is not starting...", spawner._log_name)
|
||||
await self.send_event(failed_event)
|
||||
return
|
||||
|
||||
# retrieve progress events from the Spawner
|
||||
async with aclosing(
|
||||
@@ -1034,7 +1034,7 @@ class ActivityAPIHandler(APIHandler):
|
||||
user.name,
|
||||
server_name,
|
||||
isoformat(last_activity),
|
||||
isoformat(user.last_activity),
|
||||
isoformat(spawner.last_activity),
|
||||
)
|
||||
|
||||
self.db.commit()
|
||||
|
@@ -32,7 +32,7 @@ from dateutil.parser import parse as parse_date
|
||||
from jinja2 import ChoiceLoader, Environment, FileSystemLoader, PrefixLoader
|
||||
from jupyter_events.logger import EventLogger
|
||||
from sqlalchemy.exc import OperationalError, SQLAlchemyError
|
||||
from sqlalchemy.orm import joinedload
|
||||
from sqlalchemy.orm import contains_eager, selectinload
|
||||
from tornado import gen, web
|
||||
from tornado.httpclient import AsyncHTTPClient
|
||||
from tornado.ioloop import IOLoop, PeriodicCallback
|
||||
@@ -3097,9 +3097,10 @@ class JupyterHub(Application):
|
||||
.filter(orm.Spawner.server != None)
|
||||
# pre-load relationships to avoid O(N active servers) queries
|
||||
.options(
|
||||
joinedload(orm.User._orm_spawners),
|
||||
joinedload(orm.Spawner.server),
|
||||
contains_eager(orm.User._orm_spawners),
|
||||
selectinload(orm.Spawner.server),
|
||||
)
|
||||
.populate_existing()
|
||||
):
|
||||
# instantiate Spawner wrapper and check if it's still alive
|
||||
# spawner should be running
|
||||
|
@@ -62,7 +62,7 @@ async def test_submit_login_form(app, browser, user_special_chars):
|
||||
await browser.goto(login_url)
|
||||
await login(browser, user.name, password=user.name)
|
||||
expected_url = public_url(app, user)
|
||||
await expect(browser).to_have_url(expected_url)
|
||||
await browser.wait_for_url(expected_url)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -143,7 +143,7 @@ async def test_open_url_login(
|
||||
await expect(browser).to_have_url(re.compile(pattern))
|
||||
await expect(browser).not_to_have_url(re.compile(".*/user/.*"))
|
||||
else:
|
||||
await expect(browser).to_have_url(
|
||||
await browser.wait_for_url(
|
||||
re.compile(".*/user/" + f"{user_special_chars.urlname}/")
|
||||
)
|
||||
|
||||
@@ -883,17 +883,15 @@ async def test_menu_bar(app, browser, page, logged_in, user_special_chars):
|
||||
expected_url = f"hub/login?next={url_escape(app.base_url)}"
|
||||
assert expected_url in browser.url
|
||||
else:
|
||||
await expect(browser).to_have_url(
|
||||
await browser.wait_for_url(
|
||||
re.compile(f".*/user/{user_special_chars.urlname}/")
|
||||
)
|
||||
await browser.go_back()
|
||||
await expect(browser).to_have_url(re.compile(".*" + page))
|
||||
await browser.wait_for_url(re.compile(".*" + page))
|
||||
elif index == 3:
|
||||
await expect(browser).to_have_url(re.compile(".*/login"))
|
||||
await browser.wait_for_url(re.compile(".*/login"))
|
||||
else:
|
||||
await expect(browser).to_have_url(
|
||||
re.compile(".*" + expected_link_bar_url[index])
|
||||
)
|
||||
await browser.wait_for_url(re.compile(".*" + expected_link_bar_url[index]))
|
||||
|
||||
|
||||
# LOGOUT
|
||||
@@ -924,8 +922,8 @@ async def test_user_logout(app, browser, url, user_special_chars):
|
||||
|
||||
# verify that user can login after logout
|
||||
await login(browser, user.name, password=user.name)
|
||||
await expect(browser).to_have_url(
|
||||
re.compile(".*/user/" + f"{user_special_chars.urlname}/")
|
||||
await browser.wait_for_url(
|
||||
re.compile(".*/user/" + f"{user_special_chars.urlname}/"),
|
||||
)
|
||||
|
||||
|
||||
@@ -1016,7 +1014,7 @@ async def test_oauth_page(
|
||||
await expect(scopes_element).not_to_be_visible()
|
||||
for scopes_element in scopes_elements
|
||||
]
|
||||
# checking that all scopes granded to user are presented in POST form (scope_list)
|
||||
# checking that all scopes granted to user are presented in POST form (scope_list)
|
||||
scope_list_oauth_page = [
|
||||
await scopes_element.get_attribute("value")
|
||||
for scopes_element in scopes_elements
|
||||
@@ -1288,8 +1286,8 @@ async def test_start_stop_server_on_admin_page(
|
||||
spawn_btn_xpath = f'//a[contains(@href, "spawn/{username}")]/button[contains(@class, "btn-light")]'
|
||||
spawn_btn = browser.locator(spawn_btn_xpath)
|
||||
await expect(spawn_btn).to_be_enabled()
|
||||
async with browser.expect_navigation(url=f"**/user/{username}/"):
|
||||
await spawn_btn.click()
|
||||
await spawn_btn.click()
|
||||
await browser.wait_for_url(url=f"**/user/{username}/")
|
||||
|
||||
async def click_access_server(browser, username):
|
||||
"""access to the server for users via the Access Server button"""
|
||||
@@ -1337,7 +1335,7 @@ async def test_start_stop_server_on_admin_page(
|
||||
|
||||
# click on Spawn page button
|
||||
await click_spawn_page(browser, user2.name)
|
||||
await expect(browser).to_have_url(re.compile(".*" + f"/user/{user2.name}/"))
|
||||
await browser.wait_for_url(re.compile(".*" + f"/user/{user2.name}/"))
|
||||
|
||||
# open/return to the Admin page
|
||||
admin_page = url_path_join(public_host(app), app.hub.base_url, "admin")
|
||||
@@ -1491,18 +1489,18 @@ async def test_singleuser_xsrf(
|
||||
await browser.goto(login_url)
|
||||
await login(browser, browser_user.name, browser_user.name)
|
||||
# end up at single-user
|
||||
await expect(browser).to_have_url(re.compile(rf".*/user/{browser_user.name}/.*"))
|
||||
await browser.wait_for_url(re.compile(rf".*/user/{browser_user.name}/.*"))
|
||||
# wait for target user to start, too
|
||||
await target_start
|
||||
await app.proxy.add_user(target_user)
|
||||
|
||||
# visit target user, sets credentials for second server
|
||||
await browser.goto(public_url(app, target_user))
|
||||
await expect(browser).to_have_url(re.compile(r".*/oauth2/authorize"))
|
||||
await browser.wait_for_url(re.compile(r".*/oauth2/authorize"))
|
||||
auth_button = browser.locator('//button[@type="submit"]')
|
||||
await expect(auth_button).to_be_enabled()
|
||||
await auth_button.click()
|
||||
await expect(browser).to_have_url(re.compile(rf".*/user/{target_user.name}/.*"))
|
||||
await browser.wait_for_url(re.compile(rf".*/user/{target_user.name}/.*"))
|
||||
|
||||
# at this point, we are on a page served by target_user,
|
||||
# logged in as browser_user
|
||||
@@ -1644,8 +1642,8 @@ async def test_singleuser_xsrf(
|
||||
url_path_join(app.base_url, f"hub/spawn/{browser_user.name}/{server_name}"),
|
||||
)
|
||||
await browser.goto(url)
|
||||
await expect(browser).to_have_url(
|
||||
re.compile(rf".*/user/{browser_user.name}/{server_name}/.*")
|
||||
await browser.wait_for_url(
|
||||
re.compile(rf".*/user/{browser_user.name}/{server_name}/.*"),
|
||||
)
|
||||
# from named server URL, make sure we can talk to a kernel
|
||||
token = browser_user.new_api_token(scopes=["access:servers!user"])
|
||||
|
@@ -65,7 +65,9 @@ async def test_proxy_service(app, mockservice_url):
|
||||
service = mockservice_url
|
||||
name = service.name
|
||||
await app.proxy.get_all_routes()
|
||||
url = public_url(app, service) + '/foo'
|
||||
url = public_url(app, service)
|
||||
assert url.endswith("/")
|
||||
url += "foo"
|
||||
r = await async_requests.get(url, allow_redirects=False)
|
||||
path = f'/services/{name}/foo'
|
||||
r.raise_for_status()
|
||||
|
195
package-lock.json
generated
195
package-lock.json
generated
@@ -24,15 +24,18 @@
|
||||
"version": "6.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.7.2.tgz",
|
||||
"integrity": "sha512-JUOtgFW6k9u4Y+xeIaEiLr3+cjoUPiAuLXoyKOJSia6Duzb7pq+A76P9ZdPDoAoxHdHzq6gE9/jKBGXlZT8FbA==",
|
||||
"license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.4.1.tgz",
|
||||
"integrity": "sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA==",
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz",
|
||||
"integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"detect-libc": "^1.0.3",
|
||||
@@ -48,28 +51,30 @@
|
||||
"url": "https://opencollective.com/parcel"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@parcel/watcher-android-arm64": "2.4.1",
|
||||
"@parcel/watcher-darwin-arm64": "2.4.1",
|
||||
"@parcel/watcher-darwin-x64": "2.4.1",
|
||||
"@parcel/watcher-freebsd-x64": "2.4.1",
|
||||
"@parcel/watcher-linux-arm-glibc": "2.4.1",
|
||||
"@parcel/watcher-linux-arm64-glibc": "2.4.1",
|
||||
"@parcel/watcher-linux-arm64-musl": "2.4.1",
|
||||
"@parcel/watcher-linux-x64-glibc": "2.4.1",
|
||||
"@parcel/watcher-linux-x64-musl": "2.4.1",
|
||||
"@parcel/watcher-win32-arm64": "2.4.1",
|
||||
"@parcel/watcher-win32-ia32": "2.4.1",
|
||||
"@parcel/watcher-win32-x64": "2.4.1"
|
||||
"@parcel/watcher-android-arm64": "2.5.1",
|
||||
"@parcel/watcher-darwin-arm64": "2.5.1",
|
||||
"@parcel/watcher-darwin-x64": "2.5.1",
|
||||
"@parcel/watcher-freebsd-x64": "2.5.1",
|
||||
"@parcel/watcher-linux-arm-glibc": "2.5.1",
|
||||
"@parcel/watcher-linux-arm-musl": "2.5.1",
|
||||
"@parcel/watcher-linux-arm64-glibc": "2.5.1",
|
||||
"@parcel/watcher-linux-arm64-musl": "2.5.1",
|
||||
"@parcel/watcher-linux-x64-glibc": "2.5.1",
|
||||
"@parcel/watcher-linux-x64-musl": "2.5.1",
|
||||
"@parcel/watcher-win32-arm64": "2.5.1",
|
||||
"@parcel/watcher-win32-ia32": "2.5.1",
|
||||
"@parcel/watcher-win32-x64": "2.5.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-android-arm64": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.4.1.tgz",
|
||||
"integrity": "sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==",
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz",
|
||||
"integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
@@ -83,13 +88,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-darwin-arm64": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.1.tgz",
|
||||
"integrity": "sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA==",
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz",
|
||||
"integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
@@ -103,13 +109,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-darwin-x64": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.4.1.tgz",
|
||||
"integrity": "sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg==",
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz",
|
||||
"integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
@@ -123,13 +130,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-freebsd-x64": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.4.1.tgz",
|
||||
"integrity": "sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w==",
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz",
|
||||
"integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
@@ -143,13 +151,35 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-linux-arm-glibc": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.4.1.tgz",
|
||||
"integrity": "sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA==",
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz",
|
||||
"integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-linux-arm-musl": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz",
|
||||
"integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -163,13 +193,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-linux-arm64-glibc": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.4.1.tgz",
|
||||
"integrity": "sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA==",
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz",
|
||||
"integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -183,13 +214,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-linux-arm64-musl": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.4.1.tgz",
|
||||
"integrity": "sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA==",
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz",
|
||||
"integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -203,13 +235,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-linux-x64-glibc": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.4.1.tgz",
|
||||
"integrity": "sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg==",
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz",
|
||||
"integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -223,13 +256,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-linux-x64-musl": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.4.1.tgz",
|
||||
"integrity": "sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ==",
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz",
|
||||
"integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -243,13 +277,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-win32-arm64": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.4.1.tgz",
|
||||
"integrity": "sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg==",
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz",
|
||||
"integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
@@ -263,13 +298,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-win32-ia32": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.4.1.tgz",
|
||||
"integrity": "sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw==",
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz",
|
||||
"integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
@@ -283,13 +319,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-win32-x64": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.4.1.tgz",
|
||||
"integrity": "sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A==",
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz",
|
||||
"integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
@@ -306,6 +343,7 @@
|
||||
"version": "2.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@@ -313,9 +351,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/bootstrap": {
|
||||
"version": "5.3.6",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.6.tgz",
|
||||
"integrity": "sha512-jX0GAcRzvdwISuvArXn3m7KZscWWFAf1MKBcnzaN02qWMb3jpMoUX4/qgeiGzqyIb4ojulRzs89UCUmGcFSzTA==",
|
||||
"version": "5.3.7",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.7.tgz",
|
||||
"integrity": "sha512-7KgiD8UHjfcPBHEpDNg+zGz8L3LqR3GVwqZiBRFX04a1BCArZOz1r2kjly2HQ0WokqTO0v1nF+QAt8dsW4lKlw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -336,6 +374,7 @@
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"fill-range": "^7.1.1"
|
||||
@@ -345,10 +384,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz",
|
||||
"integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==",
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
||||
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"readdirp": "^4.0.1"
|
||||
},
|
||||
@@ -364,6 +404,7 @@
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
||||
"integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"detect-libc": "bin/detect-libc.js"
|
||||
@@ -377,6 +418,7 @@
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
@@ -386,9 +428,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/immutable": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.3.tgz",
|
||||
"integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==",
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz",
|
||||
"integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@@ -397,6 +439,7 @@
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
@@ -407,6 +450,7 @@
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"is-extglob": "^2.1.1"
|
||||
@@ -420,6 +464,7 @@
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
@@ -428,13 +473,15 @@
|
||||
"node_modules/jquery": {
|
||||
"version": "3.7.1",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
|
||||
"integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg=="
|
||||
"integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/micromatch": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"braces": "^3.0.3",
|
||||
@@ -448,6 +495,7 @@
|
||||
"version": "2.30.1",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
|
||||
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
@@ -457,6 +505,7 @@
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
|
||||
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
@@ -464,6 +513,7 @@
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
@@ -473,12 +523,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.1.tgz",
|
||||
"integrity": "sha512-GkMg9uOTpIWWKbSsgwb5fA4EavTR+SG/PMPoAY8hkhHfEEY0/vqljY+XHqtDf2cr2IJtoNRDbrrEpZUiZCkYRw==",
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
||||
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14.16.0"
|
||||
"node": ">= 14.18.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
@@ -499,9 +550,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/sass": {
|
||||
"version": "1.89.1",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.89.1.tgz",
|
||||
"integrity": "sha512-eMLLkl+qz7tx/0cJ9wI+w09GQ2zodTkcE/aVfywwdlRcI3EO19xGnbmJwg/JMIm+5MxVJ6outddLZ4Von4E++Q==",
|
||||
"version": "1.90.0",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.90.0.tgz",
|
||||
"integrity": "sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -520,10 +571,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
|
||||
"integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -533,6 +585,7 @@
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"is-number": "^7.0.0"
|
||||
|
@@ -51,7 +51,7 @@ test = [
|
||||
# the test test_nbclassic_control_panel.
|
||||
"nbclassic",
|
||||
"pytest>=3.3",
|
||||
"pytest-asyncio>=0.17,!=0.23.*",
|
||||
"pytest-asyncio>=0.17,!=0.23.*,<1.0.0",
|
||||
"pytest-cov",
|
||||
"pytest-rerunfailures",
|
||||
"requests-mock",
|
||||
|
Reference in New Issue
Block a user