Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modernize scaffolding, drop py3.7, and add py3.12 #13

Merged
merged 15 commits into from
Feb 24, 2024
Merged
12 changes: 4 additions & 8 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ on:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '0 5 * * *'

permissions:
contents: read
Expand All @@ -25,7 +27,7 @@ jobs:
- ubuntu-latest
- macos-latest
- windows-latest
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11', 'pypy-3.8']
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', 'pypy-3.8']

steps:
- name: Check out code
Expand All @@ -43,13 +45,7 @@ jobs:

- name: Test with nox
run: nox
if: ${{ (matrix.python-version != '3.7') && ! (matrix.platform == 'windows-latest' && matrix.python-version == 'pypy-3.8') }}

# Skip type checkers on py3.7 because those package versions
# yield different results
- name: Test with nox (py3.7)
run: nox -s black pytest ruff
if: ${{ matrix.python-version == '3.7' }}
if: ${{ ! (matrix.platform == 'windows-latest' && matrix.python-version == 'pypy-3.8') }}

# TODO: Run tests on windows/pypy-3.8

Expand Down
15 changes: 11 additions & 4 deletions leda/gen/base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import abc
import dataclasses
import datetime
import logging
Expand All @@ -8,6 +9,7 @@

import cached_property
import nbformat
from typing_extensions import override

logger = logging.getLogger(__name__)
logger.addHandler(logging.NullHandler())
Expand Down Expand Up @@ -74,6 +76,7 @@ class _FileReport:
@dataclasses.dataclass(frozen=True)
class FileReport(Report, _FileReport):
@property
@override
def handle(self) -> str | IO:
logger.info("Reading %s", self.nb_path)
return str(self.nb_path.expanduser())
Expand All @@ -100,25 +103,29 @@ class ReportArtifact:

@dataclasses.dataclass()
class ReportGenerator:
@abc.abstractmethod
def generate(
self, nb_contents: nbformat.NotebookNode, nb_name: str | None = None
) -> bytes:
raise NotImplementedError
...


@dataclasses.dataclass()
class ReportPublisher:
@abc.abstractmethod
def publish(self, report: Report, artifact: ReportArtifact) -> str | None:
raise NotImplementedError
...


@dataclasses.dataclass()
class ReportRunner:
@abc.abstractmethod
def run(self, report: Report) -> str | None:
raise NotImplementedError
...


@dataclasses.dataclass()
class ReportSetRunner:
@abc.abstractmethod
def run(self, report_set: ReportSet) -> None:
raise NotImplementedError
...
8 changes: 6 additions & 2 deletions leda/gen/generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import termcolor
import tqdm
import traitlets
from typing_extensions import override

import leda.gen.base

Expand All @@ -35,6 +36,7 @@ def __init__(self, **kwargs: Any) -> None:
self._num_cells: int | None = None
self._pbar: tqdm.tqdm | None = None

