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
42 changes: 42 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: CI

on:
push:
branches: [master]
pull_request:
# Allow this workflow to be called from other workflows
workflow_call:

jobs:
run_tests:
name: ${{ matrix.toxenv }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.12"]
toxenv: [quality, py]

steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Install uv
uses: astral-sh/setup-uv@bd01e18f51369d5a26f1651c3cb451d3417e3bba # v6.3.1
with:
enable-cache: true
python-version: "${{ matrix.python-version }}"

- name: Install CI dependencies
run: uv sync --group ci

- name: Run tox
run: uv run tox -e ${{ matrix.toxenv }}

- name: Upload coverage to Codecov
if: matrix.toxenv == 'py' && matrix.python-version == '3.12'
uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
with:
token: ${{ secrets.CODECOV_TOKEN }}
flags: unittests
fail_ci_if_error: false
14 changes: 10 additions & 4 deletions .github/workflows/release.yml

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noticed that this is a python package but it's only being released to NPM? Not a blocker for this PR but making a note that this is strange.

Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,20 @@ on:
tags:
- '*'

permissions:
id-token: write # Required for OIDC
contents: write # For Semantic Release tagging

jobs:
run_tests:
uses: ./.github/workflows/ci.yml
secrets: inherit
permissions:
contents: read

release:
name: Release
needs: run_tests
runs-on: ubuntu-latest
permissions:
id-token: write # Required for OIDC
contents: write # For Semantic Release tagging
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
Expand Down
2 changes: 0 additions & 2 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,4 @@ include LICENSE.txt
include README.rst
# graft edx_proctoring
# prune edx_proctoring/static/proctoring/spec
recursive-include requirements *.in *.txt
global-exclude *.pyc
include requirements/constraints.txt
30 changes: 8 additions & 22 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

help: ## display this help message
@echo "Please use \`make <target>' where <target> is one of:"
@awk -F ':.*?## ' '/^[a-zA-Z]/ && NF==2 {printf "\033[36m %-25s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) | sort
@awk -F ':.*?## ' '/^[a-zA-Z]/ && NF==2 {printf "\033[36m %-25s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) | sort

clean: ## remove generated byte code, coverage reports, and build artifacts
find . -name '__pycache__' -exec rm -rf {} +
Expand All @@ -15,34 +15,20 @@ clean: ## remove generated byte code, coverage reports, and build artifacts
rm -fr dist/
rm -fr *.egg-info

COMMON_CONSTRAINTS_TXT=requirements/common_constraints.txt
.PHONY: $(COMMON_CONSTRAINTS_TXT)
$(COMMON_CONSTRAINTS_TXT):
wget -O "$(@)" https://raw.githubusercontent.com/edx/edx-lint/master/edx_lint/files/common_constraints.txt || touch "$(@)"

upgrade: export CUSTOM_COMPILE_COMMAND=make upgrade
upgrade: $(COMMON_CONSTRAINTS_TXT)
## update the requirements/*.txt files with the latest packages satisfying requirements/*.in
pip install -qr requirements/pip-tools.txt
pip-compile --upgrade --rebuild --allow-unsafe -o requirements/pip.txt requirements/pip.in
pip-compile --upgrade -o requirements/pip-tools.txt requirements/pip-tools.in
pip install -qr requirements/pip.txt
pip install -qr requirements/pip-tools.txt
pip-compile --upgrade -o requirements/base.txt requirements/base.in
pip-compile --upgrade -o requirements/server.txt requirements/server.in
pip-compile --upgrade -o requirements/testing.txt requirements/testing.in
upgrade: ## Upgrade and regenerate pinned dependencies
uv run --with edx-lint edx_lint write_uv_constraints pyproject.toml
uv lock --upgrade

requirements: ## install development environment requirements
pip install -qr requirements/base.txt
pip install -qr requirements/testing.txt

uv sync --group dev
uv tool install tox --with tox-uv

quality-python: ## Run python linters
pylint --rcfile=pylintrc mockprock setup.py
uv run tox -e quality

quality: quality-python ## Run linters

test-python: clean ## run tests using pytest and generate coverage report
pytest
uv run tox -e py312

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want this to not necessarily invoke tox. Tox is the underlying test framework for CI, but the make targets should just run the tests in the environment they exist in.

Suggested change
uv run tox -e py312
uv run pytest

@farhan farhan Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This came from the discussion in xblocks-extra#38

I interpreted that as make test-pythontox.

Should we take uv run pytest as the preferred direction?
Should we don't call any tox environment from make file For example tox -e quality?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, got it thanks, seeing it in practice here, I am noticing that one of the issues with this is that we hardcode which python version the test runs in the makefile. So to test on a new python version you'll need to add that version to tox and then run tox directly to test with the new vesion. I think this is fine. Neither of the two flows is great but since we decided this one, we can leave this as is. Thanks for the pointer and reminder.


test: test-python ## run tests
1 change: 1 addition & 0 deletions mockprock/commands.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Command line utilities"""
import argparse

from mockprock.backend import MockProckBackend


Expand Down
4 changes: 2 additions & 2 deletions mockprock/db.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from collections import namedtuple
from contextlib import closing
import json
import sqlite3
import uuid
from collections import namedtuple
from contextlib import closing


def namedtuple_factory(cursor, row):
Expand Down
3 changes: 2 additions & 1 deletion mockprock/desktop_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
These endpoints emulate a desktop proctoring application
They support starting a session, stopping a session, and pinging for availability
"""
from flask import Blueprint, jsonify
import time

from flask import Blueprint, jsonify

fake_application = Blueprint(__name__, 'mockprock')

# this assumes there's only one application "running". haha
Expand Down
1 change: 1 addition & 0 deletions mockprock/rest_api_client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from mockprock.rest_api_client.auth import SuppliedJwtAuth


def user_agent():
"""
Return a User-Agent that identifies this client.
Expand Down
5 changes: 2 additions & 3 deletions mockprock/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,16 @@
import sys
import threading
import time
from collections import Iterable
from collections.abc import Iterable
from functools import wraps
from pprint import pprint

import jwt
from flask import Flask, abort, jsonify, render_template, request

from mockprock.rest_api_client.client import OAuthAPIClient
from mockprock.db import init_app
from mockprock.desktop_views import fake_application

from mockprock.rest_api_client.client import OAuthAPIClient

app = Flask(__name__)
app.debug = True
Expand Down
130 changes: 130 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[project]
name = "mockprock"
version = "2.0.0"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this shouldn't be in here right? It should be determined by semantic release?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mockprock isn't published to PyPI, so we're using static versioning here. The 2.0.0 value is carried over from setup.py on master — no semantic-release setup is planned for this repo.

description = "Mock proctoring backend for Open edX"
readme = "README.rst"
requires-python = ">=3.12"
license = "Apache-2.0"
authors = [
{name = "Open edX Project", email = "oscm@openedx.org"},
]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Natural Language :: English",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.12",
"Framework :: Django",
"Framework :: Django :: 4.2",
"Framework :: Django :: 5.2",
]
keywords = [
"Python",
"edx",
"openedx",
"proctoring",
]
dependencies = []

[project.optional-dependencies]
server = [
"Flask<2.0",
"PyJWT",
"requests",
]

[project.entry-points."openedx.proctoring"]
mockprock = "mockprock.backend:MockProckBackend"

[project.scripts]
get-dashboard = "mockprock.commands:get_url"

[project.urls]
Repository = "https://github.com/openedx/mockprock"

[tool.setuptools.packages.find]
exclude = ["tests*", "*.tests", "*.tests.*"]

[tool.setuptools.package-data]
"mockprock" = ["templates/*"]

[dependency-groups]
test-base = [
"pytest",
"pytest-cov",
]
test = [
{include-group = "test-base"},
]
quality = [
"pylint>=3.3,<4.0",
"pylint-celery",
"pylint-django",
"isort",
"edx-lint",
]
doc = []
ci = [
"tox",
"tox-uv",
]
dev = [
{include-group = "test"},
{include-group = "quality"},
{include-group = "doc"},
"edx-lint",
]

# uv configuration
# https://docs.astral.sh/uv/reference/settings/
[tool.uv]
package = true

# edx-lint uv constraint support
# https://github.com/openedx/edx-lint
# DO NOT EDIT constraint-dependencies DIRECTLY.
# This list is managed by `edx_lint write_uv_constraints`
# and will be overwritten the next time `make upgrade` is run.
# - GLOBAL constraints: edit edx_lint/files/common_constraints.txt
# - REPO-SPECIFIC constraints: edit [tool.edx_lint].uv_constraints in this file
constraint-dependencies = [
"Django<6.0",
"elasticsearch<7.14.0",
]
[tool.edx_lint]
# This section is read by edx-lint; do not edit the constraint-dependencies directly.
uv_constraints = []

# Pytest configuration
# https://docs.pytest.org/en/stable/reference/customize.html
[tool.pytest.ini_options]
addopts = "--cov mockprock --cov-report term-missing --cov-report xml"

# Coverage configuration
# https://coverage.readthedocs.io/en/latest/config.html
[tool.coverage.run]
branch = true
source = ["mockprock"]
omit = [
"*/tests/*",
"*/__pycache__/*",
]

[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"raise AssertionError",
"raise NotImplementedError",
"if __name__ == .__main__.:",
"if TYPE_CHECKING:",
]
show_missing = true

[tool.coverage.html]
directory = "htmlcov"

2 changes: 0 additions & 2 deletions pytest.ini

This file was deleted.

1 change: 0 additions & 1 deletion requirements/base.in

This file was deleted.

6 changes: 0 additions & 6 deletions requirements/base.txt

This file was deleted.

31 changes: 0 additions & 31 deletions requirements/common_constraints.txt

This file was deleted.

12 changes: 0 additions & 12 deletions requirements/constraints.txt

This file was deleted.

3 changes: 0 additions & 3 deletions requirements/pip-tools.in

This file was deleted.

Loading
Loading