breaking‑change‑radar.

cases / real-fastapi-realworld-pydantic-v2

real-fastapi-realworld-pydantic-v2

pydantic 1.9.0 2.0.0

The RealWorld reference backend (FastAPI, ~3.1k stars, pinned to pydantic ^1.9) upgraded to v2. Two distinct traps: the dict() builtin, and response.json() from the test client.

grep-baseline
8 right 8 wrong 4 unjudged
<0.1s · $0.00
agent · deepseek-v4-flash-free
8 right 0 wrong
118.7s · $0.00

What each detector said

One row per (file, symbol) site — the unit the scorer compares on. Ground truth comes from the case's hand-written labels.

20 sites · 12 where a detector is wrong
  1. unlabeled app/core/settings/app.py :json grep-baseline flagged agent · deepseek-v4-flash-free silent
    1 matched line · reasoning
      16  openapi_url: str = "/openapi.json"
    grep-baseline conf 0.50

    'BaseModel.json' is named in the release notes and appears in 46 place(s) in this repo. No check was made that these are real call sites.

  2. not broken app/db/repositories/users.py :dict grep-baseline flagged agent · deepseek-v4-flash-free silent

    `user.copy(update=dict(user_row))` — the dict builtin constructing a mapping from a DB row, not a model method. Renaming it would be a bug.

    1 matched line · reasoning
      48  return user.copy(update=dict(user_row))
    grep-baseline conf 0.50

    'BaseModel.dict' is named in the release notes and appears in 11 place(s) in this repo. No check was made that these are real call sites.

  3. unlabeled tests/conftest.py :json grep-baseline flagged agent · deepseek-v4-flash-free silent
    1 matched line · reasoning
      43  headers={"Content-Type": "application/json"},
    grep-baseline conf 0.50

    'BaseModel.json' is named in the release notes and appears in 46 place(s) in this repo. No check was made that these are real call sites.

  4. not broken tests/test_api/test_errors/test_422_error.py :json grep-baseline flagged agent · deepseek-v4-flash-free silent

    response.json() on the test client, not a pydantic model.

    1 matched line · reasoning
      19  error_data = response.json()
    grep-baseline conf 0.50

    'BaseModel.json' is named in the release notes and appears in 46 place(s) in this repo. No check was made that these are real call sites.

  5. not broken tests/test_api/test_errors/test_error.py :json grep-baseline flagged agent · deepseek-v4-flash-free silent

    response.json() on the test client, not a pydantic model.

    1 matched line · reasoning
      15  error_data = response.json()
    grep-baseline conf 0.50

    'BaseModel.json' is named in the release notes and appears in 46 place(s) in this repo. No check was made that these are real call sites.

  6. not broken tests/test_api/test_routes/test_articles.py :json grep-baseline flagged agent · deepseek-v4-flash-free silent

    response.json() on the test client. This file is separately affected for the `dict` symbol; the two labels do not conflict because a site is keyed by (file, symbol).

    6 matched lines · reasoning
      27  app.url_path_for("articles:create-article"), json={"article": article_data}
      41  app.url_path_for("articles:create-article"), json={"article": article_data}
      43  article = ArticleInResponse(**response.json())
      58  app.url_path_for("articles:create-article"), json={"article": article_data}
      60  article = ArticleInResponse(**response.json())
      87  article = ArticleInResponse(**response.json())

    +14 more

    grep-baseline conf 0.50

    'BaseModel.json' is named in the release notes and appears in 46 place(s) in this repo. No check was made that these are real call sites.

  7. not broken tests/test_api/test_routes/test_comments.py :json grep-baseline flagged agent · deepseek-v4-flash-free silent

    response.json() on the test client, not a pydantic model.

    6 matched lines · reasoning
      20  json={"comment": {"body": "comment"}},
      23  created_comment = CommentInResponse(**created_comment_response.json())
      29  comments = ListOfCommentsInResponse(**comments_for_article_response.json())
      39  json={"comment": {"body": "comment"}},
      42  created_comment = CommentInResponse(**created_comment_response.json())
      56  comments = ListOfCommentsInResponse(**comments_for_article_response.json())
    grep-baseline conf 0.50

    'BaseModel.json' is named in the release notes and appears in 46 place(s) in this repo. No check was made that these are real call sites.

  8. unlabeled tests/test_api/test_routes/test_login.py :json grep-baseline flagged agent · deepseek-v4-flash-free silent
    2 matched lines · reasoning
      16  response = await client.post(app.url_path_for("auth:login"), json=login_json)
      33  response = await client.post(app.url_path_for("auth:login"), json=login_json)
    grep-baseline conf 0.50

    'BaseModel.json' is named in the release notes and appears in 46 place(s) in this repo. No check was made that these are real call sites.

  9. not broken tests/test_api/test_routes/test_profiles.py :json grep-baseline flagged agent · deepseek-v4-flash-free silent

    response.json() on the test client, not a pydantic model.

    4 matched lines · reasoning
      21  profile = ProfileInResponse(**response.json())
      40  profile = ProfileInResponse(**response.json())
      64  profile = ProfileInResponse(**response.json())
     124  profile = ProfileInResponse(**response.json())
    grep-baseline conf 0.50

    'BaseModel.json' is named in the release notes and appears in 46 place(s) in this repo. No check was made that these are real call sites.

  10. unlabeled tests/test_api/test_routes/test_registration.py :json grep-baseline flagged agent · deepseek-v4-flash-free silent
    2 matched lines · reasoning
      21  app.url_path_for("auth:register"), json=registration_json
      54  app.url_path_for("auth:register"), json=registration_json
    grep-baseline conf 0.50

    'BaseModel.json' is named in the release notes and appears in 46 place(s) in this repo. No check was made that these are real call sites.

  11. not broken tests/test_api/test_routes/test_tags.py :json grep-baseline flagged agent · deepseek-v4-flash-free silent

    response.json() on the test client, not a pydantic model.

    2 matched lines · reasoning
      13  assert response.json() == {"tags": []}
      26  tags_from_response = response.json()["tags"]
    grep-baseline conf 0.50

    'BaseModel.json' is named in the release notes and appears in 46 place(s) in this repo. No check was made that these are real call sites.

  12. not broken tests/test_api/test_routes/test_users.py :json grep-baseline flagged agent · deepseek-v4-flash-free silent

    response.json() on the test client. Same file/symbol split as above.

    6 matched lines · reasoning
      60  user_profile = UserInResponse(**response.json())
      83  json={"user": {update_field: update_value}},
      87  user_profile = UserInResponse(**response.json()).dict()
     100  json={"user": {"password": "new_password"}},
     103  user_profile = UserInResponse(**response.json())
     138  json={"user": {credentials_part: credentials_value}},
    grep-baseline conf 0.50

    'BaseModel.json' is named in the release notes and appears in 46 place(s) in this repo. No check was made that these are real call sites.

  13. breaks app/api/routes/articles/articles_common.py :dict grep-baseline flagged agent · deepseek-v4-flash-free flagged

    article.dict() where Article derives from RWModel -> BaseModel.

    1 matched line · reasoning
      39  ArticleForResponse(**article.dict()) for article in articles
    grep-baseline conf 0.50

    'BaseModel.dict' is named in the release notes and appears in 11 place(s) in this repo. No check was made that these are real call sites.

  14. breaks app/api/routes/articles/articles_resource.py :dict grep-baseline flagged agent · deepseek-v4-flash-free flagged

    article_update.dict() on a request-body model.

    1 matched line · reasoning
     104  **article_update.dict(),
    grep-baseline conf 0.50

    'BaseModel.dict' is named in the release notes and appears in 11 place(s) in this repo. No check was made that these are real call sites.

  15. breaks app/api/routes/authentication.py :dict grep-baseline flagged agent · deepseek-v4-flash-free flagged

    user_create.dict() on a UserInCreate model.

    1 matched line · reasoning
      79  user = await users_repo.create_user(**user_create.dict())
    grep-baseline conf 0.50

    'BaseModel.dict' is named in the release notes and appears in 11 place(s) in this repo. No check was made that these are real call sites.

  16. breaks app/api/routes/users.py :dict grep-baseline flagged agent · deepseek-v4-flash-free flagged

    user_update.dict() on a UserInUpdate model.

    1 matched line · reasoning
      59  user = await users_repo.update_user(user=current_user, **user_update.dict())
    grep-baseline conf 0.50

    'BaseModel.dict' is named in the release notes and appears in 11 place(s) in this repo. No check was made that these are real call sites.

  17. breaks app/models/common.py :validator grep-baseline flagged agent · deepseek-v4-flash-free flagged

    The repository's only @validator, imported from pydantic and applied to created_at/updated_at with pre=True.

    2 matched lines · reasoning
       3  from pydantic import BaseModel, Field, validator
      10  @validator("created_at", "updated_at", pre=True)
    grep-baseline conf 0.50

    'validator' is named in the release notes and appears in 2 place(s) in this repo. No check was made that these are real call sites.

  18. breaks app/services/jwt.py :dict grep-baseline flagged agent · deepseek-v4-flash-free flagged

    JWTMeta(...).dict() and JWTUser(...).dict(); both are BaseModel.

    2 matched lines · reasoning
      23  to_encode.update(JWTMeta(exp=expire, sub=JWT_SUBJECT).dict())
      29  jwt_content=JWTUser(username=user.username).dict(),
    grep-baseline conf 0.50

    'BaseModel.dict' is named in the release notes and appears in 11 place(s) in this repo. No check was made that these are real call sites.

  19. breaks tests/test_api/test_routes/test_articles.py :dict grep-baseline flagged agent · deepseek-v4-flash-free flagged

    article.dict() and article.dict(exclude=...) on a pydantic model.

    3 matched lines · reasoning
     105  extra_updates: dict,
     115  article_as_dict = article.dict()
     122  assert article.dict(exclude=exclude_fields) == test_article.dict(
    grep-baseline conf 0.50

    'BaseModel.dict' is named in the release notes and appears in 11 place(s) in this repo. No check was made that these are real call sites.

  20. breaks tests/test_api/test_routes/test_users.py :dict grep-baseline flagged agent · deepseek-v4-flash-free flagged

    UserInResponse(**response.json()).dict() on a pydantic model.

    1 matched line · reasoning
      87  user_profile = UserInResponse(**response.json()).dict()
    grep-baseline conf 0.50

    'BaseModel.dict' is named in the release notes and appears in 11 place(s) in this repo. No check was made that these are real call sites.