Conversation
`test_courses.py`: Flask-RESTX 1.x appends "Must not be null!" to the help string `test_learning_records.py`: Moved blueprint registration to `setUp` so it runs once on test init rather than mid-test. For the xAPI and Caliper tests, the `ENABLED=False` 404 check and re-enable are moved inside `with self.login(...)` to fix incorrect assertion order (the handler checks auth before the enabled flag, so the 404 path is only reachable when logged in). `test_demo.py`: Removed mid-test call to `register_demo_api_blueprints` after toggling `DEMO_INSTALLATION`. Removed because re-registration no longer needed because Flask 2 raises an error on duplicate blueprint registration
In Jinja2.3.x (comes with Flask 2), Markup was moved to its own package `markupsafe` and `jinja2.Markup` alias removed.
`send_file` parameter `attachment_filename` was renamed to `download_name` in v2.0 and fully deprecated in v2.2.0.
`pstats.Stats.print_stats()` writes text strings (not bytes) to output stream by calling `stream.write(str_value)`. Passing `BytesIO` will raise a `TypeError` the moment profile stats are flushed.
…anage/report.py
…agger UI at root of each blueprint
…ternative for Flask-Testing, unused imports
Greptile SummaryThis PR upgrades ComPAIR from Flask 1.1.2 to Flask 2.3.3 and modernizes the full dependency stack, including the migration from Key changes:
Confidence Score: 4/5PR is on the happy path to merge; prior thread concerns are resolved and no new critical bugs are present The migration is thorough and consistent across all 54 files. All previously flagged concerns (assertRedirects semantics, api.unauthorized dead code, learning-record test coverage) have been addressed in the thread. The test assertions are correctly updated for flask-restx's error response shape. The only remaining risk is runtime behavioral differences between flask-restful and flask-restx that won't surface until the full test suite runs. No files require special attention; all mechanical changes are consistent. The full pytest run and manual verification of login flows and file download paths listed in the test plan are the remaining gates before merge. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[HTTP Request] --> B[Flask 2.3.3 Router]
B --> C{Blueprint matched?}
C -->|/api/*| D[flask-restx Api\ndoc=False]
C -->|/api/learning_records/*| E[learning_record_api\nregistered in setUp]
C -->|/api/demo/*| F[demo_api\nregistered in setUp]
D --> G{login_required?}
E --> G
F --> G
G -->|not logged in| H[flask-login\nunauthorized_handler → 401]
G -->|logged in| I[Resource.get / post / put / delete]
I --> J{reqparse validation}
J -->|nullable=False violated| K[abort 400\nerrors key in response]
J -->|valid| L[Business logic]
L -->|abort with message| M[HTTPException\ne.data message key]
L -->|success| N[marshal response]
K --> O[JSON: errors + message]
M --> P[JSON: message + title]
N --> Q[JSON response to client]
Reviews (2): Last reviewed commit: "Remove #1016: Dead code _unauthorized_ov..." | Re-trigger Greptile |
|
@greptileai given the responses to your comments, review pr again |
Flask 2 Upgrade
Upgrades ComPAIR from Flask 1.1.2 to Flask 2.3.3 and modernizes the dependency stack.
Dependencies
Flask 1.1.2 → 2.3.3
flask-restful→flask-restx1.3.0 —flask-restfulis incompatible with Werkzeug 2.x (a Flask 2 dependency) due to breaking changes in Werkzeug's internals;flask-restxis the community-maintained fork that supports Werkzeug 2.x and has an otherwise compatible API.flask-restful'sreqparsedefaults to checking the json location on every request. It does this by accessingrequest.json, which is a Werkzeug property415 Unsupported Media Typeif the request'sContent-Typeisn'tapplication/json. So every GET request through aflask-restfulendpoint withreqparse(has no body and noContent-Type) now raises a 415 before the endpoint logic even runsflask-restxfixed this in March 2022 by switching torequest.get_json(silent=True, force=False)instead, which returnsNonequietly when there's no JSON body rather than raising an exception.flask-restful, being abandoned, never got the same fix. (python-restx/flask-restx@bb72a51#diff-2c0e74e2a5973841075bc16fcbecd360cdc4c09f0db3ffbe4b8de1aec4af5f11)Werkzeug 2.0.3 → 2.3.8 — required by Flask 2.3.3 (https://flask.palletsprojects.com/en/stable/changes/#version-2-3-3)
Jinja2 3.0.3 → 3.1.4 — required by Flask 2.3.3; previously pinned to 3.0.3 due to a
Markupbreakage that is resolved by moving the import tomarkupsafedirectly (https://flask.palletsprojects.com/en/stable/changes/#version-2-3-0)markupsafe 2.0.1 → 2.1.5 — previously pinned due to Flask 1 compatibility; restriction lifted
itsdangerous 2.0.1 → 2.1.2 — required by Flask 2.3.3; previously pinned due to Flask 1 compatibility
Flask-Login 0.6.1 → 0.6.3 — 0.6.2 fixed compatibility issues with Werkzeug 2.2 and Flask 2.2 due to breaking changes in Flask's request handling (https://github.com/maxcountryman/flask-login/blob/main/CHANGES.md)
blinker 1.4 → 1.9.0 — Flask 2.3.3 requires blinker >= 1.6.2, which introduced async signal support and type hints that Flask 2.3's signals infrastructure depends on (https://flask.palletsprojects.com/en/stable/changes/#version-2-3-0)
Removed
six— Python 2/3 compatibility library no longer needed as the codebase is Python 3 onlyCode changes
flask_restfulimports withflask_restxacross all API filesdoc=Falseon flask-restxApiinstances to suppress Swagger UI at blueprint roots (flask-restx enables this by default, unlike flask-restful)send_fileparameterattachment_filename→download_nameto match Flask 2 API (https://flask.palletsprojects.com/en/stable/changes/#version-2-2-0)Markupimport fromjinja2tomarkupsafe, where it now lives in Flask 2 (https://flask.palletsprojects.com/en/stable/changes/#version-2-3-0)sixshims with Python 3 builtins (str,io.BytesIO,io.StringIO,functools.wraps, built-inrange)urllibcompatibility try/except blocks inreport.pyandlti_membership.py, replaced with direct Python 3 importsERROR_404_HELPconfig key toRESTX_ERROR_404_HELPto match flask-restx's renamed setting (rename ERROR_404_HELP to RESTX_ERROR_404_HELP for consistency python-restx/flask-restx#114)assertRedirectsoverride to handle Werkzeug 2.1's change to return relative redirect locations instead of absolute URLsassertRedirectswas comparing against absolute URLs, so it started failing. It used to prepend the host to relative URL.test_compair.pynormalizes the location header before comparing so the assertion works with either format.BytesIO.BytesIO()was called incorrectly in profiler code; replaced withStringIO()_unauthorized_overrideandapi.unauthorizedassignment@login_manager.unauthorized_handlertook over 401 handlingserve_challenge_on_401=False), making the override doubly unnecessaryTests
errorskey instead ofmessage)six.assertCountEqual/six.assertRegexwith nativeunittestequivalentsValueErrorwhen registering an already-registered blueprint, making the old mid-test re-registration approach no longer viableTest plan
pytest)download_namerename affects this path)