@override
def preprocess(
self,
nb: nbformat.NotebookNode,
Expand All @@ -49,11 +51,12 @@ def preprocess(

return result

@override
def preprocess_cell(
self,
cell: nbformat.NotebookNode,
resources: dict,
cell_index: int,
index: int,
store_history: bool = True,
) -> tuple[nbformat.NotebookNode, dict]:
if self._pbar is None:
Expand All @@ -71,7 +74,7 @@ def preprocess_cell(
self._pbar.set_postfix_str(first_line)

# Note that preprocess_cell() will actually run the cell
result = super().preprocess_cell(cell, resources, cell_index)
result = super().preprocess_cell(cell, resources, index)
self._pbar.update(1)

return result # type: ignore[no-any-return]
Expand Down Expand Up @@ -137,6 +140,7 @@ def _get_exporter_kwargs(self) -> dict:

return exporter_kwargs

@override
def generate(
self,
nb_contents: nbformat.NotebookNode,
Expand Down
3 changes: 3 additions & 0 deletions leda/gen/modifiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from typing import ClassVar

import nbformat
from typing_extensions import override

import leda.gen.base

Expand Down Expand Up @@ -134,6 +135,7 @@ def _get_new_cells_bottom(self) -> list[nbformat.NotebookNode]:
),
]

@override
def modify(self, nb_contents: nbformat.NotebookNode) -> None:
logger.info("Modifying notebook")
self._check_nb(nb_contents)
Expand Down Expand Up @@ -190,6 +192,7 @@ def __post_init__(self) -> None:
local_img_dir_path = self.local_dir_path / "images"
local_img_dir_path.mkdir(parents=True, exist_ok=True)

@override
def _get_new_cells_top(self) -> list[nbformat.NotebookNode]:
new_cells = super()._get_new_cells_top()

Expand Down
4 changes: 4 additions & 0 deletions leda/gen/publishers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import logging
import pathlib

from typing_extensions import override

import leda.gen.base

logger = logging.getLogger(__name__)
Expand All @@ -20,6 +22,7 @@ def log_loudly(report_url: str) -> None:
class InMemoryReportPublisher(leda.gen.base.ReportPublisher):
artifact: leda.gen.base.ReportArtifact | None = None

@override
def publish(
self,
report: leda.gen.base.Report,
Expand All @@ -32,6 +35,7 @@ def publish(
class FileReportPublisher(leda.gen.base.ReportPublisher):
output_dir: pathlib.Path

@override
def publish(
self,
report: leda.gen.base.Report,
Expand Down
2 changes: 2 additions & 0 deletions leda/gen/runners.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from typing import Optional, cast

import nbformat
from typing_extensions import override

import leda.gen.base
import leda.gen.generators
Expand All @@ -22,6 +23,7 @@ class MainReportRunner(leda.gen.base.ReportRunner):
generator: leda.gen.base.ReportGenerator
publisher: leda.gen.base.ReportPublisher

@override
def run(self, report: leda.gen.base.Report) -> str | None:
nb_contents = nbformat.read(report.handle, as_version=4)

Expand Down
5 changes: 5 additions & 0 deletions leda/interact/dynamic.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing import Any, Callable

import ipywidgets
from typing_extensions import override

import leda.interact.base

Expand All @@ -25,21 +26,25 @@ def to_dynamic_ipywidgets(values: dict[str, Any]) -> dict[str, Any]:

class DynamicIpywidgetsInteractMode(leda.interact.base.InteractMode):
@property
@override
def dynamic(self) -> bool:
return True

@override
def init(self, plot_lib: str) -> None:
if plot_lib.lower() == "matplotlib":
import matplotlib.pyplot as plt

# Turn on interactive mode
plt.ion()

@override
def interact(self, func: Callable, **kwargs: Any) -> Any:
kwargs = to_dynamic_ipywidgets(kwargs)

return ipywidgets.interact(func, **kwargs)

@override
def process_result(self, obj: Any) -> Any:
if leda.interact.base.is_plotly(obj):
obj.show()
Expand Down
6 changes: 6 additions & 0 deletions leda/interact/panel.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import dataclasses
from typing import Any, Callable, Optional

from typing_extensions import override

import leda.interact.base
import leda.interact.core

Expand All @@ -12,9 +14,11 @@ class StaticPanelInteractMode(leda.interact.base.InteractMode):
_plot_lib: Optional[str] = dataclasses.field(default=None, init=False)

@property
@override
def dynamic(self) -> bool:
return False

@override
def init(self, plot_lib: str) -> None:
self._plot_lib = plot_lib.lower()
if self._plot_lib == "matplotlib":
Expand All @@ -39,6 +43,7 @@ def init(self, plot_lib: str) -> None:

pn.extension(pn_extension, safe_embed=True) # pyright: ignore

@override
def interact(self, func: Callable, **kwargs: Any) -> Any:
import panel as pn

Expand All @@ -57,6 +62,7 @@ def interact(self, func: Callable, **kwargs: Any) -> Any:
max_states=500, max_opts=500, progress=self.progress
)

@override
def process_result(self, obj: Any) -> Any:
import panel as pn

Expand Down
5 changes: 5 additions & 0 deletions leda/interact/static_ipywidgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing import Any, Callable, Optional

import ipywidgets
from typing_extensions import override

import leda.interact.base
import leda.interact.core
Expand All @@ -14,9 +15,11 @@ class StaticIpywidgetsInteractMode(leda.interact.base.InteractMode):
_plot_lib: Optional[str] = dataclasses.field(default=None, init=False)

@property
@override
def dynamic(self) -> bool:
return False

@override
def init(self, plot_lib: str) -> None:
self._plot_lib = plot_lib.lower()
if self._plot_lib == "matplotlib":
Expand All @@ -30,6 +33,7 @@ def init(self, plot_lib: str) -> None:
raise ValueError(self._plot_lib)

# noinspection PyProtectedMember
@override
def interact(self, func: Callable, **kwargs: Any) -> Any:
new_value: static_ipywidgets.widgets.StaticWidget

Expand Down Expand Up @@ -59,6 +63,7 @@ def interact(self, func: Callable, **kwargs: Any) -> Any:

return static_ipywidgets.interact.StaticInteract(func, **kwargs)

@override
def process_result(self, obj: Any) -> Any:
if leda.interact.base.is_matplotlib(obj):
import matplotlib.pyplot as plt
Expand Down
Loading
Loading