Skip to content
Merged
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
4 changes: 1 addition & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ RUN pip install -r requirements-prod.txt

COPY . .

COPY hw2-config/assets /assets

VOLUME ["/project"]

ENTRYPOINT ["python", "pygrader.py", "--config", "https://api.github.com/repos/fmipython/PythonCourse2025/contents/homeworks/homework2/config/pygrader_config_public.json", "/project"]
ENTRYPOINT ["python", "pygrader.py", "--config", "https://api.github.com/repos/fmipython/PythonCourse2025/contents/homeworks/homework3/pygrader_config_public_web.json", "/project"]
5 changes: 5 additions & 0 deletions config/2025-hw3.pylintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[FORMAT]
max-line-length=120

[MESSAGES CONTROL]
disable=trailing-whitespace,missing-module-docstring,missing-class-docstring,too-few-public-methods,unnecessary-pass,too-many-arguments,too-many-positional-arguments,too-many-instance-attributes,raise-missing-from
11 changes: 9 additions & 2 deletions grader/utils/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
PYLINT_BIN_UNIX = os.path.join("bin", "pylint")
PYLINT_BIN = PYLINT_BIN_WINDOWS if os.name == "nt" else PYLINT_BIN_UNIX
PYLINT_PATH = os.path.join(VENV_NAME, PYLINT_BIN)
PYLINTRC = os.path.join(CONFIG_DIR, "2024.pylintrc")
PYLINTRC = os.path.join(CONFIG_DIR, "2025-hw3.pylintrc")

# Pytest constants
PYTEST_BIN_WINDOWS = "pytest.exe"
Expand Down Expand Up @@ -82,4 +82,11 @@


# Ignore paths
IGNORE_DIRS = [".git", "__pycache__", ".pytest_cache", "_MACOSX"] + POSSIBLE_VENV_DIRS
IGNORE_DIRS = [
".git",
"__pycache__",
".pytest_cache",
"_MACOSX",
os.path.join("build", "lib"),
*POSSIBLE_VENV_DIRS,
]
57 changes: 47 additions & 10 deletions grader/utils/virtual_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ def setup(self) -> None:
"""
Setup the virtual environment.
Check if there is an existing venv, if so, delete it.
Check if there is a requirements.txt file.
Check if the project is a package, if yes, install.
If not, check for requirements.txt.
Create a new venv and install the requirements.
Install the grader dependencies as well.
"""
Expand All @@ -53,11 +54,6 @@ def setup(self) -> None:
shutil.rmtree(path)

# Check for requirements.txt
requirements_path = os.path.join(self._project_path, const.REQUIREMENTS_FILENAME)

does_requirements_exist = os.path.exists(requirements_path)
if not does_requirements_exist:
logger.debug("No requirements.txt file found in the project directory")

# Create new venv
logger.log(VERBOSE, "Creating new venv")
Expand All @@ -67,10 +63,28 @@ def setup(self) -> None:
logger.error("Failed to create virtual environment")
raise VirtualEnvironmentError("Failed to create virtual environment")

# Install requirements
if does_requirements_exist:
logger.log(VERBOSE, "Installing requirements")
VirtualEnvironment.__install_requirements(self._venv_path, requirements_path)
# Install project as package
# note: we haven't shown them `setup.py` so we shouldn't look for it?
# only support `pyproject.toml` configuration for now
if os.path.exists(os.path.join(self._project_path, "pyproject.toml")):
logger.log(VERBOSE, "Installing project as package")
VirtualEnvironment.__install_project_as_package(
self._venv_path, self._project_path
)
else:
# if it is not a packaged project, check for requirements.txt and install them
requirements_path = os.path.join(
self._project_path, const.REQUIREMENTS_FILENAME
)

does_requirements_exist = os.path.exists(requirements_path)
if not does_requirements_exist:
logger.debug("No requirements.txt file found in the project directory")
else:
logger.log(VERBOSE, "Installing requirements")
VirtualEnvironment.__install_requirements(
self._venv_path, requirements_path
)

# Install grader dependencies
logger.log(VERBOSE, "Installing grader dependencies")
Expand Down Expand Up @@ -106,6 +120,29 @@ def __install_requirements(venv_path: str, requirements_path: str) -> None:
logger.error("Failed to install requirements from %s", requirements_path)
raise VirtualEnvironmentError(f"Failed to install requirements from {requirements_path}")

@staticmethod
def __install_project_as_package(venv_path: str, project_path: str) -> None:
"""
Install the project as a package into the virtual environment.
:param venv_path: The path to the virtual environment.
:type venv_path: str
:param project_path: The path to the project.
:type project_path: str
:raises VirtualEnvironmentError: If the installation of the project fails.
:return: None
:rtype: None
"""

pip_path = os.path.join(venv_path, const.PIP_PATH)

output = run([pip_path, "install", project_path])

if output.returncode != 0:
logger.error("Failed to install project from %s", project_path)
raise VirtualEnvironmentError(
f"Failed to install project from {project_path}"
)


class VirtualEnvironmentError(Exception):
"""
Expand Down
Loading