Skip to content

prefer-native-string-check

Avoid unconstrained adapters for string assertions or already encoded JSON mappings.

Why

A plain string adapter obscures an assertion and can decode bytes. Generic JSON-dictionary validation after encoding adds a separate runtime contract, often only to satisfy an annotation; it can reject nested integer keys that a response serializer accepts and does not prove response serializability.

Fix

Use isinstance(value, str) for string assertions. For annotation-only JSON adaptation, return a typed Response/JSONResponse at the serialization boundary. Keep structured input and specific schema validation. Preserve intentional coercion, recursive string-key validation or ValidationError contracts explicitly.

Examples

Before — flagged A string assertion unnecessarily constructs a schema validator
tests/test_receipt.py
from pydantic import TypeAdapter
def test_receipt():
assert TypeAdapter(str).validate_python(receipt["id"]) == "abc"
After — preferred A native assertion rejects unexpected types and narrows the value
tests/test_receipt.py
def test_receipt():
value = receipt["id"]
assert isinstance(value, str)
assert value == "abc"
Before — flagged A generic validator wraps an already encoded response mapping
app/responses.py
from pydantic import TypeAdapter, JsonValue
from fastapi.encoders import jsonable_encoder
def response_content(body):
return TypeAdapter(dict[str, JsonValue]).validate_python(
jsonable_encoder(
{"body": body},
custom_encoder={
bytes: lambda value: value.decode("utf-8", errors="replace")
},
)
)
After — preferred The response owns encoded content without annotation-only validation
app/responses.py
from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse
def response(body) -> JSONResponse:
return JSONResponse(content=jsonable_encoder({"body": body}))