# Upgrade Flask Dependencies Every Week

Yes. Each week a Rush agent upgrades your Flask app's Python packages in the lockfile, runs pytest, reverts what breaks and opens one pull request.

[Run this on Rush](https://cloud.getrush.ai/run/upgrade-dependencies-weekly/flask/), in a Project that has your repository.

## What the agent does

In a Flask app like flaskbb/flaskbb there is no requirements.txt. Dependencies are declared in pyproject.toml with lower bounds (Flask>=3.1.3, SQLAlchemy>=2.1.4, Flask-SQLAlchemy>=3.1.1, celery>=5.6.3, Werkzeug>=3.1.9, WTForms>=3.2.2, alembic>=1.20.0 and about 40 more) and resolved to exact versions in uv.lock. The Makefile's dependencies target runs uv sync and its test target runs uv run pytest. So the upgrade is a lockfile change: the agent runs uv lock --upgrade-package <name> for one package at a time and leaves the lower bounds in pyproject.toml alone unless a new version needs a higher floor.

The test suite is pytest with options set in [tool.pytest] in pyproject.toml: --strict-markers, --numprocesses auto with --dist load through pytest-xdist, and --pythonwarnings error::flaskbb.deprecation.FlaskBBDeprecation, which turns FlaskBB's own deprecation warnings into failures. Tests live in tests/unit (auth, cli, forum) and tests/endtoend, with fixtures in tests/fixtures/app.py, forum.py and user.py. The agent runs uv sync --group dev, then uv run pytest after each package, the same path .github/workflows/tests.yml takes through tox on Python 3.12 to 3.15.

It groups packages that are released together or depend on each other's internals: Flask with Werkzeug, Jinja2, MarkupSafe, click and blinker; SQLAlchemy with Flask-SQLAlchemy, alembic, Flask-Alembic and WTForms-SQLAlchemy; Flask-WTF with WTForms. The two flaskbb plugins pinned in the core dependencies, flaskbb-plugin-conversations and flaskbb-plugin-portal, are upgraded on their own, since they import FlaskBB internals. Type checking is the typing environment in [tool.tox], which runs both mypy and basedpyright, and the agent runs it too with uv run tox run -e typing, because a new SQLAlchemy often changes types.

A group that fails pytest or the type checkers is reverted in uv.lock, and the failing test id or type error is kept for the pull request.

## Start it with one API call

`POST https://api.prix.dev/o/{org}/sessions`

```json
{
  "agent": "claude",
  "input": "Upgrade this project's Python dependencies to their latest compatible releases in uv.lock with uv lock --upgrade-package, one group at a time: Flask with Werkzeug, Jinja2, MarkupSafe, click and blinker; SQLAlchemy with Flask-SQLAlchemy, alembic, Flask-Alembic and WTForms-SQLAlchemy; then the rest. Raise a lower bound in pyproject.toml only if a new version needs it. After each group run uv sync --group dev, uv run pytest and uv run tox run -e typing. Revert any group that fails and record the error. Open one pull request listing each bump with its old and new version and each skipped upgrade with the error that blocked it.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
```

1. **Get an API key.** In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
2. **Send the request.** POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
3. **Read what came back.** Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

## What comes back

The pull request mostly changes uv.lock, and pyproject.toml only where a lower bound had to rise. The description lists each package with its old and new locked version, grouped as they were upgraded, then the groups held back with the pytest failure or type error. tests.yml runs the tox environments for every Python version in the matrix on the pull request, and typing.yaml runs the same tox typing environment.

A reviewer checks the changelogs of anything that crossed a major (SQLAlchemy and celery are the usual ones), makes sure no FlaskBBDeprecation warning was silenced to get the suite passing, and checks the plugin packages against the plugin API. The session transcript keeps every uv and pytest command with its output.

## Run it on every Monday morning

A lockfile only moves when someone runs uv lock, so a weekly job is what keeps it current. Have a scheduler send this request every Monday with the repository in resources; a week with nothing new produces no pull request worth merging, and the agent says so.

When the key has a webhook URL, Rush calls it at the end of the turn with run.completed and a session_url to read the result from.

## Why run it on Rush?

Testing each upgrade group means a fresh uv sync, a parallel pytest run and a type check, repeated whenever a group is reverted. In a Rush sandbox the agent does that on a clean Python with the project's own lockfile, and the output of every uv, pytest and tox command is kept for the reviewer.

Bots that open one pull request per package cannot express that Flask and Werkzeug, or SQLAlchemy and Flask-SQLAlchemy, have to move together. A single tested pull request each week can. Every Flask service you run can get the same request at the same time.

## Frequently asked questions

### Will it change the version ranges in pyproject.toml?

Only lower bounds, and only when a new release requires it. The exact versions live in uv.lock, so that is where most of the change is.

### My project uses requirements.txt and pip. Does that work?

Yes. Name pip in the request and the agent edits the pinned versions in requirements.txt and installs with pip instead of uv.

### Does it run the tests on every Python version?

In the sandbox it runs one Python version. The tox matrix in tests.yml runs 3.12 to 3.15 on the pull request.

### What about Celery and Redis?

celery and redis are upgraded and covered by the unit tests, which do not need a running broker. Check worker behavior in staging before merging a celery major.
