Skip to content

Commit

Permalink
Fix tests and set up subrepo sync (#142)
Browse files Browse the repository at this point in the history
* Create sync branch

* Remove squash from git subrepo pull.

* Trying again with the token.

* reset

* Fix poetry.lock

* Move runslow into imprint.testing.
  • Loading branch information
tbenthompson authored Dec 21, 2022
1 parent d565ed6 commit 276de73
Show file tree
Hide file tree
Showing 14 changed files with 6,123 additions and 1,467 deletions.
50 changes: 0 additions & 50 deletions .github/workflows/lint.yml

This file was deleted.

33 changes: 33 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,36 @@ jobs:
slack-message: "*Build failure on default branch!* 😱\nhttps://github.com/${{github.repository}}/actions/runs/${{github.run_id}}"
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
lint:
if: github.event.pull_request.draft == false
timeout-minutes: 15
strategy:
fail-fast: false
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Install pre-commit
run: pipx install pre-commit

- name: set PY
run: echo "PY=$(python -VV | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV

- name: Cache pre-commit
uses: actions/cache@v3
with:
path: ~/.cache/pre-commit
key: pre-commit|${{ env.PY }}|${{ hashFiles('.pre-commit-config.yaml') }}
id: precommitcache

# The hooks will be installed automatically when pre-commit run is
# called. But it's nice to do it separately for more visibility in the
# GitHub interface into where a failure happens and how long each step
# takes.
- name: Install pre-commit hooks
run: pre-commit install --install-hooks

- name: Run all pre-commit checks on all files
run: pre-commit run --color=always -a
if: github.ref == 'refs/heads/main'
115 changes: 114 additions & 1 deletion imprint/nb_util.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
"""
Tools for setting up nice Jupyter notebooks.
Tools for working with Jupyter notebooks.
1. setup_nb() - call in a notebook to set up nice defaults for plotting.
2. run_tutorial - run a tutorial notebook and return the namespace. Useful for
testing and benchmarking.
"""
import time
from pathlib import Path
from unittest import mock

import IPython
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from IPython.core.interactiveshell import prepended_to_syspath
from IPython.core.interactiveshell import warn


def magic(*text):
Expand Down Expand Up @@ -70,3 +82,104 @@ def scale_text(factor=1.0):
plt.rcParams["ytick.labelsize"] = 12 * factor
plt.rcParams["legend.fontsize"] = 15 * factor
plt.rcParams["figure.titlesize"] = 17 * factor


def safe_execfile_ipy(
self, fname, cell_indices=None, shell_futures=False, raise_exceptions=False
):
"""
A modification of
IPython.core.interactiveshell.InteractiveShell.safe_execfile_ipy which adds
the cell_indices argument. This lets us run only a subset of the cells in
a notebook.
Permalink for the copied source. If this breaks, check if the upstream
source has changed substantially.
https://github.com/ipython/ipython/blob/57eaa12cb50c9a95213b9e155032e400b9424871/IPython/core/interactiveshell.py#L2766 # noqa
Original docstring below:
Like safe_execfile, but for .ipy or .ipynb files with IPython syntax.
Parameters
----------
fname : str
The name of the file to execute. The filename must have a
.ipy or .ipynb extension.
shell_futures : bool (False)
If True, the code will share future statements with the interactive
shell. It will both be affected by previous __future__ imports, and
any __future__ imports in the code will affect the shell. If False,
__future__ imports are not shared in either direction.
raise_exceptions : bool (False)
If True raise exceptions everywhere. Meant for testing.
"""
fname = Path(fname).expanduser().resolve()

# Make sure we can open the file
try:
with fname.open("rb"):
pass
except: # noqa: E722
warn("Could not open file <%s> for safe execution." % fname)
return

# Find things also in current directory. This is needed to mimic the
# behavior of running a script from the system command line, where
# Python inserts the script's directory into sys.path
dname = str(fname.parent)

def get_cells():
"""generator for sequence of code blocks to run"""
if fname.suffix == ".ipynb":
from nbformat import read

nb = read(fname, as_version=4)
if not nb.cells:
return
for cell in nb.cells:
if cell.cell_type == "code":
yield cell.source
else:
yield fname.read_text(encoding="utf-8")

with prepended_to_syspath(dname):
try:
for i, cell in enumerate(get_cells()):
if cell_indices is not None and i not in cell_indices:
continue
print(cell)
result = self.run_cell(cell, silent=True, shell_futures=shell_futures)
if raise_exceptions:
result.raise_error()
elif not result.success:
break
except: # noqa: E722
if raise_exceptions:
raise
self.showtraceback()
warn("Unknown failure executing file: <%s>" % fname)


def run_notebook(filepath, cell_indices=None):
"""
Programmatically run a notebook return the notebook's namespace and the
execution time. This is useful for testing notebooks.
Args:
filepath: Path to the notebook to run.
cell_indices: The indices of the cells to run. Runs all cells if None.
Defaults to None.
Returns:
tuple of (namespace, execution time)
"""
# Using Agg backend to prevent figures from popping up
matplotlib.use("Agg")
# mock pyplot so that we don't spend runtime on figures that are going to
# be thrown out.
with mock.patch("matplotlib.pyplot"):
ipy = IPython.terminal.embed.InteractiveShellEmbed()
start = time.time()
safe_execfile_ipy(ipy, filepath, cell_indices=cell_indices)
end = time.time()
return ipy.user_ns, end - start
19 changes: 18 additions & 1 deletion imprint/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,28 @@ def test_foo(snapshot):
import pytest


def pytest_configure(config):
config.addinivalue_line("markers", "slow: mark test as slow to run")


def pytest_collection_modifyitems(config, items):
if config.getoption("--runslow"):
# --runslow given in cli: do not skip slow tests
return
skip_slow = pytest.mark.skip(reason="need --runslow option to run")
for item in items:
if "slow" in item.keywords:
item.add_marker(skip_slow)


def pytest_addoption(parser):
"""
Exposes snapshot plugin configuration to pytest.
https://docs.pytest.org/en/latest/reference.html#_pytest.hookspec.pytest_addoption
"""
parser.addoption(
"--runslow", action="store_true", default=False, help="run slow tests"
)
parser.addoption(
"--snapshot-update",
action="store_true",
Expand Down Expand Up @@ -133,7 +150,7 @@ def get(self, obj, serializer=None):
def __call__(self, obj, serializer=None):
"""
Return the saved copy of the object. If --snapshot-update is passed,
save the object to disk.
save the object to disk in the __snapshot__ folder.
Args:
obj: The object to compare against. This is needed here to
Expand Down
Loading

0 comments on commit 276de73

Please sign in to comment.