From 4f80d3ec027156da729ae5c00a47543ca1634859 Mon Sep 17 00:00:00 2001 From: Chris Pyles Date: Sun, 1 Sep 2024 13:22:22 -0700 Subject: [PATCH 1/6] py3.12 default, migrate to extras for dep mgmt, slim down grading envs --- CHANGELOG.md | 4 + docs/_static/grading-environment-r.yml | 4 +- docs/_static/grading-environment.yml | 4 +- docs/index.rst | 2 +- environment.yml | 2 +- otter/api.py | 7 +- otter/assign/assignment.py | 2 +- otter/export/exporters/base_exporter.py | 5 +- otter/export/exporters/via_html.py | 2 +- otter/export/exporters/via_latex.py | 2 +- otter/generate/__init__.py | 60 +++---- otter/grade/containers.py | 5 +- otter/run/run_autograder/__init__.py | 3 +- otter/utils.py | 9 -- poetry.lock | 153 ++---------------- pyproject.toml | 16 +- release.py | 50 ++---- .../environment.yml | 19 +-- .../gs-autograder-correct/environment.yml | 21 +-- .../rmd-autograder-correct/environment.yml | 34 +--- test/test_check/test_logs.py | 7 +- test/test_export/test_integration.py | 2 +- .../files/autograder-correct/environment.yml | 21 +-- .../autograder-custom-env/environment.yml | 21 +-- .../autograder-r-correct/environment.yml | 34 +--- .../environment.yml | 34 +--- .../autograder-token-correct/environment.yml | 21 +-- test/test_generate/files/environment.yml | 2 +- .../files/autograder/source/environment.yml | 20 +-- 29 files changed, 120 insertions(+), 446 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ccaf33836..26ec9eeb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,15 @@ **v6.0.0 (unreleased):** +* Switched to [poetry](https://python-poetry.org/) for packaging * Removed compatibility patches for nbconvert < 6 per [#777](https://github.com/ucbds-infra/otter-grader/issues/777) * Updated Otter Export to throw an error if nbconvert<6.0.0 is found * Converted Otter Export's PDF via HTML exporter to use nbconvert's WebPDF exporter per [#781](https://github.com/ucbds-infra/otter-grader/issues/781) * Removed pdfkit from dependencies * Added ability to export PDFs via HTML in grading containers per [#782](https://github.com/ucbds-infra/otter-grader/issues/782) +* Set default Python version for grading images to 3.12 +* Remove support for Python versions < 3.9 per [#668](https://github.com/ucbds-infra/otter-grader/issues/668) +* Removed `setuptools` and `pkg_resources` dependencies **v5.6.0:** diff --git a/docs/_static/grading-environment-r.yml b/docs/_static/grading-environment-r.yml index c498d1dea..d102dc241 100644 --- a/docs/_static/grading-environment-r.yml +++ b/docs/_static/grading-environment-r.yml @@ -4,7 +4,7 @@ channels: - conda-forge - r dependencies: - - python=3.9 + - python=3.12 - pip - nb_conda_kernels - r-base>=4.0.0 @@ -35,5 +35,5 @@ dependencies: - dill - numpy - gspread - - otter-grader==5.6.0 + - otter-grader[export,grading,plugins]==5.6.0 - rpy2 diff --git a/docs/_static/grading-environment.yml b/docs/_static/grading-environment.yml index dc64d2a56..d79712806 100644 --- a/docs/_static/grading-environment.yml +++ b/docs/_static/grading-environment.yml @@ -3,7 +3,7 @@ channels: - defaults - conda-forge dependencies: - - python=3.9 + - python=3.12 - pip - nb_conda_kernels - pip: @@ -23,4 +23,4 @@ dependencies: - numpy - gspread - pypdf - - otter-grader==5.6.0 + - otter-grader[export,grading,plugins]==5.6.0 diff --git a/docs/index.rst b/docs/index.rst index 2026c6ee8..aa7fd6393 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -68,7 +68,7 @@ each with a command-line interface: Installation ------------ -Otter is a Python package that is compatible with Python 3.8+. The PDF export internals require +Otter is a Python package that is compatible with Python 3.9+. The PDF export internals require either LaTeX and Pandoc or Playwright and Chromium to be installed. Docker is also required to grade assignments locally with containerization. Otter's Python package can be installed using pipx_ or pip. diff --git a/environment.yml b/environment.yml index e06078688..137c46342 100644 --- a/environment.yml +++ b/environment.yml @@ -3,7 +3,7 @@ channels: - conda-forge - defaults dependencies: - - python>=3.8 + - python>=3.9 - r-base>=4.0.0 - r-essentials - r-devtools diff --git a/otter/api.py b/otter/api.py index e8d7f6dcb..aa1f4cbe2 100644 --- a/otter/api.py +++ b/otter/api.py @@ -4,12 +4,7 @@ import os -from contextlib import redirect_stdout - -try: - from contextlib import nullcontext -except ImportError: - from .utils import nullcontext # nullcontext is new in Python 3.7 +from contextlib import nullcontext, redirect_stdout from .export import export_notebook from .run import main as run_grader diff --git a/otter/assign/assignment.py b/otter/assign/assignment.py index 16f40177d..808170bcf 100644 --- a/otter/assign/assignment.py +++ b/otter/assign/assignment.py @@ -219,7 +219,7 @@ class TestsValue(fica.Config): ) python_version: Optional[Union[str, int, float]] = fica.Key( - description = "the version of Python to use in the grading image (must be 3.6+)", + description = "the version of Python to use in the grading image (must be 3.9+)", default = None, ) diff --git a/otter/export/exporters/base_exporter.py b/otter/export/exporters/base_exporter.py index c973a06bd..96186b027 100644 --- a/otter/export/exporters/base_exporter.py +++ b/otter/export/exporters/base_exporter.py @@ -1,16 +1,17 @@ """ABC for Otter Export exporters""" +import importlib.resources import nbformat -import pkg_resources from abc import ABC, abstractmethod +from . import __name__ as pkg_name from .utils import has_begin, has_end, sub_end_for_new_page from ...utils import NBFORMAT_VERSION -TEMPLATE_DIR = pkg_resources.resource_filename(__name__, "templates") +TEMPLATE_DIR = importlib.resources.files(pkg_name) / "templates" class ExportFailedException(Exception): diff --git a/otter/export/exporters/via_html.py b/otter/export/exporters/via_html.py index 5b8c4146f..f69989a5e 100644 --- a/otter/export/exporters/via_html.py +++ b/otter/export/exporters/via_html.py @@ -27,7 +27,7 @@ def convert_notebook(cls, nb_path, dest, **kwargs): nb = cls.load_notebook(nb_path, filtering=options["filtering"], pagebreaks=options["pagebreaks"]) - nbconvert.TemplateExporter.extra_template_basedirs = [TEMPLATE_DIR] + nbconvert.TemplateExporter.extra_template_basedirs = [str(TEMPLATE_DIR)] orig_template_name = nbconvert.TemplateExporter.template_name nbconvert.TemplateExporter.template_name = options["template"] diff --git a/otter/export/exporters/via_latex.py b/otter/export/exporters/via_latex.py index 70ef0a055..aaef8c6db 100644 --- a/otter/export/exporters/via_latex.py +++ b/otter/export/exporters/via_latex.py @@ -36,7 +36,7 @@ def convert_notebook(cls, nb_path, dest, xecjk=False, **kwargs): nb = cls.load_notebook(nb_path, filtering=options["filtering"], pagebreaks=options["pagebreaks"]) - nbconvert.TemplateExporter.extra_template_basedirs = [TEMPLATE_DIR] + nbconvert.TemplateExporter.extra_template_basedirs = [str(TEMPLATE_DIR)] orig_template_name = nbconvert.TemplateExporter.template_name nbconvert.TemplateExporter.template_name = options["template"] diff --git a/otter/generate/__init__.py b/otter/generate/__init__.py index 751951877..a28d0858b 100644 --- a/otter/generate/__init__.py +++ b/otter/generate/__init__.py @@ -1,9 +1,9 @@ """Autograder configuration generator for Otter-Grader""" +import importlib.resources import json import os import pathlib -import pkg_resources import re import yaml import zipfile @@ -22,11 +22,10 @@ from ..version import __version__ -DEFAULT_PYTHON_VERSION = "3.9" +DEFAULT_PYTHON_VERSION = "3.12" OTTER_ENV_NAME = "otter-env" OTTR_VERSION = "1.5.0" -TEMPLATE_DIR = pkg_resources.resource_filename(__name__, "templates") -GENERAL_TEMPLATE_DIR = os.path.join(TEMPLATE_DIR, "general") +TEMPLATE_DIR = importlib.resources.files(__name__) / "templates" @dataclass @@ -63,47 +62,31 @@ def to_dict(self): environment["dependencies"].extend([ "gcc_linux-64", "gxx_linux-64", - "r-base>=4.0.0", - "r-essentials", - "r-devtools", "libgit2", "libgomp", + "r-base>=4.0.0", + "r-devtools", + "r-essentials", "r-gert", - "r-usethis", - "r-testthat", - "r-startup", "r-rmarkdown", + "r-startup", "r-stringi", + "r-testthat", + "r-usethis", f"r-ottr=={OTTR_VERSION}", ]) + r_extra = "" + if self.is_r: + r_extra = ",r" + pip_deps = self.requirements if self.overwrite_requirements else [ - "datascience", - "jupyter_client", - "ipykernel", - "matplotlib", - "pandas", - "ipywidgets", - "scipy", - "seaborn", - "scikit-learn", - "jinja2", - "nbconvert", - "nbconvert[webpdf]", - "nbformat", - "dill", - "numpy", - "gspread", - "pypdf", - f"otter-grader=={__version__}", + f"otter-grader[export,grading,plugins{r_extra}]=={__version__}", *self.requirements, ] environment["dependencies"].append({"pip": pip_deps}) - if self.is_r: - environment["dependencies"][-1]["pip"].append("rpy2") - if self.user_environment: environment = merge_conda_environments( self.user_environment, environment, OTTER_ENV_NAME) @@ -115,20 +98,20 @@ def to_str(self): COMMON_TEMPLATES = [ - os.path.join(TEMPLATE_DIR, "common", "run_autograder"), - os.path.join(TEMPLATE_DIR, "common", "run_otter.py"), + TEMPLATE_DIR / "common" / "run_autograder", + TEMPLATE_DIR / "common" / "run_otter.py", ] LANGUAGE_BASED_CONFIGURATIONS = { "python": { "test_file_pattern": "*.py", "requirements_filename": "requirements.txt", - "templates": [*COMMON_TEMPLATES, os.path.join(TEMPLATE_DIR, "python", "setup.sh")] + "templates": [*COMMON_TEMPLATES, TEMPLATE_DIR / "python" / "setup.sh"] }, "r": { "test_file_pattern": "*.[Rr]", "requirements_filename": "requirements.R", - "templates": [*COMMON_TEMPLATES, os.path.join(TEMPLATE_DIR, "r", "setup.sh")] + "templates": [*COMMON_TEMPLATES, TEMPLATE_DIR / "r" / "setup.sh"] }, } @@ -234,10 +217,9 @@ def main( lang_config = LANGUAGE_BASED_CONFIGURATIONS[ag_config.lang] templates = {} - for template_path in lang_config["templates"]: - fn = os.path.basename(template_path) - with open(template_path) as f: - templates[fn] = Template(f.read()) + for template in lang_config["templates"]: + fn = os.path.basename(template) + templates[fn] = Template(template.read_text()) if python_version is not None: match = re.match(r"(\d+)\.(\d+)(\.\d+)?", python_version) diff --git a/otter/grade/containers.py b/otter/grade/containers.py index 1e2ccbf83..27c175b28 100644 --- a/otter/grade/containers.py +++ b/otter/grade/containers.py @@ -1,9 +1,9 @@ """Docker container management for Otter Grade""" +import importlib.resources import json import os import pathlib -import pkg_resources import shutil import tempfile import zipfile @@ -13,6 +13,7 @@ from textwrap import indent from typing import List, Optional +from . import __name__ as pkg_name from .utils import OTTER_DOCKER_IMAGE_NAME, merge_scores_to_df, TimeoutException from ..run.run_autograder.autograder_config import AutograderConfig @@ -38,7 +39,7 @@ def build_image(ag_zip_path: str, base_image: str, tag: str, config: AutograderC ``str``: the tag of the newly-build Docker image """ image = OTTER_DOCKER_IMAGE_NAME + ":" + tag - dockerfile_path = pkg_resources.resource_filename(__name__, "Dockerfile") + dockerfile_path = str(importlib.resources.files(pkg_name) / "Dockerfile") LOGGER.info(f"Building image using {base_image} as base image") diff --git a/otter/run/run_autograder/__init__.py b/otter/run/run_autograder/__init__.py index cf0bd8d1d..348e09eec 100644 --- a/otter/run/run_autograder/__init__.py +++ b/otter/run/run_autograder/__init__.py @@ -5,13 +5,14 @@ import pandas as pd import zipfile +from contextlib import nullcontext from glob import glob from .runners import create_runner from .utils import capture_run_output, OtterRuntimeError, print_output from ...version import LOGO_WITH_VERSION -from ...utils import chdir, loggers, nullcontext, OTTER_CONFIG_FILENAME +from ...utils import chdir, loggers, OTTER_CONFIG_FILENAME __all__ = ["capture_run_output", "main"] diff --git a/otter/utils.py b/otter/utils.py index 5fc677da3..c79d313cf 100644 --- a/otter/utils.py +++ b/otter/utils.py @@ -146,15 +146,6 @@ def get_source(cell): raise TypeError(f"Unknown cell source type: {type(source)}") -@contextmanager -def nullcontext(): - """ - Yields an empty context. Added because ``contextlib.nullcontext`` was added in Python 3.7, so - earlier versions of Python require this patch. - """ - yield - - @contextmanager def load_default_file(provided_fn, default_fn, default_disabled=False): """ diff --git a/poetry.lock b/poetry.lock index ba729940f..018a6745f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -44,7 +44,7 @@ files = [ name = "appnope" version = "0.1.4" description = "Disable App Nap on macOS >= 10.9" -optional = false +optional = true python-versions = ">=3.6" files = [ {file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"}, @@ -585,7 +585,7 @@ tests = ["pytest", "pytest-cov", "pytest-xdist"] name = "debugpy" version = "1.8.5" description = "An implementation of the Debug Adapter Protocol for Python" -optional = false +optional = true python-versions = ">=3.8" files = [ {file = "debugpy-1.8.5-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:7e4d594367d6407a120b76bdaa03886e9eb652c05ba7f87e37418426ad2079f7"}, @@ -676,13 +676,13 @@ test = ["pytest (>=6)"] [[package]] name = "executing" -version = "2.0.1" +version = "2.1.0" description = "Get the currently executing AST node of a frame, and other information" optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, - {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, + {file = "executing-2.1.0-py2.py3-none-any.whl", hash = "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf"}, + {file = "executing-2.1.0.tar.gz", hash = "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab"}, ] [package.extras] @@ -1075,7 +1075,7 @@ files = [ name = "ipykernel" version = "6.29.5" description = "IPython Kernel for Jupyter" -optional = false +optional = true python-versions = ">=3.8" files = [ {file = "ipykernel-6.29.5-py3-none-any.whl", hash = "sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5"}, @@ -1212,17 +1212,6 @@ MarkupSafe = ">=2.0" [package.extras] i18n = ["Babel (>=2.7)"] -[[package]] -name = "joblib" -version = "1.4.2" -description = "Lightweight pipelining with Python functions" -optional = false -python-versions = ">=3.8" -files = [ - {file = "joblib-1.4.2-py3-none-any.whl", hash = "sha256:06d478d5674cbc267e7496a410ee875abd68e4340feff4490bcb7afb88060ae6"}, - {file = "joblib-1.4.2.tar.gz", hash = "sha256:2382c5816b2636fbd20a09e0f4e9dad4736765fdfb7dca582943b9c1366b3f0e"}, -] - [[package]] name = "jsonschema" version = "4.23.0" @@ -1781,7 +1770,7 @@ test = ["pep440", "pre-commit", "pytest", "testpath"] name = "nest-asyncio" version = "1.6.0" description = "Patch asyncio to allow nested event loops" -optional = false +optional = true python-versions = ">=3.5" files = [ {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, @@ -2196,7 +2185,7 @@ files = [ name = "psutil" version = "6.0.0" description = "Cross-platform lib for process and system monitoring in Python." -optional = false +optional = true python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ {file = "psutil-6.0.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a021da3e881cd935e64a3d0a20983bda0bb4cf80e4f74fa9bfcb1bc5785360c6"}, @@ -2482,7 +2471,7 @@ diagrams = ["jinja2", "railroad-diagrams"] name = "pypdf" version = "4.3.1" description = "A pure-python PDF library capable of splitting, merging, cropping, and transforming PDF files" -optional = false +optional = true python-versions = ">=3.6" files = [ {file = "pypdf-4.3.1-py3-none-any.whl", hash = "sha256:64b31da97eda0771ef22edb1bfecd5deee4b72c3d1736b7df2689805076d6418"}, @@ -3054,113 +3043,6 @@ files = [ [package.dependencies] pyasn1 = ">=0.1.3" -[[package]] -name = "scikit-learn" -version = "1.5.1" -description = "A set of python modules for machine learning and data mining" -optional = false -python-versions = ">=3.9" -files = [ - {file = "scikit_learn-1.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:781586c414f8cc58e71da4f3d7af311e0505a683e112f2f62919e3019abd3745"}, - {file = "scikit_learn-1.5.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:f5b213bc29cc30a89a3130393b0e39c847a15d769d6e59539cd86b75d276b1a7"}, - {file = "scikit_learn-1.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ff4ba34c2abff5ec59c803ed1d97d61b036f659a17f55be102679e88f926fac"}, - {file = "scikit_learn-1.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:161808750c267b77b4a9603cf9c93579c7a74ba8486b1336034c2f1579546d21"}, - {file = "scikit_learn-1.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:10e49170691514a94bb2e03787aa921b82dbc507a4ea1f20fd95557862c98dc1"}, - {file = "scikit_learn-1.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:154297ee43c0b83af12464adeab378dee2d0a700ccd03979e2b821e7dd7cc1c2"}, - {file = "scikit_learn-1.5.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:b5e865e9bd59396220de49cb4a57b17016256637c61b4c5cc81aaf16bc123bbe"}, - {file = "scikit_learn-1.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:909144d50f367a513cee6090873ae582dba019cb3fca063b38054fa42704c3a4"}, - {file = "scikit_learn-1.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:689b6f74b2c880276e365fe84fe4f1befd6a774f016339c65655eaff12e10cbf"}, - {file = "scikit_learn-1.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:9a07f90846313a7639af6a019d849ff72baadfa4c74c778821ae0fad07b7275b"}, - {file = "scikit_learn-1.5.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5944ce1faada31c55fb2ba20a5346b88e36811aab504ccafb9f0339e9f780395"}, - {file = "scikit_learn-1.5.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:0828673c5b520e879f2af6a9e99eee0eefea69a2188be1ca68a6121b809055c1"}, - {file = "scikit_learn-1.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:508907e5f81390e16d754e8815f7497e52139162fd69c4fdbd2dfa5d6cc88915"}, - {file = "scikit_learn-1.5.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97625f217c5c0c5d0505fa2af28ae424bd37949bb2f16ace3ff5f2f81fb4498b"}, - {file = "scikit_learn-1.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:da3f404e9e284d2b0a157e1b56b6566a34eb2798205cba35a211df3296ab7a74"}, - {file = "scikit_learn-1.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:88e0672c7ac21eb149d409c74cc29f1d611d5158175846e7a9c2427bd12b3956"}, - {file = "scikit_learn-1.5.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:7b073a27797a283187a4ef4ee149959defc350b46cbf63a84d8514fe16b69855"}, - {file = "scikit_learn-1.5.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b59e3e62d2be870e5c74af4e793293753565c7383ae82943b83383fdcf5cc5c1"}, - {file = "scikit_learn-1.5.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bd8d3a19d4bd6dc5a7d4f358c8c3a60934dc058f363c34c0ac1e9e12a31421d"}, - {file = "scikit_learn-1.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:5f57428de0c900a98389c4a433d4a3cf89de979b3aa24d1c1d251802aa15e44d"}, - {file = "scikit_learn-1.5.1.tar.gz", hash = "sha256:0ea5d40c0e3951df445721927448755d3fe1d80833b0b7308ebff5d2a45e6414"}, -] - -[package.dependencies] -joblib = ">=1.2.0" -numpy = ">=1.19.5" -scipy = ">=1.6.0" -threadpoolctl = ">=3.1.0" - -[package.extras] -benchmark = ["matplotlib (>=3.3.4)", "memory_profiler (>=0.57.0)", "pandas (>=1.1.5)"] -build = ["cython (>=3.0.10)", "meson-python (>=0.16.0)", "numpy (>=1.19.5)", "scipy (>=1.6.0)"] -docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.3.4)", "memory_profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "polars (>=0.20.23)", "pooch (>=1.6.0)", "pydata-sphinx-theme (>=0.15.3)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)", "sphinx (>=7.3.7)", "sphinx-copybutton (>=0.5.2)", "sphinx-design (>=0.5.0)", "sphinx-gallery (>=0.16.0)", "sphinx-prompt (>=1.4.0)", "sphinx-remove-toctrees (>=1.0.0.post1)", "sphinxcontrib-sass (>=0.3.4)", "sphinxext-opengraph (>=0.9.1)"] -examples = ["matplotlib (>=3.3.4)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)"] -install = ["joblib (>=1.2.0)", "numpy (>=1.19.5)", "scipy (>=1.6.0)", "threadpoolctl (>=3.1.0)"] -maintenance = ["conda-lock (==2.5.6)"] -tests = ["black (>=24.3.0)", "matplotlib (>=3.3.4)", "mypy (>=1.9)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "polars (>=0.20.23)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pyarrow (>=12.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.2.1)", "scikit-image (>=0.17.2)"] - -[[package]] -name = "scipy" -version = "1.13.1" -description = "Fundamental algorithms for scientific computing in Python" -optional = false -python-versions = ">=3.9" -files = [ - {file = "scipy-1.13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:20335853b85e9a49ff7572ab453794298bcf0354d8068c5f6775a0eabf350aca"}, - {file = "scipy-1.13.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:d605e9c23906d1994f55ace80e0125c587f96c020037ea6aa98d01b4bd2e222f"}, - {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfa31f1def5c819b19ecc3a8b52d28ffdcc7ed52bb20c9a7589669dd3c250989"}, - {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26264b282b9da0952a024ae34710c2aff7d27480ee91a2e82b7b7073c24722f"}, - {file = "scipy-1.13.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:eccfa1906eacc02de42d70ef4aecea45415f5be17e72b61bafcfd329bdc52e94"}, - {file = "scipy-1.13.1-cp310-cp310-win_amd64.whl", hash = "sha256:2831f0dc9c5ea9edd6e51e6e769b655f08ec6db6e2e10f86ef39bd32eb11da54"}, - {file = "scipy-1.13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:27e52b09c0d3a1d5b63e1105f24177e544a222b43611aaf5bc44d4a0979e32f9"}, - {file = "scipy-1.13.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:54f430b00f0133e2224c3ba42b805bfd0086fe488835effa33fa291561932326"}, - {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e89369d27f9e7b0884ae559a3a956e77c02114cc60a6058b4e5011572eea9299"}, - {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a78b4b3345f1b6f68a763c6e25c0c9a23a9fd0f39f5f3d200efe8feda560a5fa"}, - {file = "scipy-1.13.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45484bee6d65633752c490404513b9ef02475b4284c4cfab0ef946def50b3f59"}, - {file = "scipy-1.13.1-cp311-cp311-win_amd64.whl", hash = "sha256:5713f62f781eebd8d597eb3f88b8bf9274e79eeabf63afb4a737abc6c84ad37b"}, - {file = "scipy-1.13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5d72782f39716b2b3509cd7c33cdc08c96f2f4d2b06d51e52fb45a19ca0c86a1"}, - {file = "scipy-1.13.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:017367484ce5498445aade74b1d5ab377acdc65e27095155e448c88497755a5d"}, - {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:949ae67db5fa78a86e8fa644b9a6b07252f449dcf74247108c50e1d20d2b4627"}, - {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3ade0e53bc1f21358aa74ff4830235d716211d7d077e340c7349bc3542e884"}, - {file = "scipy-1.13.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2ac65fb503dad64218c228e2dc2d0a0193f7904747db43014645ae139c8fad16"}, - {file = "scipy-1.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:cdd7dacfb95fea358916410ec61bbc20440f7860333aee6d882bb8046264e949"}, - {file = "scipy-1.13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:436bbb42a94a8aeef855d755ce5a465479c721e9d684de76bf61a62e7c2b81d5"}, - {file = "scipy-1.13.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:8335549ebbca860c52bf3d02f80784e91a004b71b059e3eea9678ba994796a24"}, - {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d533654b7d221a6a97304ab63c41c96473ff04459e404b83275b60aa8f4b7004"}, - {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637e98dcf185ba7f8e663e122ebf908c4702420477ae52a04f9908707456ba4d"}, - {file = "scipy-1.13.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a014c2b3697bde71724244f63de2476925596c24285c7a637364761f8710891c"}, - {file = "scipy-1.13.1-cp39-cp39-win_amd64.whl", hash = "sha256:392e4ec766654852c25ebad4f64e4e584cf19820b980bc04960bca0b0cd6eaa2"}, - {file = "scipy-1.13.1.tar.gz", hash = "sha256:095a87a0312b08dfd6a6155cbbd310a8c51800fc931b8c0b84003014b874ed3c"}, -] - -[package.dependencies] -numpy = ">=1.22.4,<2.3" - -[package.extras] -dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pydevtool", "rich-click", "ruff", "types-psutil", "typing_extensions"] -doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.12.0)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0)", "sphinx-design (>=0.4.0)"] -test = ["array-api-strict", "asv", "gmpy2", "hypothesis (>=6.30)", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] - -[[package]] -name = "setuptools" -version = "74.0.0" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "setuptools-74.0.0-py3-none-any.whl", hash = "sha256:0274581a0037b638b9fc1c6883cc71c0210865aaa76073f7882376b641b84e8f"}, - {file = "setuptools-74.0.0.tar.gz", hash = "sha256:a85e96b8be2b906f3e3e789adec6a9323abf79758ecfa3065bd740d81158b11e"}, -] - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] -enabler = ["pytest-enabler (>=2.2)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.11.*)", "pytest-mypy"] - [[package]] name = "shellingham" version = "1.5.4" @@ -3419,17 +3301,6 @@ pure-eval = "*" [package.extras] tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] -[[package]] -name = "threadpoolctl" -version = "3.5.0" -description = "threadpoolctl" -optional = false -python-versions = ">=3.8" -files = [ - {file = "threadpoolctl-3.5.0-py3-none-any.whl", hash = "sha256:56c1e26c150397e58c4926da8eeee87533b1e32bef131bd4bf6a2f45f3185467"}, - {file = "threadpoolctl-3.5.0.tar.gz", hash = "sha256:082433502dd922bf738de0d8bcc4fdcbf0979ff44c42bd40f5af8a282f6fa107"}, -] - [[package]] name = "tinycss2" version = "1.3.0" @@ -3744,10 +3615,12 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", type = ["pytest-mypy"] [extras] +export = ["pypdf"] +grading = ["ipykernel", "jupyter_client"] plugins = ["google-api-python-client", "google-auth-oauthlib", "gspread", "six"] r = ["rpy2"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "7e4437bf807079afd2ad9a79b428027af0344383ffc47679908a84f31c6cd943" +content-hash = "a012c3eed8d11e3c8203694af73d73ee04c8466ba7f74dea1f08c6ee91f1d4f5" diff --git a/pyproject.toml b/pyproject.toml index 63db3d5c8..08287c0e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,41 +36,39 @@ google-api-python-client = { version = "*", optional = true } google-auth-oauthlib = { version = "*", optional = true } six = { version = "*", optional = true } gspread = { version = "*", optional = true } +ipykernel = { version = "*", optional = true} ipylab = "^1.0.0" ipython = "*" ipywidgets = "^8.1.5" jinja2 = "^3.1.4" +jupyter_client = { version = "*", optional = true} jupytext = "^1.16.4" nbconvert = { version = ">=6.0.0", extras = ["webpdf"], markers = "sys_platform != 'emscripten' and sys_platform != 'wasi'" } nbformat = ">=5.0.0" pandas = ">=2.0.0" +pypdf = { version = "*", optional = true } python-on-whales = "^0.72.0" pyyaml = "^6.0.2" requests = "^2.32.3" rpy2 = { version = "^3.5.16", optional = true } -setuptools = "^74.0.0" wrapt = "^1.16.0" [tool.poetry.extras] +export = ["pypdf"] +grading = ["ipykernel", "jupyter_client"] plugins = ["google-api-python-client", "google-auth-oauthlib", "gspread", "six"] r = ["rpy2"] -[tool.poetry.group.dev.dependencies] -ipykernel = "*" -jupyter_client = "*" -matplotlib = "*" -pypdf = "*" -scikit-learn = "*" -tqdm = "*" - [tool.poetry.group.test] optional = true [tool.poetry.group.test.dependencies] coverage = "^7.2.0" +matplotlib = "*" pytest = "^8.2.2" pytest-html = "*" responses = "^0.25.3" +tqdm = "*" [tool.poetry.group.docs] optional = true diff --git a/release.py b/release.py index 930fba13e..8b60d6601 100644 --- a/release.py +++ b/release.py @@ -5,7 +5,7 @@ import sys -FILES_WITH_VERSIONS = [ # do not include setup.py, otter/version.py +FILES_WITH_VERSIONS = [ # do not include pyproject.toml, CITATION.cff, otter/version.py "docs/_static/grading-environment.yml", "docs/_static/grading-environment-r.yml", "test/test_generate/files/autograder-correct/environment.yml", @@ -23,55 +23,43 @@ PARSER = argparse.ArgumentParser() PARSER.add_argument("new_version", nargs="?", default=None, help="Old version for regex search") PARSER.add_argument("--dry-run", action="store_true", default=False, help="Update files only but do not push release") -PARSER.add_argument("--git", action="store_true", default=False, help="Indicates that new release should be installed via git") -PARSER.add_argument("--test", action="store_true", default=False, help="Indicates that new release should be pushed to test PyPI") -PARSER.add_argument("--no-twine", action="store_true", default=False, help="Don't upload the release to PyPI") PARSER.add_argument("-f", "--force", action="store_true", default=False, help="Force run (ignore uncommitted changes)") -OLD_VERSION_REGEX = r"(otter-grader==\d+\.\d+\.\d+(?:\.\w+)?|git\+https:\/\/github\.com\/ucbds-infra\/otter-grader\.git@[\w\.]+)" +OLD_VERSION_REGEX = r"otter-grader(?:\[[\w,]+\])?==\d+\.\d+\.\d+(?:\.\w+)?" if __name__ == "__main__": args = PARSER.parse_args() - to_git = args.git + + if subprocess.run(["git", "diff"], stdout=subprocess.PIPE).stdout.decode("utf-8").strip() and not args.dry_run and not args.force: + raise RuntimeError( + "You have uncommitted changes. Please add and commit these changes before pushing " + "a release." + ) to_beta = False if args.new_version is not None: new_version_number = args.new_version - new_version = f"otter-grader=={new_version_number}" - to_beta = "b" in new_version.split(".")[-1] + to_beta = "b" in new_version_number.split(".")[-1] with open(FILES_WITH_VERSIONS[0]) as f: contents = f.read() - from_git = bool(re.search(r"https://github.com/ucbds-infra/otter-grader\.git@", contents)) - from_beta = bool(re.search(r"otter-grader==\d+\.\d+\.\d+\.b\d+", contents)) - - if subprocess.run(["git", "diff"], stdout=subprocess.PIPE).stdout.decode("utf-8").strip() and not args.dry_run and not args.force: - # throw error because this will commit everything when you make a release - raise RuntimeError( - "You have uncommitted changes. Please add and commit these changes before pushing " - "a release." - ) - - if to_git: - new_hash = ( - subprocess - .run(["git", "rev-parse", "HEAD"], stdout=subprocess.PIPE) - .stdout - .decode("utf-8") - .strip() - ) - new_version = f"git+https://github.com/ucbds-infra/otter-grader.git@{new_hash}" + from_beta = bool(re.search(r"otter-grader(?:\[[\w,]+\])?==\d+\.\d+\.\d+\.b\d+", contents)) - assert "new_version" in vars(), "Could not find a version -- did you specify one?" + assert "new_version_number" in vars(), "Could not find a version -- did you specify one?" for file in FILES_WITH_VERSIONS: with open(file) as f: contents = f.read() - contents = re.sub(OLD_VERSION_REGEX, new_version, contents) + matches = re.findall(OLD_VERSION_REGEX, contents) + for m in matches: + # Split on "==" so that any extras specified in the requirement are included in the + # result. e.g. "otter-grader[grading]==a.b.c" -> "otter-grader[grading]==a.b.d" + left = m.split("==")[0] + contents = contents.replace(m, f"{left}=={new_version_number}") with open(file, "w") as f: f.write(contents) @@ -126,10 +114,6 @@ with open("CITATION.cff", "w") as f: f.write(contents) - if to_git: - print(f"Versions updated. Release commit hash is {new_hash} -- commit and push to release") - sys.exit() - print(f"Versions updated. Release version is {new_version_number}") if to_beta: diff --git a/test/test_assign/files/example-autograder-correct/environment.yml b/test/test_assign/files/example-autograder-correct/environment.yml index 71e4593fe..4bb8b1bef 100644 --- a/test/test_assign/files/example-autograder-correct/environment.yml +++ b/test/test_assign/files/example-autograder-correct/environment.yml @@ -6,21 +6,4 @@ dependencies: - pip - nb_conda_kernels - pip: - - datascience - - jupyter_client - - ipykernel - - matplotlib - - pandas - - ipywidgets - - scipy - - seaborn - - scikit-learn - - jinja2 - - nbconvert - - nbconvert[webpdf] - - nbformat - - dill - - numpy - - gspread - - pypdf - - otter-grader==5.6.0 + - otter-grader[export,grading,plugins]==5.6.0 diff --git a/test/test_assign/files/gs-autograder-correct/environment.yml b/test/test_assign/files/gs-autograder-correct/environment.yml index 092a70491..dd3e6b616 100644 --- a/test/test_assign/files/gs-autograder-correct/environment.yml +++ b/test/test_assign/files/gs-autograder-correct/environment.yml @@ -3,25 +3,8 @@ channels: - defaults - conda-forge dependencies: - - python=3.9 + - python=3.12 - pip - nb_conda_kernels - pip: - - datascience - - jupyter_client - - ipykernel - - matplotlib - - pandas - - ipywidgets - - scipy - - seaborn - - scikit-learn - - jinja2 - - nbconvert - - nbconvert[webpdf] - - nbformat - - dill - - numpy - - gspread - - pypdf - - otter-grader==5.6.0 + - otter-grader[export,grading,plugins]==5.6.0 diff --git a/test/test_assign/files/rmd-autograder-correct/environment.yml b/test/test_assign/files/rmd-autograder-correct/environment.yml index 6c736f31e..c172221ce 100644 --- a/test/test_assign/files/rmd-autograder-correct/environment.yml +++ b/test/test_assign/files/rmd-autograder-correct/environment.yml @@ -4,40 +4,22 @@ channels: - conda-forge - r dependencies: - - python=3.9 + - python=3.12 - pip - nb_conda_kernels - gcc_linux-64 - gxx_linux-64 - - r-base>=4.0.0 - - r-essentials - - r-devtools - libgit2 - libgomp + - r-base>=4.0.0 + - r-devtools + - r-essentials - r-gert - - r-usethis - - r-testthat - - r-startup - r-rmarkdown + - r-startup - r-stringi + - r-testthat + - r-usethis - r-ottr==1.5.0 - pip: - - datascience - - jupyter_client - - ipykernel - - matplotlib - - pandas - - ipywidgets - - scipy - - seaborn - - scikit-learn - - jinja2 - - nbconvert - - nbconvert[webpdf] - - nbformat - - dill - - numpy - - gspread - - pypdf - - otter-grader==5.6.0 - - rpy2 + - otter-grader[export,grading,plugins,r]==5.6.0 diff --git a/test/test_check/test_logs.py b/test/test_check/test_logs.py index 9c489aa93..1e1026a12 100644 --- a/test/test_check/test_logs.py +++ b/test/test_check/test_logs.py @@ -1,11 +1,10 @@ """Tests for ``otter.check.logs``""" import os +import pandas as pd import pytest import sys -from sklearn.linear_model import LinearRegression - from otter.check.logs import Log from otter.check.notebook import Notebook, _OTTER_LOG_FILENAME from otter.check.logs import LogEntry, EventType, Log @@ -68,7 +67,7 @@ def square(x): env = { "num": 5, "func": square, - "model": LinearRegression(), + "df": pd.DataFrame(), "module": sys, "ignored_func": calendar.setfirstweekday } @@ -93,7 +92,7 @@ def square(x): log = Log.from_file(_OTTER_LOG_FILENAME) entry = log.get_question_entry("foo") env = entry.unshelve() - assert [*env] == ["num", "func", "model"] + assert [*env] == ["num", "func", "df"] env_with_factorial = entry.unshelve(dict(factorial = factorial)) assert "factorial" in env_with_factorial["func"].__globals__ diff --git a/test/test_export/test_integration.py b/test/test_export/test_integration.py index 8b463ed43..05b25a71f 100644 --- a/test/test_export/test_integration.py +++ b/test/test_export/test_integration.py @@ -9,12 +9,12 @@ import os import pytest +from contextlib import nullcontext from glob import glob from unittest import mock from otter.export import main as export from otter.export.exporters.base_exporter import BaseExporter -from otter.utils import nullcontext from ..utils import TestFileManager diff --git a/test/test_generate/files/autograder-correct/environment.yml b/test/test_generate/files/autograder-correct/environment.yml index 759939d22..884013142 100644 --- a/test/test_generate/files/autograder-correct/environment.yml +++ b/test/test_generate/files/autograder-correct/environment.yml @@ -3,26 +3,9 @@ channels: - defaults - conda-forge dependencies: - - python=3.9 + - python=3.12 - pip - nb_conda_kernels - pip: - - datascience - - jupyter_client - - ipykernel - - matplotlib - - pandas - - ipywidgets - - scipy - - seaborn - - scikit-learn - - jinja2 - - nbconvert - - nbconvert[webpdf] - - nbformat - - dill - - numpy - - gspread - - pypdf - - otter-grader==5.6.0 + - otter-grader[export,grading,plugins]==5.6.0 - tqdm diff --git a/test/test_generate/files/autograder-custom-env/environment.yml b/test/test_generate/files/autograder-custom-env/environment.yml index d19a72db8..88ab473ef 100644 --- a/test/test_generate/files/autograder-custom-env/environment.yml +++ b/test/test_generate/files/autograder-custom-env/environment.yml @@ -3,27 +3,10 @@ channels: - defaults - conda-forge dependencies: - - python=3.9 + - python=3.12 - pip - nb_conda_kernels - pip: - statsmodels - - datascience - - jupyter_client - - ipykernel - - matplotlib - - pandas - - ipywidgets - - scipy - - seaborn - - scikit-learn - - jinja2 - - nbconvert - - nbconvert[webpdf] - - nbformat - - dill - - numpy - - gspread - - pypdf - - otter-grader==5.6.0 + - otter-grader[export,grading,plugins]==5.6.0 - tqdm diff --git a/test/test_generate/files/autograder-r-correct/environment.yml b/test/test_generate/files/autograder-r-correct/environment.yml index 6c736f31e..c172221ce 100644 --- a/test/test_generate/files/autograder-r-correct/environment.yml +++ b/test/test_generate/files/autograder-r-correct/environment.yml @@ -4,40 +4,22 @@ channels: - conda-forge - r dependencies: - - python=3.9 + - python=3.12 - pip - nb_conda_kernels - gcc_linux-64 - gxx_linux-64 - - r-base>=4.0.0 - - r-essentials - - r-devtools - libgit2 - libgomp + - r-base>=4.0.0 + - r-devtools + - r-essentials - r-gert - - r-usethis - - r-testthat - - r-startup - r-rmarkdown + - r-startup - r-stringi + - r-testthat + - r-usethis - r-ottr==1.5.0 - pip: - - datascience - - jupyter_client - - ipykernel - - matplotlib - - pandas - - ipywidgets - - scipy - - seaborn - - scikit-learn - - jinja2 - - nbconvert - - nbconvert[webpdf] - - nbformat - - dill - - numpy - - gspread - - pypdf - - otter-grader==5.6.0 - - rpy2 + - otter-grader[export,grading,plugins,r]==5.6.0 diff --git a/test/test_generate/files/autograder-r-requirements-correct/environment.yml b/test/test_generate/files/autograder-r-requirements-correct/environment.yml index 6c736f31e..c172221ce 100644 --- a/test/test_generate/files/autograder-r-requirements-correct/environment.yml +++ b/test/test_generate/files/autograder-r-requirements-correct/environment.yml @@ -4,40 +4,22 @@ channels: - conda-forge - r dependencies: - - python=3.9 + - python=3.12 - pip - nb_conda_kernels - gcc_linux-64 - gxx_linux-64 - - r-base>=4.0.0 - - r-essentials - - r-devtools - libgit2 - libgomp + - r-base>=4.0.0 + - r-devtools + - r-essentials - r-gert - - r-usethis - - r-testthat - - r-startup - r-rmarkdown + - r-startup - r-stringi + - r-testthat + - r-usethis - r-ottr==1.5.0 - pip: - - datascience - - jupyter_client - - ipykernel - - matplotlib - - pandas - - ipywidgets - - scipy - - seaborn - - scikit-learn - - jinja2 - - nbconvert - - nbconvert[webpdf] - - nbformat - - dill - - numpy - - gspread - - pypdf - - otter-grader==5.6.0 - - rpy2 + - otter-grader[export,grading,plugins,r]==5.6.0 diff --git a/test/test_generate/files/autograder-token-correct/environment.yml b/test/test_generate/files/autograder-token-correct/environment.yml index 759939d22..884013142 100644 --- a/test/test_generate/files/autograder-token-correct/environment.yml +++ b/test/test_generate/files/autograder-token-correct/environment.yml @@ -3,26 +3,9 @@ channels: - defaults - conda-forge dependencies: - - python=3.9 + - python=3.12 - pip - nb_conda_kernels - pip: - - datascience - - jupyter_client - - ipykernel - - matplotlib - - pandas - - ipywidgets - - scipy - - seaborn - - scikit-learn - - jinja2 - - nbconvert - - nbconvert[webpdf] - - nbformat - - dill - - numpy - - gspread - - pypdf - - otter-grader==5.6.0 + - otter-grader[export,grading,plugins]==5.6.0 - tqdm diff --git a/test/test_generate/files/environment.yml b/test/test_generate/files/environment.yml index a548d96f1..5e96bb65f 100644 --- a/test/test_generate/files/environment.yml +++ b/test/test_generate/files/environment.yml @@ -3,7 +3,7 @@ channels: - defaults - conda-forge dependencies: - - python=3.9 + - python=3.12 - pip - pip: - statsmodels diff --git a/test/test_run/files/autograder/source/environment.yml b/test/test_run/files/autograder/source/environment.yml index 39935b188..884013142 100644 --- a/test/test_run/files/autograder/source/environment.yml +++ b/test/test_run/files/autograder/source/environment.yml @@ -3,25 +3,9 @@ channels: - defaults - conda-forge dependencies: - - python=3.9 + - python=3.12 - pip - nb_conda_kernels - pip: - - datascience - - jupyter_client - - ipykernel - - matplotlib - - pandas - - ipywidgets - - scipy - - seaborn - - scikit-learn - - jinja2 - - nbconvert - - nbformat - - dill - - numpy - - gspread - - pypdf - - otter-grader==5.6.0 + - otter-grader[export,grading,plugins]==5.6.0 - tqdm From 49801cb0be77f82163e8f90d7c5789e2de267305 Mon Sep 17 00:00:00 2001 From: Chris Pyles Date: Sun, 1 Sep 2024 13:38:56 -0700 Subject: [PATCH 2/6] update proj03 example --- examples/data-88e-proj03/proj03.ipynb | 5 ++--- examples/data-88e-proj03/requirements.txt | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/data-88e-proj03/proj03.ipynb b/examples/data-88e-proj03/proj03.ipynb index 401fddeb8..cdaa9d468 100644 --- a/examples/data-88e-proj03/proj03.ipynb +++ b/examples/data-88e-proj03/proj03.ipynb @@ -74,7 +74,6 @@ "\n", "warnings.simplefilter(action='ignore')\n", "%matplotlib inline\n", - "plt.style.use('seaborn-muted')\n", "plt.rcParams[\"figure.figsize\"] = [10,7]" ] }, @@ -2286,7 +2285,7 @@ "new_features = [\"bill_aug05\", \"bill_jul05\", \"paid_aug05\", \"paid_jul05\", \"sex_male\", ...]\n", "\"\"\" # END PROMPT\n", "\n", - "new_X = defaults[new_features] # SOLUTION\n", + "new_X = defaults[new_features].astype(float) # SOLUTION\n", "\n", "new_model = sm.OLS(Y, sm.add_constant(new_X)) # SOLUTION\n", "new_result = new_model.fit() # SOLUTION\n", @@ -2418,7 +2417,7 @@ { "data": { "text/plain": [ - "True" + "np.True_" ] }, "execution_count": 188, diff --git a/examples/data-88e-proj03/requirements.txt b/examples/data-88e-proj03/requirements.txt index ae57cb765..d28589457 100644 --- a/examples/data-88e-proj03/requirements.txt +++ b/examples/data-88e-proj03/requirements.txt @@ -1 +1,3 @@ statsmodels +matplotlib +numpy From 094179318343e5cf533d2b6988f349584a029235 Mon Sep 17 00:00:00 2001 From: Chris Pyles Date: Sun, 1 Sep 2024 16:59:45 -0700 Subject: [PATCH 3/6] catch chromium error from nbconvert --- otter/export/exporters/via_html.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/otter/export/exporters/via_html.py b/otter/export/exporters/via_html.py index f69989a5e..5ff7b5328 100644 --- a/otter/export/exporters/via_html.py +++ b/otter/export/exporters/via_html.py @@ -33,7 +33,18 @@ def convert_notebook(cls, nb_path, dest, **kwargs): exporter = nbconvert.WebPDFExporter() - pdf, _ = nbconvert.export(exporter, nb) + try: + pdf, _ = nbconvert.export(exporter, nb) + except RuntimeError as e: + # Replace nbconvert's error about installing chromium since their flag can't be passed + # to Otter. + if "--allow-chromium-download" in str(e): + raise RuntimeError( + "No suitable version of chromium was found; please install chromium by running " + "'playwright install chromium'" + ) + raise e + pdf_path = os.path.splitext(dest)[0] + ".pdf" with open(pdf_path, "wb+") as f: f.write(pdf) From 110561048bcebc8770583dcae388d47db23ee2b0 Mon Sep 17 00:00:00 2001 From: Chris Pyles Date: Sun, 1 Sep 2024 17:11:41 -0700 Subject: [PATCH 4/6] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26ec9eeb2..a45f8047f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ * Set default Python version for grading images to 3.12 * Remove support for Python versions < 3.9 per [#668](https://github.com/ucbds-infra/otter-grader/issues/668) * Removed `setuptools` and `pkg_resources` dependencies +* Remove dependencies not strictly required by Otter in the grading environment per [#739](https://github.com/ucbds-infra/otter-grader/issues/739) **v5.6.0:** From 1a202b1a6dcfec22ceea8a3e4669c79942d1104c Mon Sep 17 00:00:00 2001 From: Chris Pyles Date: Sun, 1 Sep 2024 17:26:25 -0700 Subject: [PATCH 5/6] combine export and grading extras --- docs/_static/grading-environment-r.yml | 2 +- docs/_static/grading-environment.yml | 2 +- otter/generate/__init__.py | 2 +- poetry.lock | 5 ++--- pyproject.toml | 3 +-- .../files/example-autograder-correct/environment.yml | 2 +- test/test_assign/files/gs-autograder-correct/environment.yml | 2 +- .../test_assign/files/rmd-autograder-correct/environment.yml | 2 +- test/test_generate/files/autograder-correct/environment.yml | 2 +- .../files/autograder-custom-env/environment.yml | 2 +- .../test_generate/files/autograder-r-correct/environment.yml | 2 +- .../files/autograder-r-requirements-correct/environment.yml | 2 +- .../files/autograder-token-correct/environment.yml | 2 +- test/test_run/files/autograder/source/environment.yml | 2 +- 14 files changed, 15 insertions(+), 17 deletions(-) diff --git a/docs/_static/grading-environment-r.yml b/docs/_static/grading-environment-r.yml index d102dc241..e1d0972bd 100644 --- a/docs/_static/grading-environment-r.yml +++ b/docs/_static/grading-environment-r.yml @@ -35,5 +35,5 @@ dependencies: - dill - numpy - gspread - - otter-grader[export,grading,plugins]==5.6.0 + - otter-grader[grading,plugins]==5.6.0 - rpy2 diff --git a/docs/_static/grading-environment.yml b/docs/_static/grading-environment.yml index d79712806..6365876c2 100644 --- a/docs/_static/grading-environment.yml +++ b/docs/_static/grading-environment.yml @@ -23,4 +23,4 @@ dependencies: - numpy - gspread - pypdf - - otter-grader[export,grading,plugins]==5.6.0 + - otter-grader[grading,plugins]==5.6.0 diff --git a/otter/generate/__init__.py b/otter/generate/__init__.py index a28d0858b..1e8b5e297 100644 --- a/otter/generate/__init__.py +++ b/otter/generate/__init__.py @@ -81,7 +81,7 @@ def to_dict(self): r_extra = ",r" pip_deps = self.requirements if self.overwrite_requirements else [ - f"otter-grader[export,grading,plugins{r_extra}]=={__version__}", + f"otter-grader[grading,plugins{r_extra}]=={__version__}", *self.requirements, ] diff --git a/poetry.lock b/poetry.lock index 018a6745f..114966e0a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3615,12 +3615,11 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", type = ["pytest-mypy"] [extras] -export = ["pypdf"] -grading = ["ipykernel", "jupyter_client"] +grading = ["ipykernel", "jupyter_client", "pypdf"] plugins = ["google-api-python-client", "google-auth-oauthlib", "gspread", "six"] r = ["rpy2"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "a012c3eed8d11e3c8203694af73d73ee04c8466ba7f74dea1f08c6ee91f1d4f5" +content-hash = "e612a9b502236c799d0a773b36170e7a9d9c352559f9bc6298277427d5f0efdc" diff --git a/pyproject.toml b/pyproject.toml index 08287c0e1..c79a19c11 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,8 +54,7 @@ rpy2 = { version = "^3.5.16", optional = true } wrapt = "^1.16.0" [tool.poetry.extras] -export = ["pypdf"] -grading = ["ipykernel", "jupyter_client"] +grading = ["ipykernel", "jupyter_client", "pypdf"] plugins = ["google-api-python-client", "google-auth-oauthlib", "gspread", "six"] r = ["rpy2"] diff --git a/test/test_assign/files/example-autograder-correct/environment.yml b/test/test_assign/files/example-autograder-correct/environment.yml index 4bb8b1bef..fb6a3a07e 100644 --- a/test/test_assign/files/example-autograder-correct/environment.yml +++ b/test/test_assign/files/example-autograder-correct/environment.yml @@ -6,4 +6,4 @@ dependencies: - pip - nb_conda_kernels - pip: - - otter-grader[export,grading,plugins]==5.6.0 + - otter-grader[grading,plugins]==5.6.0 diff --git a/test/test_assign/files/gs-autograder-correct/environment.yml b/test/test_assign/files/gs-autograder-correct/environment.yml index dd3e6b616..b3e327496 100644 --- a/test/test_assign/files/gs-autograder-correct/environment.yml +++ b/test/test_assign/files/gs-autograder-correct/environment.yml @@ -7,4 +7,4 @@ dependencies: - pip - nb_conda_kernels - pip: - - otter-grader[export,grading,plugins]==5.6.0 + - otter-grader[grading,plugins]==5.6.0 diff --git a/test/test_assign/files/rmd-autograder-correct/environment.yml b/test/test_assign/files/rmd-autograder-correct/environment.yml index c172221ce..f2682032e 100644 --- a/test/test_assign/files/rmd-autograder-correct/environment.yml +++ b/test/test_assign/files/rmd-autograder-correct/environment.yml @@ -22,4 +22,4 @@ dependencies: - r-usethis - r-ottr==1.5.0 - pip: - - otter-grader[export,grading,plugins,r]==5.6.0 + - otter-grader[grading,plugins,r]==5.6.0 diff --git a/test/test_generate/files/autograder-correct/environment.yml b/test/test_generate/files/autograder-correct/environment.yml index 884013142..12ded21e1 100644 --- a/test/test_generate/files/autograder-correct/environment.yml +++ b/test/test_generate/files/autograder-correct/environment.yml @@ -7,5 +7,5 @@ dependencies: - pip - nb_conda_kernels - pip: - - otter-grader[export,grading,plugins]==5.6.0 + - otter-grader[grading,plugins]==5.6.0 - tqdm diff --git a/test/test_generate/files/autograder-custom-env/environment.yml b/test/test_generate/files/autograder-custom-env/environment.yml index 88ab473ef..60338e916 100644 --- a/test/test_generate/files/autograder-custom-env/environment.yml +++ b/test/test_generate/files/autograder-custom-env/environment.yml @@ -8,5 +8,5 @@ dependencies: - nb_conda_kernels - pip: - statsmodels - - otter-grader[export,grading,plugins]==5.6.0 + - otter-grader[grading,plugins]==5.6.0 - tqdm diff --git a/test/test_generate/files/autograder-r-correct/environment.yml b/test/test_generate/files/autograder-r-correct/environment.yml index c172221ce..f2682032e 100644 --- a/test/test_generate/files/autograder-r-correct/environment.yml +++ b/test/test_generate/files/autograder-r-correct/environment.yml @@ -22,4 +22,4 @@ dependencies: - r-usethis - r-ottr==1.5.0 - pip: - - otter-grader[export,grading,plugins,r]==5.6.0 + - otter-grader[grading,plugins,r]==5.6.0 diff --git a/test/test_generate/files/autograder-r-requirements-correct/environment.yml b/test/test_generate/files/autograder-r-requirements-correct/environment.yml index c172221ce..f2682032e 100644 --- a/test/test_generate/files/autograder-r-requirements-correct/environment.yml +++ b/test/test_generate/files/autograder-r-requirements-correct/environment.yml @@ -22,4 +22,4 @@ dependencies: - r-usethis - r-ottr==1.5.0 - pip: - - otter-grader[export,grading,plugins,r]==5.6.0 + - otter-grader[grading,plugins,r]==5.6.0 diff --git a/test/test_generate/files/autograder-token-correct/environment.yml b/test/test_generate/files/autograder-token-correct/environment.yml index 884013142..12ded21e1 100644 --- a/test/test_generate/files/autograder-token-correct/environment.yml +++ b/test/test_generate/files/autograder-token-correct/environment.yml @@ -7,5 +7,5 @@ dependencies: - pip - nb_conda_kernels - pip: - - otter-grader[export,grading,plugins]==5.6.0 + - otter-grader[grading,plugins]==5.6.0 - tqdm diff --git a/test/test_run/files/autograder/source/environment.yml b/test/test_run/files/autograder/source/environment.yml index 884013142..12ded21e1 100644 --- a/test/test_run/files/autograder/source/environment.yml +++ b/test/test_run/files/autograder/source/environment.yml @@ -7,5 +7,5 @@ dependencies: - pip - nb_conda_kernels - pip: - - otter-grader[export,grading,plugins]==5.6.0 + - otter-grader[grading,plugins]==5.6.0 - tqdm From b5433c5e80e6d7f7dc314418a817f3ff4d05bff3 Mon Sep 17 00:00:00 2001 From: Chris Pyles Date: Sun, 1 Sep 2024 17:28:06 -0700 Subject: [PATCH 6/6] update run-docker-tests.yml --- .github/workflows/run-docker-tests.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/run-docker-tests.yml b/.github/workflows/run-docker-tests.yml index b133119cf..4569bfca1 100644 --- a/.github/workflows/run-docker-tests.yml +++ b/.github/workflows/run-docker-tests.yml @@ -42,7 +42,6 @@ jobs: - uses: r-lib/actions/setup-pandoc@v2 - uses: liskin/gh-pipx@v1 - if: ${{ steps.check-branch.outputs.run == 'true' }} with: packages: >- poetry @@ -56,7 +55,6 @@ jobs: cache-environment-key: requirements-${{ hashFiles('pyproject.toml') }} - name: Install dependencies - if: ${{ steps.check-branch.outputs.run == 'true' }} run: | micromamba activate otter-grader poetry install --with test --all-extras