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.
@@ -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
+ [![Test and build](https://github.com/software-students-fall2026/python-package-exercise-Chipotle/actions/workflows/ci.yml/badge.svg?branch=main&event=push)](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,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+