Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -472,20 +472,10 @@ jobs:
# * false positive: only affects Arrow R package, not PyArrow
# * see CVE description: "This vulnerability only affects the arrow R package, not other Apache Arrow implementations"
# * databricks-sqlalchemy 1.x caps pyarrow<17, but upgrading requires SQLAlchemy 2.x (which is not possible for some Python versions)
# CVE-2026-32274 (black cache path injection via --python-cell-magics)
# * dev-only dependency, not used with untrusted input
# * fix requires black 26.x which changes formatting style; deferring upgrade
# CVE-2026-27448, CVE-2026-27459 (pyopenssl callback vulnerabilities)
# * transitive dep of snowflake-connector-python, not used directly
# * blocked: snowflake-connector-python pins pyOpenSSL<26.0.0 (even in latest 4.3.0 as of 2026-03-17)
# * upstream fix: https://github.com/snowflakedb/snowflake-connector-python/pull/2793
ignore-vulns: &ignore-vulns |
PYSEC-2023-121
CVE-2026-0994
PYSEC-2024-161
CVE-2026-32274
CVE-2026-27448
CVE-2026-27459

audit-all:
name: Audit - All
Expand Down
2 changes: 1 addition & 1 deletion deepnote_core/resources/jupyter/jupyter_server_config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" Configuration file for jupyter-notebook."""
"""Configuration file for jupyter-notebook."""

# pylint: disable=too-many-lines

Expand Down
2 changes: 1 addition & 1 deletion deepnote_toolkit/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def clear_config_cache() -> None:


def get_config(
config_path: Optional[Union[str, os.PathLike[str]]] = None
config_path: Optional[Union[str, os.PathLike[str]]] = None,
) -> DeepnoteConfig:
"""Load the effective configuration (memoized per config_path).

Expand Down
2 changes: 1 addition & 1 deletion deepnote_toolkit/ocelots/pyspark/implementation.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ def to_records(self, mode: Literal["json", "python"]) -> List[Dict[str, Any]]:
)

def binary_to_string_repr(
binary_data: Optional[Union[bytes, bytearray]]
binary_data: Optional[Union[bytes, bytearray]],
) -> Optional[str]:
"""Convert binary data to Python string representation (e.g., b'hello').

Expand Down
2 changes: 1 addition & 1 deletion deepnote_toolkit/runtime_initialization.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" This module contains functions to set up the Deepnote runtime environment. """
"""This module contains functions to set up the Deepnote runtime environment."""

import builtins

Expand Down
2 changes: 1 addition & 1 deletion dockerfiles/builder/constraintsgen.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" Generate a constraints.txt file from installed packages. """
"""Generate a constraints.txt file from installed packages."""

import argparse
from importlib.metadata import PackageNotFoundError, distributions, requires
Expand Down
2 changes: 1 addition & 1 deletion installer/module/constants.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" Constants for the package setup module. """
"""Constants for the package setup module."""

BASH_PROMPT_SCRIPT = """

Expand Down
2 changes: 1 addition & 1 deletion installer/module/downloader.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" This module is responsible for downloading the toolkit bundle from the given URL. """
"""This module is responsible for downloading the toolkit bundle from the given URL."""

import io
import logging
Expand Down
2 changes: 1 addition & 1 deletion installer/module/kernels.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" This module provides functions to manage Jupyter kernels. """
"""This module provides functions to manage Jupyter kernels."""

import json
import logging
Expand Down
2 changes: 1 addition & 1 deletion installer/module/symlinks.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" Module to create symlinks as part of installing toolkit."""
"""Module to create symlinks as part of installing toolkit."""

import logging
import os
Expand Down
2 changes: 1 addition & 1 deletion installer/module/types.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" This module contains the Config dataclass. """
"""This module contains the Config dataclass."""

from dataclasses import dataclass, field
from typing import Optional
Expand Down
2 changes: 1 addition & 1 deletion installer/module/virtual_environment.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" This module contains the VirtualEnvironment class. """
"""This module contains the VirtualEnvironment class."""

import logging
import os
Expand Down
486 changes: 256 additions & 230 deletions poetry.lock

Large diffs are not rendered by default.

