{"id":13305846,"url":"https://github.com/shriram/gradescope-racket","last_synced_at":"2026-03-01T15:37:41.291Z","repository":{"id":39641689,"uuid":"266440787","full_name":"shriram/gradescope-racket","owner":"shriram","description":"Infrastructure to autograde Racket code on Gradescope","archived":false,"fork":false,"pushed_at":"2025-02-04T13:15:12.000Z","size":52,"stargazers_count":17,"open_issues_count":10,"forks_count":8,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-10-13T17:44:41.029Z","etag":null,"topics":["gradescope","gradescope-autograder-specification","racket","racket-lang","racket-language"],"latest_commit_sha":null,"homepage":null,"language":"Racket","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shriram.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-24T00:09:20.000Z","updated_at":"2025-02-04T13:15:07.000Z","dependencies_parsed_at":"2024-08-08T22:38:23.648Z","dependency_job_id":"3d65ed70-6ed7-4798-a7dc-8e03bf28ff8d","html_url":"https://github.com/shriram/gradescope-racket","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/shriram/gradescope-racket","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shriram%2Fgradescope-racket","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shriram%2Fgradescope-racket/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shriram%2Fgradescope-racket/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shriram%2Fgradescope-racket/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shriram","download_url":"https://codeload.github.com/shriram/gradescope-racket/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shriram%2Fgradescope-racket/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29973388,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-01T15:29:09.406Z","status":"ssl_error","status_checked_at":"2026-03-01T15:28:28.558Z","response_time":124,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gradescope","gradescope-autograder-specification","racket","racket-lang","racket-language"],"created_at":"2024-07-29T17:54:36.734Z","updated_at":"2026-03-01T15:37:41.273Z","avatar_url":"https://github.com/shriram.png","language":"Racket","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Auto-Grading Racket Code in Gradescope\n\nThis repository enables educators to autograde student submissions\nwritten in [Racket](https://racket-lang.org/) on [Gradescope](https://www.gradescope.com/).\n\nAt least in its current structure, you will want to make a different\ncopy of this code for each assignment. Since this codebase is very\nlightweight, I don't anticipate changing that in the near future.\n\n## Docker\n\nGradescope relies on Docker. You don't strictly have to know how to\nuse Docker yourself, but it certainly helps.\n\nIf you're not comfortable with Docker, you can just create the test\nsuite (see below), upload files to Gradescope, and leave the building\nto them, and test on their machines. Be aware this can be quite slow,\nand if you make a mistake, you'll have to do it all over again.\n\nAssuming you will use Docker locally:\n\n1. Make a local image for testing:\n```\nmake base-image\nmake grader-image a=\u003ctag\u003e\n```\n   There are two images due to staging. The first simply installs\n   Racket, which is unlikely to change, but the second installs the\n   assignment-specific grader content, which is likely to change quite\n   a bit as you're developing it. We don't have to name both images,\n   but it might make it a bit clearer to navigate (and it's sometimes\n   also useful to go into a pristine `base-image` to test some\n   things).\n\n2. When you're ready to test, run `make grade a=\u003ctag\u003e s=\u003cdir\u003e`, where `\u003cdir\u003e` is the\nsub-directory of `tests` that houses the (mock) student submission, and `\u003ctag\u003e`\nis the assignment tag on the grader scripts. See examples below.\n\n## Creating a Test Suite\n\nThe library currently depends on `rackunit`. If you're only used to\nthe student language levels, don't worry, it's pretty similar. Stick\nto the `test-*` forms (as opposed to the `check-*` ones). You can read\nup more\n[in the documentation](https://docs.racket-lang.org/rackunit/api.html).\n\n**Warning**: Use _only_ the `test-` forms, **not** the `check-` forms!\nThe former work well in the presence of run-time errors caused by a\ncheck. The latter do not, so one erroneous test can truncate grading.\n\nCreate a file named `grade-\u003ctag\u003e.rkt`. (Leave all the other files\nalone unless you really know what you're doing.)\nFile names of this format can be automatically managed by `Makefile` and\ninstalled into Docker container and Gradescope setup script using the `a=\u003ctag\u003e`\ninput.\n\nThere are three files to help you create your own grader:\n\n- a template file, which doesn't itself work: `grade-template.rkt`\n\n- three working example files: `grade-sq.rkt`, `grade-two-funs.rkt`,\n  and `grade-macros.rkt`\n\nIf you use the template, be sure to edit only the `UPPER-CASE` parts\nof it.\n\nYou can have only one test suite per file/grading run, but test suites can be\nnested so this does not impose much of a limitation.\n\nOnce you've created your test suite, you will probably want to test it\nlocally first. This requires you to have Docker installed (but not\nnecessarily know much about how to use it). See the instructions\nabove. If you're skipping local testing, you can move on to deployment.\n\n## Naming Tests\n\nNote that all the `test-*` forms take a *name* for the test. (This is\na difference from the student languages.) To name it wisely, it is\nimportant to understand how this name is used.\n\nWhen a test fails (either the answer is incorrect, or it has an\nerror), students get a report of the failure. In the report, they see\nthe _name_ of the test, rather than the actual test or test\noutput. This is because both of those can leak the content of the\ntest. A cunning student can write a bunch of failing tests, and use\nthose to exfiltrate your test suite, which you may have wanted to keep\nprivate.\n\nMany course staff thus like to choose names that are instructive\nto the student for fixing their error, but do not give away the whole\ntest. If, on the other hand, you want students to know the full test,\nyou could just write that in the test. For instance, assuming you are\ntesting a `sq` function that squares its input, your could write any\nof these, from least to most informative:\n```\n  (test-equal? \"\" (sq -1) 1)\n  (test-equal? \"a negative number\" (sq -1) 1)\n  (test-equal? \"-1\" (sq -1) 1)\n```\n\nTest suites can also have names, and be nested. For example:\n```\n(test-suite\n  \"Test suite 1\"\n  (test-equal? \"\" (sq -1) 1)\n  (test-suite\n    \"Tricky Tests\"\n    (test-equal? \"-1\" (sq -1) 1)))\n```\n\nWhen names suites have names, the names of test suites and their tests are\nappended hierarchically when reporting test failures and errors to GradeScope.\nIn the above example, if the tricky test fails, then the test will report `Test\nsuite 1:Tricky Tests:-1` failed.\n\n## Why `define-var`\n\nYou might wonder why you have to use `define-var` to name the\nvariables you want from the module, especially if the module already\nexports them. (If you don't use `define-var` you'll get an unbound\nidentifier error.) There are two reasons:\n\n1. Some languages, like Beginning Student Language, do not export\n   names. Therefore, the autograder has to “extract” them from the\n   module, and wouldn't know which ones to extract.\n\n2. Simply accepting all the names from a module may be dangerous: a\n   malicious student could export names that override the autograder's\n   functionality (since this code is public, after all), thereby\n   giving themselves they grade they want, not the one they deserve\n   (unless it's a course on malicious behavior, in which case, they've\n   earned whatever they award).\n\n`define-var` lets you carefully limit which names the student provided\nyou actually end up with. It will first look for the exported name\nand, only if it isn't found, extract from the module. This avoids the\nslight nuisance of having to return a student's assignment for having\nforgotten to export a name. (If this behavior isn't desired, talk to\nme and I can help you edit the source.)\n\n## Why `mirror-macro`\n\nMacros are not values. Therefore, we can't simply extract the macro as\na value from the student's module. Instead, the library sets up a\nmirror of that macro in the testing module. Note that it currently has\nthe following consequences (some are weaknesses, others aren't as clear):\n\n- All evaluation happens in the student's module. Thus, all references\n  to names are resolved in that module. This means a local helper\n  function cannot be referenced directly.\n\n- Because of the way `mirror-macro` is written, the mirroring step\n  takes place each time a test *uses* a macro. This does not seem to\n  be prohibitively costly, but it is at least annoying. If this proves\n  to be a performance problem, let me know.\n\n- Because this code goes into the student's module, it uses the\n  namespace local to that module, not the names exported. Practically\n  speaking, this means it disregards `rename-out` in the student's\n  module. Since we don't expect students will be using this feature if\n  they are still at the level where this library makes sense, this\n  should not be much of a problem.\n\n## Deploying to Gradescope\n\nRun `make zip a=\u003ctag\u003e` to generate the Zip file that you upload to\nGradescope. If you have broken your grader into multiple files, be\nsure to edit the Makefile to add those other files to the archive as\nwell. (And don't forget to add them to the repository, too!)\n\nFollowing Gradescope's instructions (see below), upload the Zip.\n\nGradescope will build a Docker image for you.\n\nWhen it's ready, you can upload sample submissions and see the output\nfrom the autograder.\n\n## Examples\n\nThe directory `tests/sq/` contains mock submissions of a `sq` function\nthat squares its argument, and `grade-sq.rkt` a test suite for it. So\ninstall that test suite, then check the several mock submissions:\n```\nmake grader-image a=sq\nmake a=sq s=sq/s1\nmake a=sq s=sq/s2\n...\n```\nwhere `s1` is the first student submission, `s2` is the second,\netc. Focus on the JSON output at the end of these runs. See\n`tests/sq/README.txt` to understand how the submissions differ.\n\nThe default `Makefile` target (`grade`) will automatically try to rebuild the\ngrader-image when necessary, so running `make grader-image` is probably not\nnecessary.\n\nThe directory `tests/two-funs/` illustrates that we can test more than\none thing from a program; `grade-two-funs.rkt` is its test suite:\n```\nmake a=two-funs s=two-funs/s1\n```\n\nThe directory `tests/macros/` illustrates that we can also test for\nmacros; `grade-macros.rkt` is its test suite:\n```\nmake a=two-funs s=macros/s1\n```\n(In this directory, student programs are purposely called\n`student-code.rkt` to show that you can choose whatever names you\nwant; they don't have to be `code.rkt`.)\n\n## Scoring\n\nGradescope demands that every submission be given a numeric score:\neither one in aggregrate or one per test. I find this system quite\nfrustrating; it imposes a numerics-driven pedagogy that I don't embrace\non many assignments. Therefore, for now the score given for the\nassignment is simple: the number of passing tests divided by the total\nnumber of tests. That's it. Someday I may look into adding weights for\ntests, etc., but I'm really not excited about any of it. Either way,\nplease give your students instructions on how to interpret the numbers.\n\n## Settings for newer Apple Macs and other Alternative Platforms\n\nOn [Apple Silicon][how-to-tell] or other arm64 based architectures,\nthese Docker images will not build correctly, because the\n`gradescope-base` images expect an amd64 platform. To work around\nthis, users will need to either\n\n- Set the `DOCKER_DEFAULT_PLATFORM` environment variable (permanently\n  by adding `export DOCKER_DEFAULT_PLATFORM=linux/amd64` to your\n  `bashrc`) or\n- If you regularly use Docker for other purposes, you could add to the\n  flag `--platform=linux/amd64` to the `docker build` and `docker run`\n  commands in the `Makefile`.\n\n## Open Issues\n\nSee \u003chttps://github.com/shriram/gradescope-racket/issues/\u003e.\n\n## Is This Current?\n\nThis code has been tested with Gradescope in late August 30, 2024, using\nRacket 8.14. Since Gradescope's APIs are in some flux, you may\nencounter errors with newer versions; contact me and I'll try to\nhelp. In addition, Gradescope intends to make it easier to deploy\nautograders using Docker; when that happens, it would be nice to\nupgrade this system.\n\nThis code does not have any non-vanilla-Racket dependencies.\n\n## Gradescope Specs\n\nGradescope's \"specs\" are currently at:\n\n\u003chttps://gradescope-autograders.readthedocs.io/en/latest/getting_started/\u003e\n\n\u003chttps://gradescope-autograders.readthedocs.io/en/latest/specs/\u003e\n\n\u003chttps://gradescope-autograders.readthedocs.io/en/latest/manual_docker/\u003e\n\n\u003chttps://gradescope-autograders.readthedocs.io/en/latest/git_pull/\u003e\n\n## Acknowledgments\n\nThanks to Matthew Flatt, Alex Harsanyi, David Storrs, Alexis King,\nMatthias Felleisen, Joe Politz, and James Tompkin.\n\n[how-to-tell]: https://support.apple.com/en-us/116943\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshriram%2Fgradescope-racket","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshriram%2Fgradescope-racket","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshriram%2Fgradescope-racket/lists"}