Skip to content
Open
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
15 changes: 8 additions & 7 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,20 @@ jobs:

- restore_cache:
keys:
- pip-cache-v1
- uv-cache-v1

- run:
name: Install uv
command: pip install --user uv

- run:
name: Install Python dependencies
command: |
pip install --upgrade --user pip
pip install --user -r build_requirements.txt
pip list
command: make env

- save_cache:
key: pip-cache-v1
key: uv-cache-v1
paths:
- ~/.cache/pip
- ~/.cache/uv

- run:
name: Build docs
Expand Down
12 changes: 3 additions & 9 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,10 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
- name: Set up uv with Python ${{ matrix.python-version }}
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
with:
python-version: ${{ matrix.python-version }}

- name: Install packages
run: |
pip install --upgrade pip wheel setuptools
pip install -r build_requirements.txt
pip list

- name: Lint
run: pre-commit run --all-files --show-diff-on-failure --color always
run: make lint
11 changes: 3 additions & 8 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.12
uses: actions/setup-python@v5
- name: Set up uv with Python 3.12
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
with:
python-version: 3.12
python-version: "3.12"

- name: Install TeX
run: |
Expand All @@ -24,11 +24,6 @@ jobs:
texlive-fonts-extra \
texlive-extra-utils

- name: Install Python dependencies
run: |
python -m pip install --upgrade pip wheel setuptools
python -m pip install -r build_requirements.txt

- name: "Build HTML"
run: |
make html
Expand Down
16 changes: 3 additions & 13 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,10 @@ jobs:
python-version: ["3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
- name: Set up uv with Python ${{ matrix.python-version }}
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
with:
python-version: ${{ matrix.python-version }}

- name: Install packages
run: |
python -m pip install -r test_requirements.txt
python -m pip list

- name: Test
run: |
# Avoid deprecation error.
export JUPYTER_PLATFORM_DIRS=1
jupyter --paths

make test
run: make test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,4 @@ advanced/advanced_numpy/test_red.png
intro/language/junk.txt
intro/language/test.pkl
joblib/
.venv/
17 changes: 13 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ To generate the html output for on-screen display, Type:
make html
```

the generated html files can be found in `build/html`
the generated html files can be found in `_build/html`

The first build takes a long time, but information is cached and
subsequent builds will be faster.
Expand All @@ -62,11 +62,20 @@ Build requirements are listed in the

```

Ensure that you have a [virtual environment](https://docs.python.org/3/library/venv.html) or conda environment
set up, then install requirements with:
With [uv](https://docs.astral.sh/uv/) installed, `make` creates a virtual
environment in `.venv` and installs all requirements into it. Make reinstalls
only when a requirements file changes.

To use your own environment instead, install the requirements:

```
pip install -r build_requirements.txt
```

then tell `make` to use the tools on your `PATH`:

```
pip install -r requirements.txt
make html VENV=
```

Note that you will also need the following system packages:
Expand Down
53 changes: 37 additions & 16 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,32 +1,41 @@
PYTHON ?= python
PIP_INSTALL_CMD ?= $(PYTHON) -m pip install
# Set VENV= (empty) to use tools already on PATH instead of a uv environment.
VENV ?= .venv
PYTHON ?= $(BIN)python
BUILD_DIR=_build/html
JL_DIR=_build/jl
REQUIREMENTS = requirements.txt build_requirements.txt test_requirements.txt jl-build-requirements.txt

html:
ifdef VENV
export VIRTUAL_ENV := $(abspath $(VENV))
export PATH := $(VIRTUAL_ENV)/bin:$(PATH)
# Make 3.81 (macOS) ignores the exported PATH when it runs a command directly.
BIN := $(VIRTUAL_ENV)/bin/
ENV_STAMP := $(VENV)/.installed
endif

html: $(ENV_STAMP)
# Check for ipynb files in source (should all be text - .md or .Rmd).
if compgen -G "*.ipynb" 2> /dev/null; then (echo "ipynb files" && exit 1); fi
jupyter-book build -W .
$(BIN)jupyter-book build -W .

jl:
jl: $(ENV_STAMP)
# Jupyter-lite files for book build.
$(PIP_INSTALL_CMD) -r jl-build-requirements.txt
rm -rf $(JL_DIR)
mkdir $(JL_DIR)
cp -r data images $(JL_DIR)
$(PYTHON) _scripts/process_notebooks.py $(JL_DIR)
$(PYTHON) -m jupyter lite build \
--contents $(JL_DIR) \
--output-dir $(BUILD_DIR)/interact \
--lite-dir $(JL_DIR)
--contents $(abspath $(JL_DIR)) \
--output-dir $(abspath $(BUILD_DIR))/interact \
--lite-dir $(abspath $(JL_DIR))

lint:
pre-commit run --all-files --show-diff-on-failure --color always
lint: $(ENV_STAMP)
$(BIN)pre-commit run --all-files --show-diff-on-failure --color always

web: html jl

github: web
ghp-import -n _build/html -p -f
$(BIN)ghp-import -n _build/html -p -f

clean: rm-ipynb
rm -rf _build
Expand All @@ -36,9 +45,21 @@ clean: rm-ipynb
rm-ipynb:
find . -name "*.ipynb" -exec rm {} \;

test:
pytest .
# Avoid a Jupyter deprecation warning, which pytest treats as an error.
test: export JUPYTER_PLATFORM_DIRS = 1
test: $(ENV_STAMP)
$(BIN)pytest .

compare-optimizers:
compare-optimizers: $(ENV_STAMP)
( cd advanced/mathematical_optimization/helper && \
python compare_optimizers.py )
$(PYTHON) compare_optimizers.py )

# Reinstall only when a requirements file is newer than the stamp.
$(ENV_STAMP): $(REQUIREMENTS)
uv venv --allow-existing $(VENV)
uv pip install $(addprefix -r ,$(REQUIREMENTS))
touch $@

env: $(ENV_STAMP)

.PHONY: html jl lint web github clean rm-ipynb test compare-optimizers env
1 change: 1 addition & 0 deletions _config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ exclude_patterns:
- data/LICENSE.txt
- .pytest_cache/*
- .ipynb_checkpoints/*
- .venv/**
- todo.md

html:
Expand Down
18 changes: 15 additions & 3 deletions _scripts/process_notebooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,15 +131,27 @@ def get_admonition_lines(nb_text, nb_path):
lines = nb_text.splitlines()
n_lines = len(lines)
admonition_lines = []
for admonition in doc.findall(dun.Admonition):
admonitions = (
node for node in doc.findall(dun.Element) if isinstance(node, dun.Admonition)
)
for admonition in admonitions:
assert admonition.line is not None
start_line = admonition.line - 1
# Find first node of subsequent doctree.
node0 = next(
admonition.findall(include_self=False, descend=False, ascend=True), None
admonition.findall(
dun.Element, include_self=False, descend=False, ascend=True
),
None,
)
# There can be a system_message as next node, in which case the correct
# line is in the 'line' attribute.
last_line = node0.get("line", node0.line) - 2 if node0 else n_lines - 1
if node0:
next_line = node0.get("line", node0.line)
assert next_line is not None
last_line = next_line - 2
else:
last_line = n_lines - 1
for end_line in range(last_line, start_line + 1, -1):
if _END_DIV_RE.match(lines[end_line]):
break
Expand Down
Loading