diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 46badc1b..d95b5146 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,9 +1,9 @@ repos: - repo: https://github.com/psf/black - rev: 23.12.1 + rev: 24.8.0 hooks: - id: black - repo: https://github.com/pycqa/flake8 - rev: 6.1.0 + rev: 7.1.1 hooks: - id: flake8 \ No newline at end of file diff --git a/Changelog.md b/Changelog.md index e4a141ef..c84f40e0 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,13 @@ # CHANGELOG All notable changes to this project will be documented here. +## [v2.5.0] +- Ensure R packages are correctly installed (#535) +- Make PyTA version a setting (#536) +- Add `libxml2-dev` to server `Dockerfile`, required by R `tidyverse` library (#539) +- Display stderr contents if R packages fail to install (#539) +- Do not display `testthat` failure messages when test case passes (#539) + ## [v2.4.4] - Add tidyverse as a default R tester package (#512) - For the Haskell tester, make stack resolver a test setting (#526) diff --git a/client/requirements.txt b/client/requirements.txt index 70902c1a..b6871faa 100644 --- a/client/requirements.txt +++ b/client/requirements.txt @@ -1,10 +1,10 @@ flask==2.2.5;python_version<"3.8" -flask==2.3.3;python_version>="3.8" +flask==3.0.3;python_version>="3.8" python-dotenv==0.21.1;python_version<"3.8" -python-dotenv==1.0.0;python_version>="3.8" -rq==1.15.1 -redis==5.0.1 +python-dotenv==1.0.1;python_version>="3.8" +rq==1.16.2 +redis==5.0.4 jsonschema==4.17.3;python_version<"3.8" -jsonschema==4.20.0;python_version>="3.8" +jsonschema==4.22.0;python_version>="3.8" Werkzeug==2.2.3;python_version<"3.8" -Werkzeug==2.3.8;python_version>="3.8" +Werkzeug==3.0.3;python_version>="3.8" diff --git a/server/.dockerfiles/Dockerfile b/server/.dockerfiles/Dockerfile index 36884913..ff5a7598 100644 --- a/server/.dockerfiles/Dockerfile +++ b/server/.dockerfiles/Dockerfile @@ -34,6 +34,7 @@ RUN apt-get update -y && \ libjpeg-dev \ libharfbuzz-dev \ libfribidi-dev \ + libxml2-dev \ r-base RUN useradd -ms /bin/bash $LOGIN_USER && \ diff --git a/server/autotest_server/__init__.py b/server/autotest_server/__init__.py index a44d8d98..666e65b4 100644 --- a/server/autotest_server/__init__.py +++ b/server/autotest_server/__init__.py @@ -405,7 +405,10 @@ def update_test_settings(user, settings_id, test_settings, file_url): try: tester_settings["_env"] = tester_install.create_environment(tester_settings, env_dir, default_env) except Exception as e: - raise Exception(f"create tester environment failed:\n{e}") from e + error_message = f"create tester environment failed:\n{e}" + if e.stderr: + error_message += f"\nDetails (captured stderr):\n{e.stderr}" + raise Exception(error_message) from e test_settings["testers"][i] = tester_settings test_settings["_files"] = files_dir test_settings.pop("_error", None) diff --git a/server/autotest_server/testers/pyta/requirements.txt b/server/autotest_server/testers/pyta/requirements.txt index b9e7f41c..9145eaa7 100644 --- a/server/autotest_server/testers/pyta/requirements.txt +++ b/server/autotest_server/testers/pyta/requirements.txt @@ -1,3 +1 @@ -python-ta==1.4.2;python_version<"3.8" -python-ta==2.7.0; python_version>="3.8" isort<5;python_version<"3.8" diff --git a/server/autotest_server/testers/pyta/settings_schema.json b/server/autotest_server/testers/pyta/settings_schema.json index 816b1716..3983c486 100644 --- a/server/autotest_server/testers/pyta/settings_schema.json +++ b/server/autotest_server/testers/pyta/settings_schema.json @@ -25,6 +25,11 @@ "pip_requirements": { "title": "Package requirements", "type": "string" + }, + "pyta_version": { + "title": "PyTA version", + "type": "string", + "default": null } } }, diff --git a/server/autotest_server/testers/pyta/setup.py b/server/autotest_server/testers/pyta/setup.py index 4df657f0..853038eb 100644 --- a/server/autotest_server/testers/pyta/setup.py +++ b/server/autotest_server/testers/pyta/setup.py @@ -3,15 +3,21 @@ import json import subprocess +PYTA_VERSION_PREFIX = "python-ta==" +PYTA_VERSION = "2.7.0" + def create_environment(settings_, env_dir, _default_env_dir): env_data = settings_.get("env_data", {}) python_version = env_data.get("python_version", "3") - pip_requirements = ["wheel"] + env_data.get("pip_requirements", "").split() + env_properties = ["wheel"] + env_data.get("pip_requirements", "").split() + pyta_version = env_data.get("pyta_version", PYTA_VERSION) + pyta_version = PYTA_VERSION_PREFIX + pyta_version + env_properties.append(pyta_version) requirements = os.path.join(os.path.dirname(os.path.realpath(__file__)), "requirements.txt") pip = os.path.join(env_dir, "bin", "pip") subprocess.run([f"python{python_version}", "-m", "venv", "--clear", env_dir], check=True) - subprocess.run([pip, "install", "-r", requirements, *pip_requirements], check=True) + subprocess.run([pip, "install", "-r", requirements, *env_properties], check=True) return {"PYTHON": os.path.join(env_dir, "bin", "python3")} @@ -22,6 +28,8 @@ def settings(): python_versions = settings_["properties"]["env_data"]["properties"]["python_version"] python_versions["enum"] = py_versions python_versions["default"] = py_versions[-1] + pyta_version = settings_["properties"]["env_data"]["properties"]["pyta_version"] + pyta_version["default"] = PYTA_VERSION return settings_ diff --git a/server/autotest_server/testers/r/lib/r_tester_setup.R b/server/autotest_server/testers/r/lib/r_tester_setup.R index 4791a12c..4aef4b00 100644 --- a/server/autotest_server/testers/r/lib/r_tester_setup.R +++ b/server/autotest_server/testers/r/lib/r_tester_setup.R @@ -38,10 +38,13 @@ install_dep <- function(row) { } else { remote_type <- NA_character_ } + if (!('stringi' %in% rownames(installed.packages))) { + install.packages(name, configure.args="--disable-pkg-config") + } # Check if package is already installed # TODO: make this work for remote packages (with '/' in the name) - if (name %in% installed.packages() && + if (name %in% rownames(installed.packages()) && (is.na(version) || version_satisfies_criterion(name, compare, version))) { print(paste("Skipping '", name, "': package already installed", sep="")) return() @@ -61,7 +64,7 @@ install_dep <- function(row) { } } - if (!(name %in% installed.packages())) { + if (!(name %in% rownames(installed.packages()))) { stop("ERROR: Could not install package ", name) } } diff --git a/server/autotest_server/testers/r/r_tester.py b/server/autotest_server/testers/r/r_tester.py index 641ca76b..a5f99c3b 100644 --- a/server/autotest_server/testers/r/r_tester.py +++ b/server/autotest_server/testers/r/r_tester.py @@ -34,7 +34,10 @@ def run(self): successes = 0 error = False for result in self.result: - messages.append(result["message"]) + # Only add message if not a success, as testthat reports failure messages only + if result["type"] != "expectation_success": + messages.append(result["message"]) + if result["type"] == "expectation_success": self.points_total += 1 successes += 1 diff --git a/server/autotest_server/testers/r/setup.py b/server/autotest_server/testers/r/setup.py index 729808ca..16ff1326 100644 --- a/server/autotest_server/testers/r/setup.py +++ b/server/autotest_server/testers/r/setup.py @@ -10,7 +10,13 @@ def create_environment(settings_, env_dir, default_env_dir): env = {"R_LIBS_SITE": env_dir, "R_LIBS_USER": env_dir} r_tester_setup = os.path.join(os.path.dirname(os.path.realpath(__file__)), "lib", "r_tester_setup.R") - subprocess.run(["Rscript", r_tester_setup, req_string], env={**os.environ, **env}, check=True) + subprocess.run( + ["Rscript", r_tester_setup, req_string], + env={**os.environ, **env}, + check=True, + text=True, + capture_output=True, + ) return {**env, "PYTHON": os.path.join(default_env_dir, "bin", "python3")} diff --git a/server/requirements.txt b/server/requirements.txt index ae91fdd0..cecfc36d 100644 --- a/server/requirements.txt +++ b/server/requirements.txt @@ -1,9 +1,10 @@ -rq==1.15.1 +rq==1.16.2 click==8.1.7 -redis==5.0.1 +redis==5.0.4 pyyaml==6.0.1 jsonschema==4.17.3;python_version<"3.8" -jsonschema==4.20.0;python_version>="3.8" -requests==2.31.0 +jsonschema==4.22.0;python_version>="3.8" +requests==2.31.0;python_version<"3.8" +requests==2.32.3;python_version>="3.8" psycopg2-binary==2.9.9 supervisor==4.2.5