chipotle-quests 0.1.0__py3-none-any.whl
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.
- chipotle_quests-0.1.0.dist-info/METADATA +293 -0
- chipotle_quests-0.1.0.dist-info/RECORD +10 -0
- chipotle_quests-0.1.0.dist-info/WHEEL +5 -0
- chipotle_quests-0.1.0.dist-info/licenses/LICENSE +674 -0
- chipotle_quests-0.1.0.dist-info/top_level.txt +5 -0
- progression.py +27 -0
- quest_descriptions.py +161 -0
- quest_manager.py +121 -0
- quest_validation.py +15 -0
- storage.py +224 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: chipotle-quests
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Turn everyday tasks into fantasy quests and manage quest lists.
|
|
5
|
+
Author: Team Chipotle
|
|
6
|
+
License-Expression: GPL-3.0-only
|
|
7
|
+
Project-URL: Repository, https://github.com/software-students-fall2026/python-package-exercise-Chipotle
|
|
8
|
+
Requires-Python: >=3.11
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Dynamic: license-file
|
|
12
|
+
|
|
13
|
+
[](https://github.com/software-students-fall2026/python-package-exercise-Chipotle/actions/workflows/ci.yml)
|
|
14
|
+
|
|
15
|
+
# Python Package Exercise - RPG Quest Planner
|
|
16
|
+
|
|
17
|
+
Turn everyday tasks into fantasy quests. Enter a task title and planned duration, then manage the saved quest and earn XP when you complete it. The Flask app stores quests and player progress locally in SQLite.
|
|
18
|
+
|
|
19
|
+
## Development setup
|
|
20
|
+
|
|
21
|
+
Use Python 3.11 or newer. Run these commands from the repository root.
|
|
22
|
+
Pipenv is installed in `.tools` and project dependencies in `.venv`.
|
|
23
|
+
|
|
24
|
+
On macOS/Linux:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
python3 -m venv .tools
|
|
28
|
+
.tools/bin/python -m pip install pipenv==2026.11.0
|
|
29
|
+
export PIPENV_VENV_IN_PROJECT=1
|
|
30
|
+
.tools/bin/pipenv --python "$(command -v python3)"
|
|
31
|
+
.tools/bin/pipenv sync --dev
|
|
32
|
+
.tools/bin/pipenv run python -m playwright install chromium
|
|
33
|
+
.tools/bin/pipenv run test
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
On Windows PowerShell (`py -3` must select Python 3.11 or newer):
|
|
37
|
+
|
|
38
|
+
```powershell
|
|
39
|
+
py -3 -m venv .tools
|
|
40
|
+
.\.tools\Scripts\python.exe -m pip install pipenv==2026.11.0
|
|
41
|
+
$env:PIPENV_VENV_IN_PROJECT = "1"
|
|
42
|
+
.\.tools\Scripts\pipenv.exe --python (py -3 -c "import sys; print(sys.executable)")
|
|
43
|
+
.\.tools\Scripts\pipenv.exe sync --dev
|
|
44
|
+
.\.tools\Scripts\pipenv.exe run python -m playwright install chromium
|
|
45
|
+
.\.tools\Scripts\pipenv.exe run test
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`sync --dev` installs the development versions recorded in `Pipfile.lock`.
|
|
49
|
+
The `test` script runs the existing pytest tests. `colorama` is explicitly
|
|
50
|
+
included so a lock generated on macOS also covers pytest's Windows dependency.
|
|
51
|
+
After changing `Pipfile`, run `pipenv lock` and commit both dependency files.
|
|
52
|
+
|
|
53
|
+
## Run the planner
|
|
54
|
+
|
|
55
|
+
After completing the development setup, run the app from the repository root.
|
|
56
|
+
|
|
57
|
+
**Windows Command Prompt**
|
|
58
|
+
|
|
59
|
+
```cmd
|
|
60
|
+
.\.tools\Scripts\pipenv.exe run python app.py
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**macOS and Linux**
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
.tools/bin/pipenv run python app.py
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Open [the planner](http://127.0.0.1:8000/). Create `Study math` for `60` minutes, open its details, and click **Complete quest**. On a fresh database, the header shows **60 XP | Level 1**. The app saves quests and progress in `quests.db`.
|
|
70
|
+
|
|
71
|
+
## Build and use the Python package
|
|
72
|
+
|
|
73
|
+
The working distribution name is `chipotle-quests` (version `0.1.0`). It contains
|
|
74
|
+
the `quest_descriptions`, `quest_manager`, `progression`, `storage`, and
|
|
75
|
+
`quest_validation` modules. The package has
|
|
76
|
+
not been published to PyPI; confirm the distribution name before publishing.
|
|
77
|
+
|
|
78
|
+
Pipenv now installs the project in editable mode, so source edits are available
|
|
79
|
+
immediately. From the repository root on macOS/Linux:
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
export PIPENV_VENV_IN_PROJECT=1
|
|
83
|
+
.tools/bin/pipenv sync --dev
|
|
84
|
+
.tools/bin/pipenv run test
|
|
85
|
+
.tools/bin/pipenv run build
|
|
86
|
+
.tools/bin/pipenv run python examples/basic_usage.py
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
On Windows PowerShell:
|
|
90
|
+
|
|
91
|
+
```powershell
|
|
92
|
+
$env:PIPENV_VENV_IN_PROJECT = "1"
|
|
93
|
+
.\.tools\Scripts\pipenv.exe sync --dev
|
|
94
|
+
.\.tools\Scripts\pipenv.exe run test
|
|
95
|
+
.\.tools\Scripts\pipenv.exe run build
|
|
96
|
+
.\.tools\Scripts\pipenv.exe run python examples/basic_usage.py
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The build command uses `python -m build` to create
|
|
100
|
+
`dist/chipotle_quests-0.1.0.tar.gz` (source distribution) and
|
|
101
|
+
`dist/chipotle_quests-0.1.0-py3-none-any.whl` (installable wheel).
|
|
102
|
+
`MANIFEST.in` includes the usage example and Pipenv files in the source distribution.
|
|
103
|
+
|
|
104
|
+
To try the built wheel, replace the editable installation using your platform's
|
|
105
|
+
Pipenv executable (`pipenv` below means the executable used above):
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
pipenv run python -m pip install --force-reinstall --no-deps dist/chipotle_quests-0.1.0-py3-none-any.whl
|
|
109
|
+
pipenv run python -I examples/basic_usage.py
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Run `pipenv sync --dev` again to return to editable development.
|
|
113
|
+
|
|
114
|
+
### Public functions
|
|
115
|
+
|
|
116
|
+
| Import from | Function | Purpose |
|
|
117
|
+
| --- | --- | --- |
|
|
118
|
+
| `quest_validation` | `validate_quest_input(title, duration_minutes)` | Return the trimmed title and validated whole-minute duration. Raise `ValueError` for a blank title or an invalid duration. |
|
|
119
|
+
| `quest_descriptions` | `generate_fantasy_description(title, *, seed=None, custom_templates=None)` | Describe a nonblank title; an integer seed selects a repeatable template, with optional category overrides. |
|
|
120
|
+
| `quest_descriptions` | `rename_pending_quest(quest, new_title, *, seed=None, custom_templates=None)` | Return a pending quest copy with its title and description updated. |
|
|
121
|
+
| `quest_manager` | `create_quest(quests, title, duration_minutes, *, seed=None, custom_templates=None)` | Return a new list containing a new pending quest with a UUID string ID. |
|
|
122
|
+
| `quest_manager` | `list_quests(quests, status=None)` | Return quest copies, optionally filtering by `pending` or `completed`. |
|
|
123
|
+
| `quest_manager` | `get_quest(quests, quest_id)` | Return a quest copy by ID; raise `KeyError` if it is missing. |
|
|
124
|
+
| `quest_manager` | `delete_quest(quests, quest_id)` | Return a new list with the specified pending quest removed. |
|
|
125
|
+
| `quest_manager` | `rename_quest(quests, quest_id, new_title, *, seed=None, custom_templates=None)` | Rename a pending quest by ID and regenerate its description. |
|
|
126
|
+
| `quest_manager` | `change_quest_duration(quests, quest_id, duration_minutes)` | Update a pending quest's duration and planned XP reward together. |
|
|
127
|
+
| `progression` | `calculate_xp(duration_minutes)` | Return 1 XP per positive integer minute. |
|
|
128
|
+
| `progression` | `calculate_level(total_xp)` | Calculate a level from nonnegative integer total XP: `1 + total_xp // 100`. |
|
|
129
|
+
| `progression` | `award_xp(total_xp, duration_minutes)` | Calculate total XP and level after one reward. |
|
|
130
|
+
| `storage` | `initialize_database(database_path)` | Create SQLite tables and initialize progress without overwriting existing data. |
|
|
131
|
+
| `storage` | `insert_quest(database_path, quest)` | Commit one new pending quest without changing earned XP; duplicate IDs raise `sqlite3.IntegrityError`. |
|
|
132
|
+
| `storage` | `update_pending_quest(database_path, quest)` | Save an existing pending quest's title, description, duration, and reward together. |
|
|
133
|
+
| `storage` | `delete_pending_quest(database_path, quest_id)` | Delete one saved pending quest without changing earned XP. |
|
|
134
|
+
| `storage` | `complete_quest(database_path, quest_id)` | Complete a saved quest and award XP in one transaction; retries award 0 XP and preserve its completion time. |
|
|
135
|
+
| `storage` | `load_quests(database_path, status=None)` | Read quest dictionaries in insertion order, optionally filtering by `pending` or `completed`. |
|
|
136
|
+
| `storage` | `load_progress(database_path)` | Read `{"totalXP": saved_integer}`; derive the level with `calculate_level`. |
|
|
137
|
+
| `storage` | `complete_quest(database_path, quest_id)` | Save completion and award XP in one transaction. Repeating completion awards zero additional XP. |
|
|
138
|
+
|
|
139
|
+
For example, `from quest_manager import list_quests` imports the listing function.
|
|
140
|
+
The [usage example](examples/basic_usage.py) calls all nineteen public functions:
|
|
141
|
+
initialize a temporary database, create/save/reload a quest, read saved progress,
|
|
142
|
+
persist edits and deletion, complete a quest and retry it, filter/look up/edit/delete in-memory copies, generate
|
|
143
|
+
descriptions, and calculate XP, a level, and updated progress. The temporary
|
|
144
|
+
database is removed when the storage demonstration finishes. More XP details are in the
|
|
145
|
+
[progression notes](docs/progression.md).
|
|
146
|
+
Expected output includes `First completion reward: 100`, `Reward on retry: 0`,
|
|
147
|
+
`Saved XP after completion: 100`, `Saved level after completion: 2`, and
|
|
148
|
+
`Pending quests: 1`. It ends with `Remaining quests: 0`.
|
|
149
|
+
Extend the example and module list in `pyproject.toml` as public functions and
|
|
150
|
+
modules are added. More title-editing details are in the
|
|
151
|
+
[integration notes](docs/quest-description-integration.md).
|
|
152
|
+
|
|
153
|
+
## Database initialization
|
|
154
|
+
|
|
155
|
+
After syncing the editable installation with `pipenv sync --dev`, initialize a
|
|
156
|
+
local database using Python's standard-library SQLite support:
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
from storage import initialize_database
|
|
160
|
+
|
|
161
|
+
initialize_database("quests.db")
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
This creates the file if needed, plus two tables:
|
|
165
|
+
|
|
166
|
+
- `quests`: `id` (text), `title`, `durationMinutes`, `fantasyDescription`,
|
|
167
|
+
`status`, `xpReward`, and nullable `completedAt`, matching existing quest helpers.
|
|
168
|
+
- `progress`: one local-user row (`id = 1`) with `totalXP = 0` initially.
|
|
169
|
+
Use `calculate_level(total_xp)` to derive the level rather than storing it twice.
|
|
170
|
+
|
|
171
|
+
Repeated initialization preserves existing tasks and XP. Schema creation and
|
|
172
|
+
initial progress are committed together, and the connection is closed before
|
|
173
|
+
the function returns. Basic schema constraints enforce positive integer minutes,
|
|
174
|
+
matching XP rewards, supported statuses, and nonnegative integer total XP.
|
|
175
|
+
|
|
176
|
+
Pass a string or `pathlib.Path` pointing to a file in an existing directory.
|
|
177
|
+
Invalid path types raise `TypeError`; blank names, `:memory:`, and SQLite URIs
|
|
178
|
+
raise `ValueError`. File-access and database errors propagate as SQLite errors.
|
|
179
|
+
Existing table definitions are not migrated by this initializer.
|
|
180
|
+
|
|
181
|
+
Local database files and SQLite transaction files are ignored by Git.
|
|
182
|
+
|
|
183
|
+
### Save and reload a new quest
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
from progression import calculate_level
|
|
187
|
+
from quest_manager import create_quest
|
|
188
|
+
from storage import initialize_database, insert_quest, load_progress, load_quests
|
|
189
|
+
|
|
190
|
+
database_path = "quests.db"
|
|
191
|
+
initialize_database(database_path)
|
|
192
|
+
quest = create_quest([], "Study math", 60, seed=7)[0]
|
|
193
|
+
insert_quest(database_path, quest)
|
|
194
|
+
|
|
195
|
+
pending = load_quests(database_path, status="pending")
|
|
196
|
+
assert any(saved == quest for saved in pending)
|
|
197
|
+
progress = load_progress(database_path)
|
|
198
|
+
print(progress["totalXP"], calculate_level(progress["totalXP"]))
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Every helper closes its connection. Committed tasks and XP remain available
|
|
202
|
+
after restarting Python and calling the readers again. On a fresh database,
|
|
203
|
+
creating a pending quest leaves XP at 0 and the level at 1.
|
|
204
|
+
|
|
205
|
+
Initialize the database before using these helpers. They open existing files
|
|
206
|
+
only, so a misspelled path raises `sqlite3.OperationalError` instead of creating
|
|
207
|
+
another empty database. Missing tables and other SQLite errors propagate.
|
|
208
|
+
`load_progress` raises `ValueError` if the initial progress row is missing;
|
|
209
|
+
it does not reset XP or silently create a row. Readers use read-only connections.
|
|
210
|
+
|
|
211
|
+
`insert_quest` accepts a dictionary with exactly the seven standard quest fields.
|
|
212
|
+
IDs, titles, and descriptions must be nonblank strings. Duration and reward must
|
|
213
|
+
be integers (not booleans), duration must be positive and fit SQLite's signed
|
|
214
|
+
64-bit range, and reward must equal duration. Only `pending` quests with
|
|
215
|
+
`completedAt=None` can be inserted. Invalid field types raise `TypeError`;
|
|
216
|
+
missing/extra fields or invalid values raise `ValueError`. Extra metadata is
|
|
217
|
+
rejected rather than discarded. Titles and descriptions are stored unchanged.
|
|
218
|
+
|
|
219
|
+
Insertion returns `None` after committing. It never replaces existing IDs,
|
|
220
|
+
clears other tasks, or awards XP. Duplicate IDs raise `sqlite3.IntegrityError`;
|
|
221
|
+
a failed insert leaves existing tasks and progress unchanged. `load_quests`
|
|
222
|
+
returns independent dictionaries, or `[]` if there are no matches. Its filter
|
|
223
|
+
must be `None`, `pending`, or `completed`; other values raise `ValueError`.
|
|
224
|
+
|
|
225
|
+
### Save edits and delete a pending quest
|
|
226
|
+
|
|
227
|
+
After the save/reload example above, use the business helpers to prepare edits
|
|
228
|
+
and the storage helpers to commit them:
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
from quest_manager import change_quest_duration, get_quest, rename_quest
|
|
232
|
+
from storage import delete_pending_quest, update_pending_quest
|
|
233
|
+
|
|
234
|
+
quests = load_quests(database_path)
|
|
235
|
+
edited = rename_quest(quests, quest["id"], "Do laundry", seed=7)
|
|
236
|
+
edited = change_quest_duration(edited, quest["id"], 45)
|
|
237
|
+
before_xp = load_progress(database_path)
|
|
238
|
+
updated_quest = get_quest(edited, quest["id"])
|
|
239
|
+
update_pending_quest(database_path, updated_quest)
|
|
240
|
+
|
|
241
|
+
reloaded = load_quests(database_path)
|
|
242
|
+
assert any(saved == updated_quest for saved in reloaded)
|
|
243
|
+
delete_pending_quest(database_path, quest["id"])
|
|
244
|
+
assert all(saved["id"] != quest["id"] for saved in load_quests(database_path))
|
|
245
|
+
assert load_progress(database_path) == before_xp
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
`update_pending_quest` accepts the same seven-field pending record as
|
|
249
|
+
`insert_quest`, using the same field/type/range validation. It updates only the
|
|
250
|
+
title, description, duration, and planned reward for the matching ID. It does
|
|
251
|
+
not generate descriptions; prepare the record with `rename_quest` and
|
|
252
|
+
`change_quest_duration` so related fields are updated together. Load the latest
|
|
253
|
+
record before editing; each update writes all four editable fields.
|
|
254
|
+
|
|
255
|
+
Both mutation helpers return `None` after committing and closing the connection.
|
|
256
|
+
They check the stored status within a write transaction, so a stale pending
|
|
257
|
+
copy cannot overwrite or delete a quest that has already been completed.
|
|
258
|
+
Missing IDs raise `KeyError`; completed quests raise `ValueError`. Updates never
|
|
259
|
+
insert missing IDs. Delete IDs must be nonblank strings, matching stored IDs;
|
|
260
|
+
other types raise `TypeError` and blank IDs raise `ValueError`.
|
|
261
|
+
|
|
262
|
+
Successful edits/deletions preserve other quests and total XP. Failed writes
|
|
263
|
+
roll back. These helpers require an existing initialized database and use the
|
|
264
|
+
same path/error rules as the earlier storage helpers. Deleting the same ID
|
|
265
|
+
again raises `KeyError`. No completion or reward is performed by either helper.
|
|
266
|
+
|
|
267
|
+
`complete_quest` checks the stored status and saves completion, its timestamp,
|
|
268
|
+
and the XP award in one transaction. Retrying a completed quest returns 0 awarded
|
|
269
|
+
XP and preserves its original completion time. The main example verifies the
|
|
270
|
+
saved quest and XP through fresh database connections. See the
|
|
271
|
+
[completion notes](docs/quest-completion.md) for the full contract.
|
|
272
|
+
|
|
273
|
+
## Automated checks
|
|
274
|
+
|
|
275
|
+
The [Test and build workflow](.github/workflows/ci.yml) runs on every pull request,
|
|
276
|
+
including PRs targeting feature branches, and on pushes to `main` or `master`.
|
|
277
|
+
It can also be run manually from GitHub Actions once available on the default branch.
|
|
278
|
+
Each job uses Python 3.13 or 3.14 to install locked dependencies, run pytest,
|
|
279
|
+
and build the source distribution and wheel. It then reruns pytest and the usage
|
|
280
|
+
example from a fresh wheel installation outside the source checkout, catching
|
|
281
|
+
missing packaged modules as well as source failures. A failed step fails that job.
|
|
282
|
+
The badge at the top shows the latest `main` push result. The instructor's
|
|
283
|
+
separate event-logging workflow is unchanged.
|
|
284
|
+
|
|
285
|
+
## Team and presentation
|
|
286
|
+
|
|
287
|
+
- [Yuyang](https://github.com/Yuyang-Ding1102) — backend, SQLite persistence, and CI
|
|
288
|
+
- [Ali](https://github.com/AliG119) — Create Quest form, submission, and validation
|
|
289
|
+
- [Yvonne](https://github.com/Lyvoj) — XP, leveling, and tests
|
|
290
|
+
- [Sirius](https://github.com/S1rius-Yang) — quest APIs and management controls
|
|
291
|
+
- [Zihan](https://github.com/Vent1Zzz) — fantasy descriptions and templates
|
|
292
|
+
|
|
293
|
+
[Project 3 team roles](PROJECT3_TEAM_ROLES.md)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
progression.py,sha256=XFY2-1fTob09TvgRihPWTbgL24ETkOK7w84I21XiQE4,1144
|
|
2
|
+
quest_descriptions.py,sha256=C80XiHgEnzuzPczjPT72ObcMqi_8GZK8HH95mxMgB0s,6098
|
|
3
|
+
quest_manager.py,sha256=gEAtHyAxci_IshWHyMW07fIOEtDsuMcs-xDjD5ooRKc,3970
|
|
4
|
+
quest_validation.py,sha256=IlQM8D8l8j59voQdMY3KBJrYJ6sxP1wqpqPgjxcUsPA,479
|
|
5
|
+
storage.py,sha256=qXluld2vkzPl1MBuRZQoq1g0linr5VJNlYNVITjpTx4,9719
|
|
6
|
+
chipotle_quests-0.1.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
7
|
+
chipotle_quests-0.1.0.dist-info/METADATA,sha256=PdHT8tM3KMXRKZZjFp58B90cp1oVAUEQyeMh05WLL10,15214
|
|
8
|
+
chipotle_quests-0.1.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
9
|
+
chipotle_quests-0.1.0.dist-info/top_level.txt,sha256=7Dfs6h67CwzSP1TmZX3blR-J3vfe0Ows2TKUfm5mzM0,70
|
|
10
|
+
chipotle_quests-0.1.0.dist-info/RECORD,,
|