12 changes: 7 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ dependencies = [
"filelock>=3.20.3,<4",
"pyjwt>=2.12.0,<3",
"pynacl>=1.6.2,<2", # https://github.com/deepnote/deepnote-toolkit/security/dependabot/8
"pyopenssl>=26.0.0,<27", # https://github.com/deepnote/deepnote-toolkit/security/dependabot/21
"pillow>=12.2.0,<13", # https://github.com/deepnote/deepnote-toolkit/security/dependabot/34 https://github.com/deepnote/deepnote-toolkit/security/dependabot/17

# Config dependencies - they need to be declared both in main and server extras, keep them in sync
"pydantic>=1.10.0,<3",
Expand Down Expand Up @@ -190,7 +192,7 @@ deepnote-toolkit = "deepnote_toolkit.cli.main:main"
dev = [
"pylint>=3.3.0,<4.0.0",
"flake8>=7.1.0,<8.0.0",
"black>=24.4.2,<25.0.0",
"black>=26.3.1,<27.0.0",
"isort>=5.13.2,<6.0.0",
"pytest>=8.3.1,<9.0.0",
"pytest-cov>=6.0.0,<7.0.0",
Expand All @@ -199,8 +201,8 @@ dev = [
"pre-commit>=3.6.0,<4.0.0",
"responses>=0.25.7,<0.26.0",
"parameterized>=0.9.0,<0.10.0",
"geopandas>=0.11.1,<1.1; python_version < '3.12'",
"geopandas>=0.13.2; python_version >= '3.12'",
"geopandas>=1.1.2,<2; python_version < '3.12'",
"geopandas>=1.1.2,<2; python_version >= '3.12'",
# We do not distribute PySpark for all users because it's huge dependency (300mb) and not all
# users need it. So in code we get pyspark from global module cache (since user already imported it at
# that point). But we also have it as dev dependency to provide better autocompletion and for tests
Expand All @@ -217,8 +219,8 @@ dev = [
]
license-check = [
# Dependencies needed for license checking that aren't in main production dependencies
"geopandas>=0.11.1,<1.1; python_version < '3.12'",
"geopandas>=0.13.2; python_version >= '3.12'",
"geopandas>=1.1.2,<2; python_version < '3.12'",
"geopandas>=1.1.2,<2; python_version >= '3.12'",
"pyspark>=3.5.5,<4.0.0; python_version < '3.13'",
"pyspark>=4.0.0,<5.0.0; python_version >= '3.13'"
]
Expand Down
24 changes: 8 additions & 16 deletions tests/integration/test_deepnote_toolkit_cli_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,12 +305,10 @@ def test_config_validate_valid(self, temp_config_file):
def test_config_validate_invalid(self, tmp_path, capsys):
"""Test config validate with invalid config."""
config_file = tmp_path / "invalid.toml"
config_file.write_text(
"""
config_file.write_text("""
[server]
jupyter_port = "not_a_number"
"""
)
""")

ret = main(["config", "validate", "--config", str(config_file)])
assert ret == 1
Expand Down Expand Up @@ -397,12 +395,10 @@ def test_config_migrate_command(self, tmp_path, monkeypatch):

# Create a legacy config
legacy_config = tmp_path / "legacy.toml"
legacy_config.write_text(
"""
legacy_config.write_text("""
[server]
jupyter_port = 7777
"""
)
""")

# Run migrate
ret = main(["config", "migrate", "--config", str(legacy_config)])
Expand Down Expand Up @@ -436,11 +432,9 @@ def test_config_set_invalid_path(self, tmp_path, capsys):
config_file = tmp_path / "config.toml"

# Create initial config with non-dict value
config_file.write_text(
"""
config_file.write_text("""
server = "not_a_dict"
"""
)
""")

ret = main(["config", "set", "server.port", "8080", "--file", str(config_file)])

Expand All @@ -463,12 +457,10 @@ class TestCLIWithEnvironment:
def test_config_from_environment(self, tmp_path, monkeypatch, capsys):
"""Test loading config from environment variable."""
config_file = tmp_path / "env_config.toml"
config_file.write_text(
"""
config_file.write_text("""
[server]
jupyter_port = 5555
"""
)
""")

monkeypatch.setenv("DEEPNOTE_CONFIG_FILE", str(config_file))

Expand Down
6 changes: 2 additions & 4 deletions tests/unit/test_cli_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@

def test_cli_print_runtime(tmp_path, capsys, monkeypatch):
cfg_path = tmp_path / "cfg.toml"
cfg_path.write_text(
"""
cfg_path.write_text("""
[server]
jupyter_port = 7777
""".strip()
)
""".strip())
monkeypatch.setenv("DEEPNOTE_CONFIG_FILE", str(cfg_path))

assert main(["config", "print", "--runtime"]) == 0
Expand Down
12 changes: 4 additions & 8 deletions tests/unit/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,10 @@ def test_coerce_float_picks_up_late_env_after_cache_clear(monkeypatch):
def test_loader_precedence_cli_over_env_over_file(tmp_path, monkeypatch):
# File value: 7777
config_file = tmp_path / "deepnote-toolkit.toml"
config_file.write_text(
"""
config_file.write_text("""
[server]
jupyter_port = 7777
""".strip()
)
""".strip())

# Env overlay: 8888
monkeypatch.setenv("DEEPNOTE_SERVER__JUPYTER_PORT", "8888")
Expand Down Expand Up @@ -88,12 +86,10 @@ class Args:

def test_runtime_loader_env_over_file(tmp_path, monkeypatch):
config_file = tmp_path / "conf.toml"
config_file.write_text(
"""
config_file.write_text("""
[server]
jupyter_port = 7777
""".strip()
)
""".strip())

monkeypatch.setenv("DEEPNOTE_CONFIG_FILE", str(config_file))
monkeypatch.setenv("DEEPNOTE_SERVER__JUPYTER_PORT", "8888")
Expand Down
16 changes: 4 additions & 12 deletions tests/unit/test_get_webapp_url.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,11 @@
def test_attached_mode_local_urls(tmp_path, monkeypatch):
# Attached mode (not detached, not dev)
cfg_path = tmp_path / "cfg.toml"
cfg_path.write_text(
textwrap.dedent(
"""
cfg_path.write_text(textwrap.dedent("""
[runtime]
running_in_detached_mode = false
dev_mode = false
"""
).strip()
)
""").strip())
monkeypatch.setenv("DEEPNOTE_CONFIG_FILE", str(cfg_path))

assert (
Expand All @@ -33,17 +29,13 @@ def test_attached_mode_local_urls(tmp_path, monkeypatch):

def test_detached_headers_from_config(tmp_path, monkeypatch):
cfg_path = tmp_path / "cfg.toml"
cfg_path.write_text(
textwrap.dedent(
"""
cfg_path.write_text(textwrap.dedent("""
[runtime]
running_in_detached_mode = true
project_id = "pid"
project_secret = "sec"
webapp_url = "https://wa.example"
"""
).strip()
)
""").strip())
monkeypatch.setenv("DEEPNOTE_CONFIG_FILE", str(cfg_path))

assert get_project_auth_headers() == {
Expand Down
12 changes: 4 additions & 8 deletions tests/unit/test_set_notebook_path_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ def test_set_notebook_path_uses_config_home_and_port(tmp_path, monkeypatch):
cfg_path = tmp_path / "cfg.toml"
home_dir = tmp_path / "home"
(home_dir / "work" / "folder").mkdir(parents=True, exist_ok=True)
cfg_path.write_text(
f"""
cfg_path.write_text(f"""
[paths]
home_dir = "{home_dir}"

Expand All @@ -17,8 +16,7 @@ def test_set_notebook_path_uses_config_home_and_port(tmp_path, monkeypatch):

[runtime]
running_in_detached_mode = true
""".strip()
)
""".strip())

monkeypatch.setenv("DEEPNOTE_CONFIG_FILE", str(cfg_path))

Expand Down Expand Up @@ -62,15 +60,13 @@ def test_set_notebook_path_uses_explicit_notebook_root(tmp_path, monkeypatch):
cfg_path = tmp_path / "cfg.toml"
root_dir = tmp_path / "root"
(root_dir / "x" / "y").mkdir(parents=True, exist_ok=True)
cfg_path.write_text(
f"""
cfg_path.write_text(f"""
[paths]
notebook_root = "{root_dir}"

[server]
jupyter_port = 8888
""".strip()
)
""".strip())

monkeypatch.setenv("DEEPNOTE_CONFIG_FILE", str(cfg_path))

Expand Down
12 changes: 4 additions & 8 deletions tests/unit/test_toolkit_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@ def test_logger_uses_config_log_dir(tmp_path, monkeypatch):
# Prepare config file with custom log_dir
cfg_path = tmp_path / "deepnote-toolkit.toml"
log_dir = tmp_path / "logs"
cfg_path.write_text(
f"""
cfg_path.write_text(f"""
[paths]
log_dir = "{log_dir}"
""".strip()
)
""".strip())

monkeypatch.setenv("DEEPNOTE_CONFIG_FILE", str(cfg_path))
# Ensure env fixture default does not override file (Env > File precedence)
Expand Down Expand Up @@ -53,14 +51,12 @@ def test_get_webapp_url_uses_config(tmp_path, monkeypatch):

# Prepare config for detached mode with webapp_url and project_id
cfg_path = tmp_path / "deepnote-toolkit.toml"
cfg_path.write_text(
"""
cfg_path.write_text("""
[runtime]
running_in_detached_mode = true
webapp_url = "https://webapp.example"
project_id = "abc-123"
""".strip()
)
""".strip())
monkeypatch.setenv("DEEPNOTE_CONFIG_FILE", str(cfg_path))

url = get_absolute_userpod_api_url("foo")
Expand Down
Loading