pexams 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pexams-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Oscar José Pellicer Valero
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
pexams-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,246 @@
1
+ Metadata-Version: 2.4
2
+ Name: pexams
3
+ Version: 0.1.0
4
+ Summary: A Python library for generating and correcting exams using Playwright and OpenCV.
5
+ Author: AutoTestIA
6
+ Project-URL: Homepage, https://github.com/OscarPellicer/pexams
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Operating System :: OS Independent
9
+ Requires-Python: >=3.9
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: opencv-python
13
+ Requires-Dist: numpy
14
+ Requires-Dist: pdf2image
15
+ Requires-Dist: pydantic
16
+ Requires-Dist: Markdown
17
+ Requires-Dist: Faker
18
+ Requires-Dist: Pillow
19
+ Requires-Dist: playwright
20
+ Requires-Dist: matplotlib
21
+ Requires-Dist: pandas
22
+ Requires-Dist: tabulate
23
+ Requires-Dist: torch
24
+ Requires-Dist: torchvision
25
+ Requires-Dist: transformers
26
+ Requires-Dist: timm
27
+ Dynamic: license-file
28
+
29
+ # Pexams: Python exam generation and correction
30
+
31
+ Pexams is a library for generating beautiful multiple-choice exam sheets from simple data structures and automatically correcting them from scans using computer vision. It is similar to R/exams, but written in Python and using [Playwright](https://playwright.dev/python/) for high-fidelity PDF generation instead of LaTeX. It has the following advantages:
32
+ - It is much easier to install, as it requires only Python (no R, LaTeX, or any other external dependencies).
33
+ - It is easier to customize (it's Python + HTML/CSS!).
34
+ - It is less prone to compilation errors (again, no LaTeX!).
35
+
36
+ NOTE: This library is still in development and is not yet ready for production use. Although everything should work, there may be some bugs, missing features, or breaking changes in future versions.
37
+
38
+ ## Installation
39
+
40
+ The library has been tested on Python 3.11.
41
+
42
+ <!-- may not be needed
43
+ ### Prerequisites
44
+
45
+ - **Poppler**: Needed for `pdf2image` to convert PDFs to images during correction.
46
+ - **Windows**: `conda install -c conda-forge poppler`
47
+ - **macOS**: `brew install poppler`
48
+ - **Debian/Ubuntu**: `sudo apt-get install poppler-utils`
49
+ - -->
50
+
51
+ ### 1. Install the library
52
+
53
+ You can install the library from PyPI:
54
+ ```bash
55
+ pip install pexams
56
+ ```
57
+
58
+ If the previous command failed, you can install the library from GitHub:
59
+ ```bash
60
+ pip install git+https://github.com/OscarPellicer/pexams.git
61
+ ```
62
+
63
+ Alternatively, you can clone the repository and install it in editable mode, which is useful for development, testing and pushing changes to the repository:
64
+
65
+ ```bash
66
+ git clone https://github.com/OscarPellicer/pexams.git
67
+ cd pexams
68
+ pip install -e .
69
+ ```
70
+
71
+ ### 2. Install Playwright browsers
72
+
73
+ `pexams` uses Playwright to convert HTML to PDF. You need to download the necessary browser binaries by running:
74
+ ```bash
75
+ playwright install chromium
76
+ ```
77
+ This command only needs to be run once.
78
+
79
+ ## Quick start
80
+
81
+ This example will guide you through generating an exam with 2 different models, creating 4 simulated student scans, and then correcting them.
82
+
83
+ After installation, the `pexams` command is available globally in your environment. For the following example, we assume you are running the commands from the root of the project where `sample_test.json` is located.
84
+
85
+ ### 1. Generate the exams
86
+
87
+ Run the following command:
88
+
89
+ ```bash
90
+ pexams generate --questions-json sample_test.json --output-dir ./exam_output --num-models 2 --generate-fakes 4 --columns 2 --exam-title "Sample Exam" --exam-course "Everything 101" --exam-date "2025-10-26"
91
+ ```
92
+
93
+ This will create an `exam_output` directory containing:
94
+ - PDF files for 2 exam models.
95
+ - JSON files for each model containing the question data and correct answers.
96
+ - A `simulated_scans` subdirectory with 4 sample PNGs of filled answer sheets.
97
+
98
+ ### 2. Correct the exams
99
+
100
+ Now, let's correct the simulated scans:
101
+
102
+ ```bash
103
+ pexams correct --input-path ./exam_output/simulated_scans/ --exam-dir ./exam_output/ --output-dir ./correction_results
104
+ ```
105
+
106
+ This will create a `correction_results` directory with a CSV report and annotated images of each corrected scan.
107
+
108
+ ## Visual examples
109
+
110
+ You can view an example of a fully generated exam PDF [here](media/example_model_1.pdf).
111
+
112
+ Below is an example of a simulated answer sheet and the annotated, corrected version that the library produces.
113
+
114
+ | Simulated Scan | Corrected Scan |
115
+ | :---: | :---: |
116
+ | <img src="media/simulated.png" width="400"> | <img src="media/corrected.png" width="400"> |
117
+
118
+ The analysis module also generates a plot showing the distribution of answers for each question, which helps in identifying problematic questions, as well as a plot showing the distribution of marks, which helps in assessing the fairness of the exam.
119
+
120
+ | Answer distribution | Marks distribution |
121
+ | :---: | :---: |
122
+ | <img src="media/answer_distribution.png" width="400"> | <img src="media/mark_distribution.png" width="400"> |
123
+
124
+ ## Usage
125
+
126
+ ### Input format (JSON)
127
+
128
+ The `generate` command expects a JSON file containing the exam questions. The JSON file must conform to the following schema:
129
+
130
+ - The root object should have a single key, `questions`, which is an array of question objects.
131
+ - Each question object has the following keys:
132
+ - `id` (integer, required): A unique identifier for the question.
133
+ - `text` (string, required): The question text. You can use Markdown here. For LaTeX, enclose it in `$...$`.
134
+ - `options` (array, required): A list of option objects.
135
+ - Each option object has:
136
+ - `text` (string, required): The option text.
137
+ - `is_correct` (boolean, required): Must be `true` for exactly one option per question.
138
+ - `image_source` (string, optional): A path to a local image or a URL.
139
+
140
+ **Example `questions.json`:**
141
+ ```json
142
+ {
143
+ "questions": [
144
+ {
145
+ "id": 1,
146
+ "text": "What is the capital of France?",
147
+ "options": [
148
+ { "text": "Berlin", "is_correct": false },
149
+ { "text": "Madrid", "is_correct": false },
150
+ { "text": "Paris", "is_correct": true },
151
+ { "text": "Rome", "is_correct": false }
152
+ ]
153
+ }
154
+ ]
155
+ }
156
+ ```
157
+
158
+ ### Command line
159
+
160
+ #### Generating exams
161
+
162
+ ```bash
163
+ pexams generate --questions-json <path_to_questions.json> --output-dir <results_directory> [OPTIONS]
164
+ ```
165
+
166
+ **Common options:**
167
+ - `--num-models <int>`: Number of exam variations to generate (default: 4).
168
+ - `--exam-title <str>`: Title for the exam (default: "Final Exam").
169
+ - `--exam-course <str>`: Course name for the exam (optional).
170
+ - `--exam-date <str>`: Date of the exam (optional).
171
+ - `--font-size <str>`: Base font size, e.g., '10pt' (default: '11pt').
172
+ - `--columns <int>`: Number of question columns (1, 2, or 3; default: 1).
173
+ - `--generate-fakes <int>`: Number of simulated scans to generate for testing.
174
+ - `--generate-references`: Generates a reference scan with correct answers for each model.
175
+
176
+ #### Correcting exams
177
+
178
+ ```bash
179
+ pexams correct --input-path <path_to_scans> --exam-dir <path_to_exam_models> --output-dir <results_directory>
180
+ ```
181
+ - The `--input-path` can be a single PDF file or a folder of images (PNG, JPG).
182
+ - The `--exam-dir` must contain the `exam_model_*_questions.json` files generated alongside the exam PDFs.
183
+
184
+ ### Python API
185
+
186
+ You can also programatically use the library from Python to generate and correct exams.
187
+
188
+ #### Generating exams
189
+
190
+ ```python
191
+ from pexams import generate_exams
192
+ from pexams.schemas import PexamQuestion, PexamOption
193
+
194
+ # 1. Create your list of questions
195
+ questions = [
196
+ PexamQuestion(
197
+ id=1,
198
+ text="What is the capital of France?",
199
+ options=[
200
+ PexamOption(text="Berlin", is_correct=False),
201
+ PexamOption(text="Madrid", is_correct=False),
202
+ PexamOption(text="Paris", is_correct=True),
203
+ PexamOption(text="Rome", is_correct=False),
204
+ ]
205
+ ),
206
+ # ... more questions
207
+ ]
208
+
209
+ # 2. Generate the exam PDFs
210
+ generate_exams(
211
+ questions=questions,
212
+ output_dir="my_exams",
213
+ num_models=4,
214
+ exam_title="Geography Quiz",
215
+ exam_course="GEO101",
216
+ lang="en"
217
+ )
218
+ ```
219
+
220
+ #### Correcting exams
221
+
222
+ ```python
223
+ from pexams import correct_exams
224
+
225
+ # In a real scenario, you would load the solutions that were
226
+ # generated by the `generate_exams` function.
227
+ solutions_per_model = {
228
+ "1": { # model_id
229
+ 1: 2, # Question 1, correct option is index 2 ('C')
230
+ 2: 0,
231
+ # ... more solutions for model 1
232
+ },
233
+ "2": {
234
+ 1: 0,
235
+ 2: 3,
236
+ # ... more solutions for model 2
237
+ }
238
+ }
239
+
240
+ # Correct the scanned PDF or image folder
241
+ correct_exams(
242
+ input_path="scans/all_scans.pdf",
243
+ solutions_per_model=solutions_per_model,
244
+ output_dir="results"
245
+ )
246
+ ```
pexams-0.1.0/README.md ADDED
@@ -0,0 +1,218 @@
1
+ # Pexams: Python exam generation and correction
2
+
3
+ Pexams is a library for generating beautiful multiple-choice exam sheets from simple data structures and automatically correcting them from scans using computer vision. It is similar to R/exams, but written in Python and using [Playwright](https://playwright.dev/python/) for high-fidelity PDF generation instead of LaTeX. It has the following advantages:
4
+ - It is much easier to install, as it requires only Python (no R, LaTeX, or any other external dependencies).
5
+ - It is easier to customize (it's Python + HTML/CSS!).
6
+ - It is less prone to compilation errors (again, no LaTeX!).
7
+
8
+ NOTE: This library is still in development and is not yet ready for production use. Although everything should work, there may be some bugs, missing features, or breaking changes in future versions.
9
+
10
+ ## Installation
11
+
12
+ The library has been tested on Python 3.11.
13
+
14
+ <!-- may not be needed
15
+ ### Prerequisites
16
+
17
+ - **Poppler**: Needed for `pdf2image` to convert PDFs to images during correction.
18
+ - **Windows**: `conda install -c conda-forge poppler`
19
+ - **macOS**: `brew install poppler`
20
+ - **Debian/Ubuntu**: `sudo apt-get install poppler-utils`
21
+ - -->
22
+
23
+ ### 1. Install the library
24
+
25
+ You can install the library from PyPI:
26
+ ```bash
27
+ pip install pexams
28
+ ```
29
+
30
+ If the previous command failed, you can install the library from GitHub:
31
+ ```bash
32
+ pip install git+https://github.com/OscarPellicer/pexams.git
33
+ ```
34
+
35
+ Alternatively, you can clone the repository and install it in editable mode, which is useful for development, testing and pushing changes to the repository:
36
+
37
+ ```bash
38
+ git clone https://github.com/OscarPellicer/pexams.git
39
+ cd pexams
40
+ pip install -e .
41
+ ```
42
+
43
+ ### 2. Install Playwright browsers
44
+
45
+ `pexams` uses Playwright to convert HTML to PDF. You need to download the necessary browser binaries by running:
46
+ ```bash
47
+ playwright install chromium
48
+ ```
49
+ This command only needs to be run once.
50
+
51
+ ## Quick start
52
+
53
+ This example will guide you through generating an exam with 2 different models, creating 4 simulated student scans, and then correcting them.
54
+
55
+ After installation, the `pexams` command is available globally in your environment. For the following example, we assume you are running the commands from the root of the project where `sample_test.json` is located.
56
+
57
+ ### 1. Generate the exams
58
+
59
+ Run the following command:
60
+
61
+ ```bash
62
+ pexams generate --questions-json sample_test.json --output-dir ./exam_output --num-models 2 --generate-fakes 4 --columns 2 --exam-title "Sample Exam" --exam-course "Everything 101" --exam-date "2025-10-26"
63
+ ```
64
+
65
+ This will create an `exam_output` directory containing:
66
+ - PDF files for 2 exam models.
67
+ - JSON files for each model containing the question data and correct answers.
68
+ - A `simulated_scans` subdirectory with 4 sample PNGs of filled answer sheets.
69
+
70
+ ### 2. Correct the exams
71
+
72
+ Now, let's correct the simulated scans:
73
+
74
+ ```bash
75
+ pexams correct --input-path ./exam_output/simulated_scans/ --exam-dir ./exam_output/ --output-dir ./correction_results
76
+ ```
77
+
78
+ This will create a `correction_results` directory with a CSV report and annotated images of each corrected scan.
79
+
80
+ ## Visual examples
81
+
82
+ You can view an example of a fully generated exam PDF [here](media/example_model_1.pdf).
83
+
84
+ Below is an example of a simulated answer sheet and the annotated, corrected version that the library produces.
85
+
86
+ | Simulated Scan | Corrected Scan |
87
+ | :---: | :---: |
88
+ | <img src="media/simulated.png" width="400"> | <img src="media/corrected.png" width="400"> |
89
+
90
+ The analysis module also generates a plot showing the distribution of answers for each question, which helps in identifying problematic questions, as well as a plot showing the distribution of marks, which helps in assessing the fairness of the exam.
91
+
92
+ | Answer distribution | Marks distribution |
93
+ | :---: | :---: |
94
+ | <img src="media/answer_distribution.png" width="400"> | <img src="media/mark_distribution.png" width="400"> |
95
+
96
+ ## Usage
97
+
98
+ ### Input format (JSON)
99
+
100
+ The `generate` command expects a JSON file containing the exam questions. The JSON file must conform to the following schema:
101
+
102
+ - The root object should have a single key, `questions`, which is an array of question objects.
103
+ - Each question object has the following keys:
104
+ - `id` (integer, required): A unique identifier for the question.
105
+ - `text` (string, required): The question text. You can use Markdown here. For LaTeX, enclose it in `$...$`.
106
+ - `options` (array, required): A list of option objects.
107
+ - Each option object has:
108
+ - `text` (string, required): The option text.
109
+ - `is_correct` (boolean, required): Must be `true` for exactly one option per question.
110
+ - `image_source` (string, optional): A path to a local image or a URL.
111
+
112
+ **Example `questions.json`:**
113
+ ```json
114
+ {
115
+ "questions": [
116
+ {
117
+ "id": 1,
118
+ "text": "What is the capital of France?",
119
+ "options": [
120
+ { "text": "Berlin", "is_correct": false },
121
+ { "text": "Madrid", "is_correct": false },
122
+ { "text": "Paris", "is_correct": true },
123
+ { "text": "Rome", "is_correct": false }
124
+ ]
125
+ }
126
+ ]
127
+ }
128
+ ```
129
+
130
+ ### Command line
131
+
132
+ #### Generating exams
133
+
134
+ ```bash
135
+ pexams generate --questions-json <path_to_questions.json> --output-dir <results_directory> [OPTIONS]
136
+ ```
137
+
138
+ **Common options:**
139
+ - `--num-models <int>`: Number of exam variations to generate (default: 4).
140
+ - `--exam-title <str>`: Title for the exam (default: "Final Exam").
141
+ - `--exam-course <str>`: Course name for the exam (optional).
142
+ - `--exam-date <str>`: Date of the exam (optional).
143
+ - `--font-size <str>`: Base font size, e.g., '10pt' (default: '11pt').
144
+ - `--columns <int>`: Number of question columns (1, 2, or 3; default: 1).
145
+ - `--generate-fakes <int>`: Number of simulated scans to generate for testing.
146
+ - `--generate-references`: Generates a reference scan with correct answers for each model.
147
+
148
+ #### Correcting exams
149
+
150
+ ```bash
151
+ pexams correct --input-path <path_to_scans> --exam-dir <path_to_exam_models> --output-dir <results_directory>
152
+ ```
153
+ - The `--input-path` can be a single PDF file or a folder of images (PNG, JPG).
154
+ - The `--exam-dir` must contain the `exam_model_*_questions.json` files generated alongside the exam PDFs.
155
+
156
+ ### Python API
157
+
158
+ You can also programatically use the library from Python to generate and correct exams.
159
+
160
+ #### Generating exams
161
+
162
+ ```python
163
+ from pexams import generate_exams
164
+ from pexams.schemas import PexamQuestion, PexamOption
165
+
166
+ # 1. Create your list of questions
167
+ questions = [
168
+ PexamQuestion(
169
+ id=1,
170
+ text="What is the capital of France?",
171
+ options=[
172
+ PexamOption(text="Berlin", is_correct=False),
173
+ PexamOption(text="Madrid", is_correct=False),
174
+ PexamOption(text="Paris", is_correct=True),
175
+ PexamOption(text="Rome", is_correct=False),
176
+ ]
177
+ ),
178
+ # ... more questions
179
+ ]
180
+
181
+ # 2. Generate the exam PDFs
182
+ generate_exams(
183
+ questions=questions,
184
+ output_dir="my_exams",
185
+ num_models=4,
186
+ exam_title="Geography Quiz",
187
+ exam_course="GEO101",
188
+ lang="en"
189
+ )
190
+ ```
191
+
192
+ #### Correcting exams
193
+
194
+ ```python
195
+ from pexams import correct_exams
196
+
197
+ # In a real scenario, you would load the solutions that were
198
+ # generated by the `generate_exams` function.
199
+ solutions_per_model = {
200
+ "1": { # model_id
201
+ 1: 2, # Question 1, correct option is index 2 ('C')
202
+ 2: 0,
203
+ # ... more solutions for model 1
204
+ },
205
+ "2": {
206
+ 1: 0,
207
+ 2: 3,
208
+ # ... more solutions for model 2
209
+ }
210
+ }
211
+
212
+ # Correct the scanned PDF or image folder
213
+ correct_exams(
214
+ input_path="scans/all_scans.pdf",
215
+ solutions_per_model=solutions_per_model,
216
+ output_dir="results"
217
+ )
218
+ ```
File without changes