[{"data":1,"prerenderedAt":2521},["ShallowReactive",2],{"nav":3,"page-\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Foverriding-dependencies-in-tests\u002F":580,"surround-\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Foverriding-dependencies-in-tests\u002F":2520},[4,186,386],{"title":5,"path":6,"stem":7,"children":8},"Advanced Pydantic Validation Serialization","\u002Fadvanced-pydantic-validation-serialization","advanced-pydantic-validation-serialization",[9,12,42,66,90,114,150,174],{"title":10,"path":6,"stem":11},"Advanced Pydantic Validation and Serialization","advanced-pydantic-validation-serialization\u002Findex",{"title":13,"path":14,"stem":15,"children":16},"Custom Validators and Field Constraints in Pydantic","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Findex",[17,18,24,30,36],{"title":13,"path":14,"stem":15},{"title":19,"path":20,"stem":21,"children":22},"Before, After and Wrap Validators in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fbefore-after-and-wrap-validators","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fbefore-after-and-wrap-validators\u002Findex",[23],{"title":19,"path":20,"stem":21},{"title":25,"path":26,"stem":27,"children":28},"Creating Reusable Custom Validators in Pydantic","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcreating-reusable-custom-validators-in-pydantic","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcreating-reusable-custom-validators-in-pydantic\u002Findex",[29],{"title":25,"path":26,"stem":27},{"title":31,"path":32,"stem":33,"children":34},"Cross-Field Validation Patterns in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcross-field-validation-patterns","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcross-field-validation-patterns\u002Findex",[35],{"title":31,"path":32,"stem":33},{"title":37,"path":38,"stem":39,"children":40},"Pydantic v2 Async Custom Validator: What to Do Instead","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fpydantic-v2-async-custom-validator","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fpydantic-v2-async-custom-validator\u002Findex",[41],{"title":37,"path":38,"stem":39},{"title":43,"path":44,"stem":45,"children":46},"JSON Schema Customization in Pydantic and FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Findex",[47,48,54,60],{"title":43,"path":44,"stem":45},{"title":49,"path":50,"stem":51,"children":52},"Customizing OpenAPI Schema Generation in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fcustomizing-openapi-schema-generation-in-fastapi","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fcustomizing-openapi-schema-generation-in-fastapi\u002Findex",[53],{"title":49,"path":50,"stem":51},{"title":55,"path":56,"stem":57,"children":58},"Discriminated Unions in OpenAPI with Pydantic","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fdiscriminated-unions-in-openapi","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fdiscriminated-unions-in-openapi\u002Findex",[59],{"title":55,"path":56,"stem":57},{"title":61,"path":62,"stem":63,"children":64},"Examples in the OpenAPI Schema with FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fexamples-in-openapi-schema","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fexamples-in-openapi-schema\u002Findex",[65],{"title":61,"path":62,"stem":63},{"title":67,"path":68,"stem":69,"children":70},"Nested Model Serialization in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Findex",[71,72,78,84],{"title":67,"path":68,"stem":69},{"title":73,"path":74,"stem":75,"children":76},"Excluding Fields Per Endpoint in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fexcluding-fields-per-endpoint","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fexcluding-fields-per-endpoint\u002Findex",[77],{"title":73,"path":74,"stem":75},{"title":79,"path":80,"stem":81,"children":82},"Handling Deeply Nested JSON Models Efficiently","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fhandling-deeply-nested-json-models-efficiently","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fhandling-deeply-nested-json-models-efficiently\u002Findex",[83],{"title":79,"path":80,"stem":81},{"title":85,"path":86,"stem":87,"children":88},"Self-Referencing and Recursive Models in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fself-referencing-and-recursive-models","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fself-referencing-and-recursive-models\u002Findex",[89],{"title":85,"path":86,"stem":87},{"title":91,"path":92,"stem":93,"children":94},"Performance Optimization for Pydantic Models in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models","advanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Findex",[95,96,102,108],{"title":91,"path":92,"stem":93},{"title":97,"path":98,"stem":99,"children":100},"model_construct and When to Skip Validation in Pydantic","\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fmodel-construct-when-to-skip-validation","advanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fmodel-construct-when-to-skip-validation\u002Findex",[101],{"title":97,"path":98,"stem":99},{"title":103,"path":104,"stem":105,"children":106},"Pydantic Model Serialization Performance in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fpydantic-model-serialization-performance","advanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fpydantic-model-serialization-performance\u002Findex",[107],{"title":103,"path":104,"stem":105},{"title":109,"path":110,"stem":111,"children":112},"TypeAdapter for Non-Model Types in Pydantic","\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Ftypeadapter-for-non-model-types","advanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Ftypeadapter-for-non-model-types\u002Findex",[113],{"title":109,"path":110,"stem":111},{"title":115,"path":116,"stem":117,"children":118},"Pydantic V2 Migration Guide for FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Findex",[119,120,126,132,138,144],{"title":115,"path":116,"stem":117},{"title":121,"path":122,"stem":123,"children":124},"Migrate @validator to @field_validator in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrate-validator-to-field-validator","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrate-validator-to-field-validator\u002Findex",[125],{"title":121,"path":122,"stem":123},{"title":127,"path":128,"stem":129,"children":130},"Migrating from Pydantic v1 to v2 Without Breaking APIs","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrating-from-pydantic-v1-to-v2-without-breaking-apis","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrating-from-pydantic-v1-to-v2-without-breaking-apis\u002Findex",[131],{"title":127,"path":128,"stem":129},{"title":133,"path":134,"stem":135,"children":136},"model_config vs class Config in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmodel-config-vs-class-config","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmodel-config-vs-class-config\u002Findex",[137],{"title":133,"path":134,"stem":135},{"title":139,"path":140,"stem":141,"children":142},"Replacing json_encoders with field_serializer in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Freplacing-json-encoders-with-field-serializer","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Freplacing-json-encoders-with-field-serializer\u002Findex",[143],{"title":139,"path":140,"stem":141},{"title":145,"path":146,"stem":147,"children":148},"Migrating @root_validator to @model_validator in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Froot-validator-to-model-validator","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Froot-validator-to-model-validator\u002Findex",[149],{"title":145,"path":146,"stem":147},{"title":151,"path":152,"stem":153,"children":154},"Request Validation Patterns in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Frequest-validation-patterns","advanced-pydantic-validation-serialization\u002Frequest-validation-patterns\u002Findex",[155,156,162,168],{"title":151,"path":152,"stem":153},{"title":157,"path":158,"stem":159,"children":160},"Optional vs Nullable Fields in Pydantic and FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Frequest-validation-patterns\u002Foptional-vs-nullable-fields","advanced-pydantic-validation-serialization\u002Frequest-validation-patterns\u002Foptional-vs-nullable-fields\u002Findex",[161],{"title":157,"path":158,"stem":159},{"title":163,"path":164,"stem":165,"children":166},"Query, Path and Body Parameter Validation in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Frequest-validation-patterns\u002Fquery-path-and-body-parameter-validation","advanced-pydantic-validation-serialization\u002Frequest-validation-patterns\u002Fquery-path-and-body-parameter-validation\u002Findex",[167],{"title":163,"path":164,"stem":165},{"title":169,"path":170,"stem":171,"children":172},"Validating File Uploads and Forms in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Frequest-validation-patterns\u002Fvalidating-file-uploads-and-forms","advanced-pydantic-validation-serialization\u002Frequest-validation-patterns\u002Fvalidating-file-uploads-and-forms\u002Findex",[173],{"title":169,"path":170,"stem":171},{"title":175,"path":176,"stem":177,"children":178},"Type Hinting and IDE Integration in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration","advanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration\u002Findex",[179,180],{"title":175,"path":176,"stem":177},{"title":181,"path":182,"stem":183,"children":184},"Annotated Dependencies and Reusable Types in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration\u002Fannotated-dependencies-and-reusable-types","advanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration\u002Fannotated-dependencies-and-reusable-types\u002Findex",[185],{"title":181,"path":182,"stem":183},{"title":187,"path":188,"stem":189,"children":190},"Async Background Tasks Observability","\u002Fasync-background-tasks-observability","async-background-tasks-observability",[191,194,224,254,284,308,338,362],{"title":192,"path":188,"stem":193},"Async, Background Tasks, and Observability in FastAPI","async-background-tasks-observability\u002Findex",{"title":195,"path":196,"stem":197,"children":198},"Async Correctness and Concurrency in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Findex",[199,200,206,212,218],{"title":195,"path":196,"stem":197},{"title":201,"path":202,"stem":203,"children":204},"Concurrent Requests with asyncio.gather in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Fconcurrent-requests-with-asyncio-gather","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Fconcurrent-requests-with-asyncio-gather\u002Findex",[205],{"title":201,"path":202,"stem":203},{"title":207,"path":208,"stem":209,"children":210},"FastAPI async def vs def: Performance and When to Use Each","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffastapi-async-def-vs-def-performance","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffastapi-async-def-vs-def-performance\u002Findex",[211],{"title":207,"path":208,"stem":209},{"title":213,"path":214,"stem":215,"children":216},"Fixing Blocking Calls in Async FastAPI Routes","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffixing-blocking-calls-in-async-routes","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffixing-blocking-calls-in-async-routes\u002Findex",[217],{"title":213,"path":214,"stem":215},{"title":219,"path":220,"stem":221,"children":222},"Running Sync Code in a Threadpool in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Frunning-sync-code-in-a-threadpool","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Frunning-sync-code-in-a-threadpool\u002Findex",[223],{"title":219,"path":220,"stem":221},{"title":225,"path":226,"stem":227,"children":228},"Async Database Sessions in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions","async-background-tasks-observability\u002Fasync-database-sessions\u002Findex",[229,230,236,242,248],{"title":225,"path":226,"stem":227},{"title":231,"path":232,"stem":233,"children":234},"Async SQLAlchemy Session per Request in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions\u002Fasync-sqlalchemy-session-per-request","async-background-tasks-observability\u002Fasync-database-sessions\u002Fasync-sqlalchemy-session-per-request\u002Findex",[235],{"title":231,"path":232,"stem":233},{"title":237,"path":238,"stem":239,"children":240},"Fixing asyncpg Connection Pool Exhaustion in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions\u002Ffixing-asyncpg-pool-exhaustion","async-background-tasks-observability\u002Fasync-database-sessions\u002Ffixing-asyncpg-pool-exhaustion\u002Findex",[241],{"title":237,"path":238,"stem":239},{"title":243,"path":244,"stem":245,"children":246},"Testing with Async Database Fixtures in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions\u002Ftesting-with-async-database-fixtures","async-background-tasks-observability\u002Fasync-database-sessions\u002Ftesting-with-async-database-fixtures\u002Findex",[247],{"title":243,"path":244,"stem":245},{"title":249,"path":250,"stem":251,"children":252},"Transaction Management and Rollback in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions\u002Ftransaction-management-and-rollback","async-background-tasks-observability\u002Fasync-database-sessions\u002Ftransaction-management-and-rollback\u002Findex",[253],{"title":249,"path":250,"stem":251},{"title":255,"path":256,"stem":257,"children":258},"Background Task Processing in FastAPI","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing","async-background-tasks-observability\u002Fbackground-task-processing\u002Findex",[259,260,266,272,278],{"title":255,"path":256,"stem":257},{"title":261,"path":262,"stem":263,"children":264},"FastAPI BackgroundTasks vs Celery vs ARQ","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing\u002Ffastapi-backgroundtasks-vs-celery-vs-arq","async-background-tasks-observability\u002Fbackground-task-processing\u002Ffastapi-backgroundtasks-vs-celery-vs-arq\u002Findex",[265],{"title":261,"path":262,"stem":263},{"title":267,"path":268,"stem":269,"children":270},"Retry and Idempotency for FastAPI Background Tasks","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing\u002Fretry-and-idempotency-for-tasks","async-background-tasks-observability\u002Fbackground-task-processing\u002Fretry-and-idempotency-for-tasks\u002Findex",[271],{"title":267,"path":268,"stem":269},{"title":273,"path":274,"stem":275,"children":276},"Running ARQ Workers with FastAPI","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing\u002Frunning-arq-workers-with-fastapi","async-background-tasks-observability\u002Fbackground-task-processing\u002Frunning-arq-workers-with-fastapi\u002Findex",[277],{"title":273,"path":274,"stem":275},{"title":279,"path":280,"stem":281,"children":282},"When FastAPI BackgroundTasks Silently Fails","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing\u002Fwhen-backgroundtasks-silently-fails","async-background-tasks-observability\u002Fbackground-task-processing\u002Fwhen-backgroundtasks-silently-fails\u002Findex",[283],{"title":279,"path":280,"stem":281},{"title":285,"path":286,"stem":287,"children":288},"Caching Strategies in FastAPI","\u002Fasync-background-tasks-observability\u002Fcaching-strategies","async-background-tasks-observability\u002Fcaching-strategies\u002Findex",[289,290,296,302],{"title":285,"path":286,"stem":287},{"title":291,"path":292,"stem":293,"children":294},"Cache Invalidation Patterns in FastAPI","\u002Fasync-background-tasks-observability\u002Fcaching-strategies\u002Fcache-invalidation-patterns-in-fastapi","async-background-tasks-observability\u002Fcaching-strategies\u002Fcache-invalidation-patterns-in-fastapi\u002Findex",[295],{"title":291,"path":292,"stem":293},{"title":297,"path":298,"stem":299,"children":300},"Caching Dependency Results in FastAPI","\u002Fasync-background-tasks-observability\u002Fcaching-strategies\u002Fcaching-dependency-results","async-background-tasks-observability\u002Fcaching-strategies\u002Fcaching-dependency-results\u002Findex",[301],{"title":297,"path":298,"stem":299},{"title":303,"path":304,"stem":305,"children":306},"Redis Response Caching in FastAPI","\u002Fasync-background-tasks-observability\u002Fcaching-strategies\u002Fredis-response-caching-in-fastapi","async-background-tasks-observability\u002Fcaching-strategies\u002Fredis-response-caching-in-fastapi\u002Findex",[307],{"title":303,"path":304,"stem":305},{"title":309,"path":310,"stem":311,"children":312},"Observability and Tracing in FastAPI","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing","async-background-tasks-observability\u002Fobservability-and-tracing\u002Findex",[313,314,320,326,332],{"title":309,"path":310,"stem":311},{"title":315,"path":316,"stem":317,"children":318},"Correlating Logs, Traces and Errors in FastAPI","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Fcorrelating-logs-traces-and-errors","async-background-tasks-observability\u002Fobservability-and-tracing\u002Fcorrelating-logs-traces-and-errors\u002Findex",[319],{"title":315,"path":316,"stem":317},{"title":321,"path":322,"stem":323,"children":324},"Instrumenting FastAPI with OpenTelemetry","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Finstrumenting-fastapi-with-opentelemetry","async-background-tasks-observability\u002Fobservability-and-tracing\u002Finstrumenting-fastapi-with-opentelemetry\u002Findex",[325],{"title":321,"path":322,"stem":323},{"title":327,"path":328,"stem":329,"children":330},"Prometheus Metrics for FastAPI","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Fprometheus-metrics-for-fastapi","async-background-tasks-observability\u002Fobservability-and-tracing\u002Fprometheus-metrics-for-fastapi\u002Findex",[331],{"title":327,"path":328,"stem":329},{"title":333,"path":334,"stem":335,"children":336},"Structured JSON Logging with Request IDs in FastAPI","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Fstructured-json-logging-with-request-ids","async-background-tasks-observability\u002Fobservability-and-tracing\u002Fstructured-json-logging-with-request-ids\u002Findex",[337],{"title":333,"path":334,"stem":335},{"title":339,"path":340,"stem":341,"children":342},"Rate Limiting and Throttling in FastAPI","\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling","async-background-tasks-observability\u002Frate-limiting-throttling\u002Findex",[343,344,350,356],{"title":339,"path":340,"stem":341},{"title":345,"path":346,"stem":347,"children":348},"FastAPI Rate Limiting with Redis and SlowAPI","\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling\u002Ffastapi-rate-limiting-with-redis-slowapi","async-background-tasks-observability\u002Frate-limiting-throttling\u002Ffastapi-rate-limiting-with-redis-slowapi\u002Findex",[349],{"title":345,"path":346,"stem":347},{"title":351,"path":352,"stem":353,"children":354},"Per-User Token Bucket Throttling in FastAPI","\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling\u002Fper-user-token-bucket-throttling","async-background-tasks-observability\u002Frate-limiting-throttling\u002Fper-user-token-bucket-throttling\u002Findex",[355],{"title":351,"path":352,"stem":353},{"title":357,"path":358,"stem":359,"children":360},"Rate Limit Headers and 429 Responses in FastAPI","\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling\u002Frate-limit-headers-and-429-responses","async-background-tasks-observability\u002Frate-limiting-throttling\u002Frate-limit-headers-and-429-responses\u002Findex",[361],{"title":357,"path":358,"stem":359},{"title":363,"path":364,"stem":365,"children":366},"Testing FastAPI Applications","\u002Fasync-background-tasks-observability\u002Ftesting-fastapi-applications","async-background-tasks-observability\u002Ftesting-fastapi-applications\u002Findex",[367,368,374,380],{"title":363,"path":364,"stem":365},{"title":369,"path":370,"stem":371,"children":372},"Mocking External Services in FastAPI Tests","\u002Fasync-background-tasks-observability\u002Ftesting-fastapi-applications\u002Fmocking-external-services-in-tests","async-background-tasks-observability\u002Ftesting-fastapi-applications\u002Fmocking-external-services-in-tests\u002Findex",[373],{"title":369,"path":370,"stem":371},{"title":375,"path":376,"stem":377,"children":378},"TestClient vs httpx AsyncClient in FastAPI","\u002Fasync-background-tasks-observability\u002Ftesting-fastapi-applications\u002Ftestclient-vs-httpx-asyncclient","async-background-tasks-observability\u002Ftesting-fastapi-applications\u002Ftestclient-vs-httpx-asyncclient\u002Findex",[379],{"title":375,"path":376,"stem":377},{"title":381,"path":382,"stem":383,"children":384},"Testing Async FastAPI Endpoints with pytest-asyncio","\u002Fasync-background-tasks-observability\u002Ftesting-fastapi-applications\u002Ftesting-async-endpoints-with-pytest-asyncio","async-background-tasks-observability\u002Ftesting-fastapi-applications\u002Ftesting-async-endpoints-with-pytest-asyncio\u002Findex",[385],{"title":381,"path":382,"stem":383},{"title":387,"path":388,"stem":389,"children":390},"Core Architecture Routing Patterns","\u002Fcore-architecture-routing-patterns","core-architecture-routing-patterns",[391,394,412,436,472,496,526,556],{"title":392,"path":388,"stem":393},"FastAPI Core Architecture and Routing Patterns","core-architecture-routing-patterns\u002Findex",{"title":395,"path":396,"stem":397,"children":398},"Application Factory Patterns in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns","core-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Findex",[399,400,406],{"title":395,"path":396,"stem":397},{"title":401,"path":402,"stem":403,"children":404},"FastAPI App Factory Pattern for Testing and Deployment","\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Ffastapi-app-factory-pattern-for-testing-and-deployment","core-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Ffastapi-app-factory-pattern-for-testing-and-deployment\u002Findex",[405],{"title":401,"path":402,"stem":403},{"title":407,"path":408,"stem":409,"children":410},"Lifespan Events vs Startup and Shutdown in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Flifespan-events-vs-startup-shutdown","core-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Flifespan-events-vs-startup-shutdown\u002Findex",[411],{"title":407,"path":408,"stem":409},{"title":413,"path":414,"stem":415,"children":416},"Configuration Management in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management","core-architecture-routing-patterns\u002Fconfiguration-management\u002Findex",[417,418,424,430],{"title":413,"path":414,"stem":415},{"title":419,"path":420,"stem":421,"children":422},"Managing Environment Variables with Pydantic Settings","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fmanaging-environment-variables-with-pydantic-settings","core-architecture-routing-patterns\u002Fconfiguration-management\u002Fmanaging-environment-variables-with-pydantic-settings\u002Findex",[423],{"title":419,"path":420,"stem":421},{"title":425,"path":426,"stem":427,"children":428},"Pydantic Settings vs Dynaconf vs python-decouple","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fpydantic-settings-vs-dynaconf-vs-python-decouple","core-architecture-routing-patterns\u002Fconfiguration-management\u002Fpydantic-settings-vs-dynaconf-vs-python-decouple\u002Findex",[429],{"title":425,"path":426,"stem":427},{"title":431,"path":432,"stem":433,"children":434},"Secrets and .env Files Per Environment in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fsecrets-and-env-files-per-environment","core-architecture-routing-patterns\u002Fconfiguration-management\u002Fsecrets-and-env-files-per-environment\u002Findex",[435],{"title":431,"path":432,"stem":433},{"title":437,"path":438,"stem":439,"children":440},"Dependency Injection Strategies in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Findex",[441,442,448,454,460,466],{"title":437,"path":438,"stem":439},{"title":443,"path":444,"stem":445,"children":446},"Best Practices for FastAPI Dependency Injection","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fbest-practices-for-fastapi-dependency-injection","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fbest-practices-for-fastapi-dependency-injection\u002Findex",[447],{"title":443,"path":444,"stem":445},{"title":449,"path":450,"stem":451,"children":452},"Dependency Caching and use_cache in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fdependency-caching-and-use-cache","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fdependency-caching-and-use-cache\u002Findex",[453],{"title":449,"path":450,"stem":451},{"title":455,"path":456,"stem":457,"children":458},"Fixing FastAPI Dependency Injection Circular Imports","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Ffastapi-dependency-injection-circular-import-fix","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Ffastapi-dependency-injection-circular-import-fix\u002Findex",[459],{"title":455,"path":456,"stem":457},{"title":461,"path":462,"stem":463,"children":464},"Overriding Dependencies in FastAPI Tests","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Foverriding-dependencies-in-tests","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Foverriding-dependencies-in-tests\u002Findex",[465],{"title":461,"path":462,"stem":463},{"title":467,"path":468,"stem":469,"children":470},"Yield Dependencies and Cleanup Order in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fyield-dependencies-and-cleanup-order","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fyield-dependencies-and-cleanup-order\u002Findex",[471],{"title":467,"path":468,"stem":469},{"title":473,"path":474,"stem":475,"children":476},"Error Handling and Global Exceptions in FastAPI","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Findex",[477,478,484,490],{"title":473,"path":474,"stem":475},{"title":479,"path":480,"stem":481,"children":482},"Customising Validation Error Responses in FastAPI","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fcustomising-validation-error-responses","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fcustomising-validation-error-responses\u002Findex",[483],{"title":479,"path":480,"stem":481},{"title":485,"path":486,"stem":487,"children":488},"Global Exception Handlers for Consistent API Responses","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fglobal-exception-handlers-for-consistent-api-responses","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fglobal-exception-handlers-for-consistent-api-responses\u002Findex",[489],{"title":485,"path":486,"stem":487},{"title":491,"path":492,"stem":493,"children":494},"HTTPException vs Custom Exception Classes in FastAPI","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fhttpexception-vs-custom-exception-classes","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fhttpexception-vs-custom-exception-classes\u002Findex",[495],{"title":491,"path":492,"stem":493},{"title":497,"path":498,"stem":499,"children":500},"Middleware Implementation in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Findex",[501,502,508,514,520],{"title":497,"path":498,"stem":499},{"title":503,"path":504,"stem":505,"children":506},"CORS Middleware Configuration in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fcors-middleware-configuration","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fcors-middleware-configuration\u002Findex",[507],{"title":503,"path":504,"stem":505},{"title":509,"path":510,"stem":511,"children":512},"Implementing Custom Middleware for Request Tracing","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fimplementing-custom-middleware-for-request-tracing","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fimplementing-custom-middleware-for-request-tracing\u002Findex",[513],{"title":509,"path":510,"stem":511},{"title":515,"path":516,"stem":517,"children":518},"Middleware Execution Order in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fmiddleware-execution-order","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fmiddleware-execution-order\u002Findex",[519],{"title":515,"path":516,"stem":517},{"title":521,"path":522,"stem":523,"children":524},"Middleware vs Dependencies: When to Use Which","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fmiddleware-vs-dependencies-when-to-use-which","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fmiddleware-vs-dependencies-when-to-use-which\u002Findex",[525],{"title":521,"path":522,"stem":523},{"title":527,"path":528,"stem":529,"children":530},"Modular Router Organization in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Findex",[531,532,538,544,550],{"title":527,"path":528,"stem":529},{"title":533,"path":534,"stem":535,"children":536},"APIRouter Prefix vs Sub-Application Mounting in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization\u002Fapirouter-prefix-vs-sub-application-mounting","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Fapirouter-prefix-vs-sub-application-mounting\u002Findex",[537],{"title":533,"path":534,"stem":535},{"title":539,"path":540,"stem":541,"children":542},"How to Structure Large FastAPI Projects for Scale","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization\u002Fhow-to-structure-large-fastapi-projects-for-scale","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Fhow-to-structure-large-fastapi-projects-for-scale\u002Findex",[543],{"title":539,"path":540,"stem":541},{"title":545,"path":546,"stem":547,"children":548},"Router Tags and OpenAPI Grouping in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization\u002Frouter-tags-and-openapi-grouping","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Frouter-tags-and-openapi-grouping\u002Findex",[549],{"title":545,"path":546,"stem":547},{"title":551,"path":552,"stem":553,"children":554},"Versioning APIs with FastAPI Routers","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization\u002Fversioning-apis-with-routers","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Fversioning-apis-with-routers\u002Findex",[555],{"title":551,"path":552,"stem":553},{"title":557,"path":558,"stem":559,"children":560},"The FastAPI Request\u002FResponse Lifecycle","\u002Fcore-architecture-routing-patterns\u002Frequest-response-lifecycle","core-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Findex",[561,562,568,574],{"title":557,"path":558,"stem":559},{"title":563,"path":564,"stem":565,"children":566},"How a Request Flows Through FastAPI","\u002Fcore-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fhow-a-request-flows-through-fastapi","core-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fhow-a-request-flows-through-fastapi\u002Findex",[567],{"title":563,"path":564,"stem":565},{"title":569,"path":570,"stem":571,"children":572},"Response Model and Serialization Order","\u002Fcore-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fresponse-model-and-serialization-order","core-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fresponse-model-and-serialization-order\u002Findex",[573],{"title":569,"path":570,"stem":571},{"title":575,"path":576,"stem":577,"children":578},"Streaming and File Responses in FastAPI","\u002Fcore-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fstreaming-and-file-responses","core-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fstreaming-and-file-responses\u002Findex",[579],{"title":575,"path":576,"stem":577},{"id":581,"title":461,"body":582,"dateModified":2489,"datePublished":2489,"description":2490,"extension":2491,"faq":2492,"howto":2503,"meta":2504,"navigation":881,"path":462,"seo":2517,"stem":463,"type":2518,"__hash__":2519},"content\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Foverriding-dependencies-in-tests\u002Findex.md",{"type":583,"value":584,"toc":2476},"minimark",[585,589,596,630,639,644,655,662,770,774,783,791,803,807,829,1716,1719,1726,1736,1755,1774,1782,1786,1789,2019,2025,2074,2079,2098,2101,2150,2161,2165,2173,2180,2266,2277,2281,2294,2306,2320,2324,2337,2347,2358,2376,2380,2386,2392,2401,2407,2417,2427,2431,2472],[586,587,461],"h1",{"id":588},"overriding-dependencies-in-fastapi-tests",[590,591,592],"p",{},[593,594,595],"strong",{},"Key takeaways:",[597,598,599,611,614,617,627],"ul",{},[600,601,602,606,607,610],"li",{},[603,604,605],"code",{},"app.dependency_overrides"," is a plain dict keyed by the ",[593,608,609],{},"callable object"," the route declares — identity, not name.",[600,612,613],{},"An override keyed on the wrong callable fails silently. There is no warning, no error, just the real dependency running.",[600,615,616],{},"The dictionary lives on the app, so it outlives the test. Clear it in fixture teardown or tests contaminate each other.",[600,618,619,620,623,624,626],{},"Overriding a ",[603,621,622],{},"yield"," dependency works, and the replacement should also ",[603,625,622],{}," if you want its teardown exercised.",[600,628,629],{},"Overrides are application-wide. Per-route substitution needs a distinct provider or a per-test app.",[590,631,632,633,638],{},"Testing is the payoff for building the graph described in ",[634,635,637],"a",{"href":636},"\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002F","dependency injection strategies",": every node in it is replaceable from the outside without touching the code under test.",[640,641,643],"h2",{"id":642},"the-problem-this-solves","The Problem This Solves",[590,645,646,647,650,651,654],{},"Your ",[603,648,649],{},"\u002Fme"," endpoint depends on ",[603,652,653],{},"get_current_user",", which reads a header and validates a token, which needs a secret, which needs settings. To test the handler's actual logic you would otherwise need a valid token, a signing key, and probably a user row. Overrides let you cut the graph at exactly one node and hand the handler the value it needs.",[590,656,657,658,661],{},"The failure mode is what makes this worth a page. Overrides use ",[603,659,660],{},"dict"," lookup on a function object. When the key does not match, nothing complains — the test simply runs against production behaviour and fails with an error that looks like a bug in your code.",[663,664,665,766],"figure",{},[666,667,675,676,675,680,675,684,675,693,675,699,675,706,675,711,675,716,675,723,675,729,675,733,675,737,675,742,675,745,675,750,675,756,675,761],"svg",{"viewBox":668,"role":669,"ariaLabelledBy":670,"xmlns":673,"style":674},"0 0 720 300","img",[671,672],"ovr-t","ovr-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;height:auto;max-width:720px;margin:2rem 0","\n  ",[677,678,679],"title",{"id":671},"How dependency_overrides substitutes a node by identity",[681,682,683],"desc",{"id":672},"The resolver looks up the declared callable in the overrides dictionary. A matching key returns the fake provider. A key that is a different object with the same name misses, and the real provider runs.",[685,686],"rect",{"x":687,"y":688,"width":689,"height":690,"rx":691,"style":692},"255","16","210","44","8","fill:#E0F2F1;stroke:#00796B;stroke-width:2px",[694,695,698],"text",{"x":696,"y":690,"style":697},"360","text-anchor:middle;fill:#00695C;font:700 13px sans-serif","Depends(get_user)",[685,700],{"x":701,"y":702,"width":703,"height":704,"rx":691,"style":705},"235","104","250","46","fill:#FFFFFF;stroke:currentColor;stroke-width:1.5px",[694,707,710],{"x":696,"y":708,"style":709},"124","text-anchor:middle;fill:currentColor;font:600 12px sans-serif","overrides.get(callable)",[694,712,715],{"x":696,"y":713,"style":714},"141","text-anchor:middle;fill:#4B5563;font:400 11px sans-serif","compared with is, not by name",[685,717],{"x":718,"y":719,"width":720,"height":721,"rx":691,"style":722},"40","196","270","60","fill:#E0F2F1;stroke:#00796B;stroke-width:1.6px",[694,724,728],{"x":725,"y":726,"style":727},"175","219","text-anchor:middle;fill:#00695C;font:700 12px sans-serif","key matches",[694,730,732],{"x":725,"y":731,"style":714},"238","fake provider runs",[685,734],{"x":735,"y":719,"width":720,"height":721,"rx":691,"style":736},"410","fill:#FFFFFF;stroke:#B00020;stroke-width:1.6px",[694,738,741],{"x":739,"y":726,"style":740},"545","text-anchor:middle;fill:#B00020;font:700 12px sans-serif","key misses",[694,743,744],{"x":739,"y":731,"style":714},"real provider runs, silently",[746,747],"line",{"x1":696,"y1":721,"x2":696,"y2":748,"style":749},"102","stroke:#00796B;stroke-width:1.6px",[746,751],{"x1":752,"y1":753,"x2":754,"y2":755,"style":749},"300","150","200","194",[746,757],{"x1":758,"y1":753,"x2":759,"y2":755,"style":760},"420","520","stroke:#B00020;stroke-width:1.6px",[694,762,765],{"x":696,"y":763,"style":764},"286","text-anchor:middle;fill:#4B5563;font:400 12px sans-serif","Nothing is logged on a miss — the test just exercises production code.",[767,768,769],"figcaption",{},"The override is a dictionary lookup on the function object. A near-identical function is a different key.",[640,771,773],{"id":772},"why-it-happens-one-dict-keyed-by-identity","Why It Happens: One Dict, Keyed by Identity",[590,775,776,778,779,782],{},[603,777,605],{}," is an ordinary dictionary attribute on the ",[603,780,781],{},"FastAPI"," instance. During resolution, before FastAPI calls a provider it checks whether that provider appears as a key and, if so, calls the value instead. The lookup uses the callable's hash and equality, and for plain functions that is object identity.",[590,784,785,786,790],{},"That single design choice explains both the power and the sharp edge. It is the same identity rule that governs the per-request cache in ",[634,787,789],{"href":788},"\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fdependency-caching-and-use-cache\u002F","dependency caching and use_cache",": two functions with the same name and the same body are two different keys.",[590,792,793,794,798,799,802],{},"The dictionary is also ",[795,796,797],"em",{},"not"," request-scoped or test-scoped. It is application state. If your ",[603,800,801],{},"client"," fixture is session-scoped — as most are, because constructing the app is slow — then an override written in the third test is still installed for the ninetieth.",[640,804,806],{"id":805},"proving-it-before-after-and-the-silent-miss","Proving It: Before, After, and the Silent Miss",[590,808,809,810,812,813,815,816,819,820,822,823,825,826,828],{},"This app makes the whole cycle observable in one transcript. ",[603,811,649],{}," depends on a real ",[603,814,653],{}," (which rejects requests without a token) and a real ",[603,817,818],{},"get_db"," (a ",[603,821,622],{}," dependency). Three control endpoints mutate ",[603,824,605],{}," exactly as a test fixture would, and ",[603,827,649],{}," is called again after each mutation.",[830,831,836],"pre",{"className":832,"code":833,"language":834,"meta":835,"style":835},"language-python shiki shiki-themes github-light-high-contrast","\"\"\"app.dependency_overrides: real before\u002Fafter responses, yield overrides, and wrong-key misses.\"\"\"\nfrom collections.abc import AsyncGenerator\nfrom typing import Annotated\n\nfrom fastapi import Depends, FastAPI, Header, HTTPException\n\napp = FastAPI()\n\n\nasync def get_current_user(x_token: Annotated[str | None, Header()] = None) -> dict:\n    \"\"\"The real dependency: refuses to run without a token.\"\"\"\n    if x_token != \"prod-secret\":\n        raise HTTPException(status_code=401, detail=\"Not authenticated\")\n    return {\"id\": 1, \"name\": \"real-user\", \"source\": \"production\"}\n\n\nasync def get_db() -> AsyncGenerator[dict, None]:\n    session = {\"engine\": \"postgres\", \"rows\": [\"real-row\"]}\n    try:\n        yield session\n    finally:\n        session[\"closed\"] = True\n\n\nUserDep = Annotated[dict, Depends(get_current_user)]\nDbDep = Annotated[dict, Depends(get_db)]\n\n\n@app.get(\"\u002Fme\")\nasync def me(user: UserDep, db: DbDep):\n    return {\"user\": user, \"rows\": db[\"rows\"]}\n\n\nasync def fake_user() -> dict:\n    return {\"id\": 99, \"name\": \"test-user\", \"source\": \"override\"}\n\n\nasync def fake_db() -> AsyncGenerator[dict, None]:\n    session = {\"engine\": \"sqlite-memory\", \"rows\": [\"fixture-row\"]}\n    try:\n        yield session\n    finally:\n        session[\"closed\"] = True\n\n\n# A callable that is NOT the one the endpoint declares — the classic silent no-op.\nasync def get_current_user_copy() -> dict:\n    return {\"id\": 0, \"name\": \"never-used\", \"source\": \"wrong-key\"}\n\n\n@app.post(\"\u002F_control\u002Foverride-correct\")\nasync def override_correct():\n    app.dependency_overrides[get_current_user] = fake_user\n    app.dependency_overrides[get_db] = fake_db\n    return {\"overrides\": sorted(fn.__name__ for fn in app.dependency_overrides)}\n\n\n@app.post(\"\u002F_control\u002Foverride-wrong-key\")\nasync def override_wrong_key():\n    app.dependency_overrides.clear()\n    app.dependency_overrides[get_current_user_copy] = fake_user\n    return {\"overrides\": sorted(fn.__name__ for fn in app.dependency_overrides)}\n\n\n@app.post(\"\u002F_control\u002Fclear\")\nasync def clear():\n    app.dependency_overrides.clear()\n    return {\"overrides\": sorted(fn.__name__ for fn in app.dependency_overrides)}\n","python","",[603,837,838,846,863,876,883,896,901,913,918,923,964,970,987,1019,1060,1065,1070,1093,1125,1133,1142,1150,1167,1172,1177,1193,1208,1213,1218,1232,1245,1267,1272,1277,1294,1328,1333,1338,1358,1385,1392,1399,1406,1419,1424,1429,1436,1452,1486,1491,1496,1509,1522,1533,1544,1577,1582,1587,1599,1611,1617,1627,1652,1657,1662,1674,1686,1691],{"__ignoreMap":835},[839,840,842],"span",{"class":746,"line":841},1,[839,843,845],{"class":844},"sYEJz","\"\"\"app.dependency_overrides: real before\u002Fafter responses, yield overrides, and wrong-key misses.\"\"\"\n",[839,847,849,853,857,860],{"class":746,"line":848},2,[839,850,852],{"class":851},"sTJeM","from",[839,854,856],{"class":855},"sigWx"," collections.abc ",[839,858,859],{"class":851},"import",[839,861,862],{"class":855}," AsyncGenerator\n",[839,864,866,868,871,873],{"class":746,"line":865},3,[839,867,852],{"class":851},[839,869,870],{"class":855}," typing ",[839,872,859],{"class":851},[839,874,875],{"class":855}," Annotated\n",[839,877,879],{"class":746,"line":878},4,[839,880,882],{"emptyLinePlaceholder":881},true,"\n",[839,884,886,888,891,893],{"class":746,"line":885},5,[839,887,852],{"class":851},[839,889,890],{"class":855}," fastapi ",[839,892,859],{"class":851},[839,894,895],{"class":855}," Depends, FastAPI, Header, HTTPException\n",[839,897,899],{"class":746,"line":898},6,[839,900,882],{"emptyLinePlaceholder":881},[839,902,904,907,910],{"class":746,"line":903},7,[839,905,906],{"class":855},"app ",[839,908,909],{"class":851},"=",[839,911,912],{"class":855}," FastAPI()\n",[839,914,916],{"class":746,"line":915},8,[839,917,882],{"emptyLinePlaceholder":881},[839,919,921],{"class":746,"line":920},9,[839,922,882],{"emptyLinePlaceholder":881},[839,924,926,929,932,936,939,943,946,949,952,954,956,959,961],{"class":746,"line":925},10,[839,927,928],{"class":851},"async",[839,930,931],{"class":851}," def",[839,933,935],{"class":934},"s3dhs"," get_current_user",[839,937,938],{"class":855},"(x_token: Annotated[",[839,940,942],{"class":941},"sacAq","str",[839,944,945],{"class":851}," |",[839,947,948],{"class":941}," None",[839,950,951],{"class":855},", Header()] ",[839,953,909],{"class":851},[839,955,948],{"class":941},[839,957,958],{"class":855},") -> ",[839,960,660],{"class":941},[839,962,963],{"class":855},":\n",[839,965,967],{"class":746,"line":966},11,[839,968,969],{"class":844},"    \"\"\"The real dependency: refuses to run without a token.\"\"\"\n",[839,971,973,976,979,982,985],{"class":746,"line":972},12,[839,974,975],{"class":851},"    if",[839,977,978],{"class":855}," x_token ",[839,980,981],{"class":851},"!=",[839,983,984],{"class":844}," \"prod-secret\"",[839,986,963],{"class":855},[839,988,990,993,996,1000,1002,1005,1008,1011,1013,1016],{"class":746,"line":989},13,[839,991,992],{"class":851},"        raise",[839,994,995],{"class":855}," HTTPException(",[839,997,999],{"class":998},"sV4o_","status_code",[839,1001,909],{"class":851},[839,1003,1004],{"class":941},"401",[839,1006,1007],{"class":855},", ",[839,1009,1010],{"class":998},"detail",[839,1012,909],{"class":851},[839,1014,1015],{"class":844},"\"Not authenticated\"",[839,1017,1018],{"class":855},")\n",[839,1020,1022,1025,1028,1031,1034,1037,1039,1042,1044,1047,1049,1052,1054,1057],{"class":746,"line":1021},14,[839,1023,1024],{"class":851},"    return",[839,1026,1027],{"class":855}," {",[839,1029,1030],{"class":844},"\"id\"",[839,1032,1033],{"class":855},": ",[839,1035,1036],{"class":941},"1",[839,1038,1007],{"class":855},[839,1040,1041],{"class":844},"\"name\"",[839,1043,1033],{"class":855},[839,1045,1046],{"class":844},"\"real-user\"",[839,1048,1007],{"class":855},[839,1050,1051],{"class":844},"\"source\"",[839,1053,1033],{"class":855},[839,1055,1056],{"class":844},"\"production\"",[839,1058,1059],{"class":855},"}\n",[839,1061,1063],{"class":746,"line":1062},15,[839,1064,882],{"emptyLinePlaceholder":881},[839,1066,1068],{"class":746,"line":1067},16,[839,1069,882],{"emptyLinePlaceholder":881},[839,1071,1073,1075,1077,1080,1083,1085,1087,1090],{"class":746,"line":1072},17,[839,1074,928],{"class":851},[839,1076,931],{"class":851},[839,1078,1079],{"class":934}," get_db",[839,1081,1082],{"class":855},"() -> AsyncGenerator[",[839,1084,660],{"class":941},[839,1086,1007],{"class":855},[839,1088,1089],{"class":941},"None",[839,1091,1092],{"class":855},"]:\n",[839,1094,1096,1099,1101,1103,1106,1108,1111,1113,1116,1119,1122],{"class":746,"line":1095},18,[839,1097,1098],{"class":855},"    session ",[839,1100,909],{"class":851},[839,1102,1027],{"class":855},[839,1104,1105],{"class":844},"\"engine\"",[839,1107,1033],{"class":855},[839,1109,1110],{"class":844},"\"postgres\"",[839,1112,1007],{"class":855},[839,1114,1115],{"class":844},"\"rows\"",[839,1117,1118],{"class":855},": [",[839,1120,1121],{"class":844},"\"real-row\"",[839,1123,1124],{"class":855},"]}\n",[839,1126,1128,1131],{"class":746,"line":1127},19,[839,1129,1130],{"class":851},"    try",[839,1132,963],{"class":855},[839,1134,1136,1139],{"class":746,"line":1135},20,[839,1137,1138],{"class":851},"        yield",[839,1140,1141],{"class":855}," session\n",[839,1143,1145,1148],{"class":746,"line":1144},21,[839,1146,1147],{"class":851},"    finally",[839,1149,963],{"class":855},[839,1151,1153,1156,1159,1162,1164],{"class":746,"line":1152},22,[839,1154,1155],{"class":855},"        session[",[839,1157,1158],{"class":844},"\"closed\"",[839,1160,1161],{"class":855},"] ",[839,1163,909],{"class":851},[839,1165,1166],{"class":941}," True\n",[839,1168,1170],{"class":746,"line":1169},23,[839,1171,882],{"emptyLinePlaceholder":881},[839,1173,1175],{"class":746,"line":1174},24,[839,1176,882],{"emptyLinePlaceholder":881},[839,1178,1180,1183,1185,1188,1190],{"class":746,"line":1179},25,[839,1181,1182],{"class":855},"UserDep ",[839,1184,909],{"class":851},[839,1186,1187],{"class":855}," Annotated[",[839,1189,660],{"class":941},[839,1191,1192],{"class":855},", Depends(get_current_user)]\n",[839,1194,1196,1199,1201,1203,1205],{"class":746,"line":1195},26,[839,1197,1198],{"class":855},"DbDep ",[839,1200,909],{"class":851},[839,1202,1187],{"class":855},[839,1204,660],{"class":941},[839,1206,1207],{"class":855},", Depends(get_db)]\n",[839,1209,1211],{"class":746,"line":1210},27,[839,1212,882],{"emptyLinePlaceholder":881},[839,1214,1216],{"class":746,"line":1215},28,[839,1217,882],{"emptyLinePlaceholder":881},[839,1219,1221,1224,1227,1230],{"class":746,"line":1220},29,[839,1222,1223],{"class":934},"@app.get",[839,1225,1226],{"class":855},"(",[839,1228,1229],{"class":844},"\"\u002Fme\"",[839,1231,1018],{"class":855},[839,1233,1235,1237,1239,1242],{"class":746,"line":1234},30,[839,1236,928],{"class":851},[839,1238,931],{"class":851},[839,1240,1241],{"class":934}," me",[839,1243,1244],{"class":855},"(user: UserDep, db: DbDep):\n",[839,1246,1248,1250,1252,1255,1258,1260,1263,1265],{"class":746,"line":1247},31,[839,1249,1024],{"class":851},[839,1251,1027],{"class":855},[839,1253,1254],{"class":844},"\"user\"",[839,1256,1257],{"class":855},": user, ",[839,1259,1115],{"class":844},[839,1261,1262],{"class":855},": db[",[839,1264,1115],{"class":844},[839,1266,1124],{"class":855},[839,1268,1270],{"class":746,"line":1269},32,[839,1271,882],{"emptyLinePlaceholder":881},[839,1273,1275],{"class":746,"line":1274},33,[839,1276,882],{"emptyLinePlaceholder":881},[839,1278,1280,1282,1284,1287,1290,1292],{"class":746,"line":1279},34,[839,1281,928],{"class":851},[839,1283,931],{"class":851},[839,1285,1286],{"class":934}," fake_user",[839,1288,1289],{"class":855},"() -> ",[839,1291,660],{"class":941},[839,1293,963],{"class":855},[839,1295,1297,1299,1301,1303,1305,1308,1310,1312,1314,1317,1319,1321,1323,1326],{"class":746,"line":1296},35,[839,1298,1024],{"class":851},[839,1300,1027],{"class":855},[839,1302,1030],{"class":844},[839,1304,1033],{"class":855},[839,1306,1307],{"class":941},"99",[839,1309,1007],{"class":855},[839,1311,1041],{"class":844},[839,1313,1033],{"class":855},[839,1315,1316],{"class":844},"\"test-user\"",[839,1318,1007],{"class":855},[839,1320,1051],{"class":844},[839,1322,1033],{"class":855},[839,1324,1325],{"class":844},"\"override\"",[839,1327,1059],{"class":855},[839,1329,1331],{"class":746,"line":1330},36,[839,1332,882],{"emptyLinePlaceholder":881},[839,1334,1336],{"class":746,"line":1335},37,[839,1337,882],{"emptyLinePlaceholder":881},[839,1339,1341,1343,1345,1348,1350,1352,1354,1356],{"class":746,"line":1340},38,[839,1342,928],{"class":851},[839,1344,931],{"class":851},[839,1346,1347],{"class":934}," fake_db",[839,1349,1082],{"class":855},[839,1351,660],{"class":941},[839,1353,1007],{"class":855},[839,1355,1089],{"class":941},[839,1357,1092],{"class":855},[839,1359,1361,1363,1365,1367,1369,1371,1374,1376,1378,1380,1383],{"class":746,"line":1360},39,[839,1362,1098],{"class":855},[839,1364,909],{"class":851},[839,1366,1027],{"class":855},[839,1368,1105],{"class":844},[839,1370,1033],{"class":855},[839,1372,1373],{"class":844},"\"sqlite-memory\"",[839,1375,1007],{"class":855},[839,1377,1115],{"class":844},[839,1379,1118],{"class":855},[839,1381,1382],{"class":844},"\"fixture-row\"",[839,1384,1124],{"class":855},[839,1386,1388,1390],{"class":746,"line":1387},40,[839,1389,1130],{"class":851},[839,1391,963],{"class":855},[839,1393,1395,1397],{"class":746,"line":1394},41,[839,1396,1138],{"class":851},[839,1398,1141],{"class":855},[839,1400,1402,1404],{"class":746,"line":1401},42,[839,1403,1147],{"class":851},[839,1405,963],{"class":855},[839,1407,1409,1411,1413,1415,1417],{"class":746,"line":1408},43,[839,1410,1155],{"class":855},[839,1412,1158],{"class":844},[839,1414,1161],{"class":855},[839,1416,909],{"class":851},[839,1418,1166],{"class":941},[839,1420,1422],{"class":746,"line":1421},44,[839,1423,882],{"emptyLinePlaceholder":881},[839,1425,1427],{"class":746,"line":1426},45,[839,1428,882],{"emptyLinePlaceholder":881},[839,1430,1432],{"class":746,"line":1431},46,[839,1433,1435],{"class":1434},"sFeEa","# A callable that is NOT the one the endpoint declares — the classic silent no-op.\n",[839,1437,1439,1441,1443,1446,1448,1450],{"class":746,"line":1438},47,[839,1440,928],{"class":851},[839,1442,931],{"class":851},[839,1444,1445],{"class":934}," get_current_user_copy",[839,1447,1289],{"class":855},[839,1449,660],{"class":941},[839,1451,963],{"class":855},[839,1453,1455,1457,1459,1461,1463,1466,1468,1470,1472,1475,1477,1479,1481,1484],{"class":746,"line":1454},48,[839,1456,1024],{"class":851},[839,1458,1027],{"class":855},[839,1460,1030],{"class":844},[839,1462,1033],{"class":855},[839,1464,1465],{"class":941},"0",[839,1467,1007],{"class":855},[839,1469,1041],{"class":844},[839,1471,1033],{"class":855},[839,1473,1474],{"class":844},"\"never-used\"",[839,1476,1007],{"class":855},[839,1478,1051],{"class":844},[839,1480,1033],{"class":855},[839,1482,1483],{"class":844},"\"wrong-key\"",[839,1485,1059],{"class":855},[839,1487,1489],{"class":746,"line":1488},49,[839,1490,882],{"emptyLinePlaceholder":881},[839,1492,1494],{"class":746,"line":1493},50,[839,1495,882],{"emptyLinePlaceholder":881},[839,1497,1499,1502,1504,1507],{"class":746,"line":1498},51,[839,1500,1501],{"class":934},"@app.post",[839,1503,1226],{"class":855},[839,1505,1506],{"class":844},"\"\u002F_control\u002Foverride-correct\"",[839,1508,1018],{"class":855},[839,1510,1512,1514,1516,1519],{"class":746,"line":1511},52,[839,1513,928],{"class":851},[839,1515,931],{"class":851},[839,1517,1518],{"class":934}," override_correct",[839,1520,1521],{"class":855},"():\n",[839,1523,1525,1528,1530],{"class":746,"line":1524},53,[839,1526,1527],{"class":855},"    app.dependency_overrides[get_current_user] ",[839,1529,909],{"class":851},[839,1531,1532],{"class":855}," fake_user\n",[839,1534,1536,1539,1541],{"class":746,"line":1535},54,[839,1537,1538],{"class":855},"    app.dependency_overrides[get_db] ",[839,1540,909],{"class":851},[839,1542,1543],{"class":855}," fake_db\n",[839,1545,1547,1549,1551,1554,1556,1559,1562,1565,1568,1571,1574],{"class":746,"line":1546},55,[839,1548,1024],{"class":851},[839,1550,1027],{"class":855},[839,1552,1553],{"class":844},"\"overrides\"",[839,1555,1033],{"class":855},[839,1557,1558],{"class":941},"sorted",[839,1560,1561],{"class":855},"(fn.",[839,1563,1564],{"class":941},"__name__",[839,1566,1567],{"class":851}," for",[839,1569,1570],{"class":855}," fn ",[839,1572,1573],{"class":851},"in",[839,1575,1576],{"class":855}," app.dependency_overrides)}\n",[839,1578,1580],{"class":746,"line":1579},56,[839,1581,882],{"emptyLinePlaceholder":881},[839,1583,1585],{"class":746,"line":1584},57,[839,1586,882],{"emptyLinePlaceholder":881},[839,1588,1590,1592,1594,1597],{"class":746,"line":1589},58,[839,1591,1501],{"class":934},[839,1593,1226],{"class":855},[839,1595,1596],{"class":844},"\"\u002F_control\u002Foverride-wrong-key\"",[839,1598,1018],{"class":855},[839,1600,1602,1604,1606,1609],{"class":746,"line":1601},59,[839,1603,928],{"class":851},[839,1605,931],{"class":851},[839,1607,1608],{"class":934}," override_wrong_key",[839,1610,1521],{"class":855},[839,1612,1614],{"class":746,"line":1613},60,[839,1615,1616],{"class":855},"    app.dependency_overrides.clear()\n",[839,1618,1620,1623,1625],{"class":746,"line":1619},61,[839,1621,1622],{"class":855},"    app.dependency_overrides[get_current_user_copy] ",[839,1624,909],{"class":851},[839,1626,1532],{"class":855},[839,1628,1630,1632,1634,1636,1638,1640,1642,1644,1646,1648,1650],{"class":746,"line":1629},62,[839,1631,1024],{"class":851},[839,1633,1027],{"class":855},[839,1635,1553],{"class":844},[839,1637,1033],{"class":855},[839,1639,1558],{"class":941},[839,1641,1561],{"class":855},[839,1643,1564],{"class":941},[839,1645,1567],{"class":851},[839,1647,1570],{"class":855},[839,1649,1573],{"class":851},[839,1651,1576],{"class":855},[839,1653,1655],{"class":746,"line":1654},63,[839,1656,882],{"emptyLinePlaceholder":881},[839,1658,1660],{"class":746,"line":1659},64,[839,1661,882],{"emptyLinePlaceholder":881},[839,1663,1665,1667,1669,1672],{"class":746,"line":1664},65,[839,1666,1501],{"class":934},[839,1668,1226],{"class":855},[839,1670,1671],{"class":844},"\"\u002F_control\u002Fclear\"",[839,1673,1018],{"class":855},[839,1675,1677,1679,1681,1684],{"class":746,"line":1676},66,[839,1678,928],{"class":851},[839,1680,931],{"class":851},[839,1682,1683],{"class":934}," clear",[839,1685,1521],{"class":855},[839,1687,1689],{"class":746,"line":1688},67,[839,1690,1616],{"class":855},[839,1692,1694,1696,1698,1700,1702,1704,1706,1708,1710,1712,1714],{"class":746,"line":1693},68,[839,1695,1024],{"class":851},[839,1697,1027],{"class":855},[839,1699,1553],{"class":844},[839,1701,1033],{"class":855},[839,1703,1558],{"class":941},[839,1705,1561],{"class":855},[839,1707,1564],{"class":941},[839,1709,1567],{"class":851},[839,1711,1570],{"class":855},[839,1713,1573],{"class":851},[839,1715,1576],{"class":855},[590,1717,1718],{},"The transcript below is the harness's real output:",[830,1720,1724],{"className":1721,"code":1723,"language":694,"meta":835},[1722],"language-text","$ GET \u002Fme\n401 Unauthorized\n{\n  \"detail\": \"Not authenticated\"\n}\n\n$ POST \u002F_control\u002Foverride-correct\n200 OK\n{\n  \"overrides\": [\n    \"get_current_user\",\n    \"get_db\"\n  ]\n}\n\n$ GET \u002Fme\n200 OK\n{\n  \"user\": {\n    \"id\": 99,\n    \"name\": \"test-user\",\n    \"source\": \"override\"\n  },\n  \"rows\": [\n    \"fixture-row\"\n  ]\n}\n\n$ POST \u002F_control\u002Foverride-wrong-key\n200 OK\n{\n  \"overrides\": [\n    \"get_current_user_copy\"\n  ]\n}\n\n$ GET \u002Fme\n401 Unauthorized\n{\n  \"detail\": \"Not authenticated\"\n}\n\n$ POST \u002F_control\u002Fclear\n200 OK\n{\n  \"overrides\": []\n}\n\n$ GET \u002Fme\n401 Unauthorized\n{\n  \"detail\": \"Not authenticated\"\n}\n",[603,1725,1723],{"__ignoreMap":835},[590,1727,1728,1731,1732,1735],{},[593,1729,1730],{},"Before:"," ",[603,1733,1734],{},"401 Not authenticated",". The real dependency runs and rejects the request.",[590,1737,1738,1731,1741,1743,1744,1747,1748,1751,1752,1754],{},[593,1739,1740],{},"After the correct override:",[603,1742,754],{},", with ",[603,1745,1746],{},"source: \"override\""," and ",[603,1749,1750],{},"rows: [\"fixture-row\"]",". Both nodes were replaced, including the ",[603,1753,622],{}," dependency — the override generator's value flowed into the handler exactly like the original's.",[590,1756,1757,1760,1761,1763,1764,1767,1768,1770,1771,1773],{},[593,1758,1759],{},"After the wrong-key override:"," back to ",[603,1762,1004],{},". This is the whole point. The dictionary contains one entry, ",[603,1765,1766],{},"get_current_user_copy",", which has the same signature and returns a plausible user. The application reports the override as installed. And ",[603,1769,649],{}," behaves as if you had written nothing at all. There is no warning, no log line, and no exception — just a test that fails with ",[603,1772,1004],{}," and sends you looking for an authentication bug that does not exist.",[590,1775,1776,1731,1779,1781],{},[593,1777,1778],{},"After clearing:",[603,1780,1004],{},", the original behaviour restored. That final line is what your fixture teardown must guarantee.",[640,1783,1785],{"id":1784},"the-fix-fixtures-that-cannot-leak","The Fix: Fixtures That Cannot Leak",[590,1787,1788],{},"Two rules make overrides safe. Register them in a fixture, and clear them in that fixture's teardown so they are removed even when the test raises.",[830,1790,1792],{"className":832,"code":1791,"language":834,"meta":835,"style":835},"# tests\u002Fconftest.py\nimport pytest\nfrom fastapi.testclient import TestClient\n\nfrom app.deps import get_current_user, get_db\nfrom app.main import app\n\n\n@pytest.fixture\ndef override():\n    \"\"\"Install overrides for one test and guarantee removal, even on failure.\"\"\"\n    def _install(**mapping):\n        app.dependency_overrides.update(mapping)\n    yield _install\n    app.dependency_overrides.clear()      # teardown runs even if the test raised\n\n\n@pytest.fixture\ndef client():\n    with TestClient(app) as c:\n        yield c\n\n\ndef test_me_returns_the_injected_user(client, override):\n    override(**{get_current_user: fake_user, get_db: fake_db})\n    body = client.get(\"\u002Fme\").json()\n    assert body[\"user\"][\"name\"] == \"test-user\"\n",[603,1793,1794,1799,1806,1818,1822,1834,1846,1850,1854,1859,1869,1874,1890,1895,1903,1911,1915,1919,1923,1932,1946,1953,1957,1961,1971,1981,1996],{"__ignoreMap":835},[839,1795,1796],{"class":746,"line":841},[839,1797,1798],{"class":1434},"# tests\u002Fconftest.py\n",[839,1800,1801,1803],{"class":746,"line":848},[839,1802,859],{"class":851},[839,1804,1805],{"class":855}," pytest\n",[839,1807,1808,1810,1813,1815],{"class":746,"line":865},[839,1809,852],{"class":851},[839,1811,1812],{"class":855}," fastapi.testclient ",[839,1814,859],{"class":851},[839,1816,1817],{"class":855}," TestClient\n",[839,1819,1820],{"class":746,"line":878},[839,1821,882],{"emptyLinePlaceholder":881},[839,1823,1824,1826,1829,1831],{"class":746,"line":885},[839,1825,852],{"class":851},[839,1827,1828],{"class":855}," app.deps ",[839,1830,859],{"class":851},[839,1832,1833],{"class":855}," get_current_user, get_db\n",[839,1835,1836,1838,1841,1843],{"class":746,"line":898},[839,1837,852],{"class":851},[839,1839,1840],{"class":855}," app.main ",[839,1842,859],{"class":851},[839,1844,1845],{"class":855}," app\n",[839,1847,1848],{"class":746,"line":903},[839,1849,882],{"emptyLinePlaceholder":881},[839,1851,1852],{"class":746,"line":915},[839,1853,882],{"emptyLinePlaceholder":881},[839,1855,1856],{"class":746,"line":920},[839,1857,1858],{"class":934},"@pytest.fixture\n",[839,1860,1861,1864,1867],{"class":746,"line":925},[839,1862,1863],{"class":851},"def",[839,1865,1866],{"class":934}," override",[839,1868,1521],{"class":855},[839,1870,1871],{"class":746,"line":966},[839,1872,1873],{"class":844},"    \"\"\"Install overrides for one test and guarantee removal, even on failure.\"\"\"\n",[839,1875,1876,1879,1882,1884,1887],{"class":746,"line":972},[839,1877,1878],{"class":851},"    def",[839,1880,1881],{"class":934}," _install",[839,1883,1226],{"class":855},[839,1885,1886],{"class":851},"**",[839,1888,1889],{"class":855},"mapping):\n",[839,1891,1892],{"class":746,"line":989},[839,1893,1894],{"class":855},"        app.dependency_overrides.update(mapping)\n",[839,1896,1897,1900],{"class":746,"line":1021},[839,1898,1899],{"class":851},"    yield",[839,1901,1902],{"class":855}," _install\n",[839,1904,1905,1908],{"class":746,"line":1062},[839,1906,1907],{"class":855},"    app.dependency_overrides.clear()      ",[839,1909,1910],{"class":1434},"# teardown runs even if the test raised\n",[839,1912,1913],{"class":746,"line":1067},[839,1914,882],{"emptyLinePlaceholder":881},[839,1916,1917],{"class":746,"line":1072},[839,1918,882],{"emptyLinePlaceholder":881},[839,1920,1921],{"class":746,"line":1095},[839,1922,1858],{"class":934},[839,1924,1925,1927,1930],{"class":746,"line":1127},[839,1926,1863],{"class":851},[839,1928,1929],{"class":934}," client",[839,1931,1521],{"class":855},[839,1933,1934,1937,1940,1943],{"class":746,"line":1135},[839,1935,1936],{"class":851},"    with",[839,1938,1939],{"class":855}," TestClient(app) ",[839,1941,1942],{"class":851},"as",[839,1944,1945],{"class":855}," c:\n",[839,1947,1948,1950],{"class":746,"line":1144},[839,1949,1138],{"class":851},[839,1951,1952],{"class":855}," c\n",[839,1954,1955],{"class":746,"line":1152},[839,1956,882],{"emptyLinePlaceholder":881},[839,1958,1959],{"class":746,"line":1169},[839,1960,882],{"emptyLinePlaceholder":881},[839,1962,1963,1965,1968],{"class":746,"line":1174},[839,1964,1863],{"class":851},[839,1966,1967],{"class":934}," test_me_returns_the_injected_user",[839,1969,1970],{"class":855},"(client, override):\n",[839,1972,1973,1976,1978],{"class":746,"line":1179},[839,1974,1975],{"class":855},"    override(",[839,1977,1886],{"class":851},[839,1979,1980],{"class":855},"{get_current_user: fake_user, get_db: fake_db})\n",[839,1982,1983,1986,1988,1991,1993],{"class":746,"line":1195},[839,1984,1985],{"class":855},"    body ",[839,1987,909],{"class":851},[839,1989,1990],{"class":855}," client.get(",[839,1992,1229],{"class":844},[839,1994,1995],{"class":855},").json()\n",[839,1997,1998,2001,2004,2006,2009,2011,2013,2016],{"class":746,"line":1210},[839,1999,2000],{"class":851},"    assert",[839,2002,2003],{"class":855}," body[",[839,2005,1254],{"class":844},[839,2007,2008],{"class":855},"][",[839,2010,1041],{"class":844},[839,2012,1161],{"class":855},[839,2014,2015],{"class":851},"==",[839,2017,2018],{"class":844}," \"test-user\"\n",[590,2020,2021,2024],{},[603,2022,2023],{},"clear()"," is a blunt instrument — it removes overrides another fixture installed too. If your suite has a base set of overrides that should always be present (a test database, a stubbed clock), snapshot and restore instead:",[830,2026,2028],{"className":832,"code":2027,"language":834,"meta":835,"style":835},"@pytest.fixture\ndef override():\n    original = dict(app.dependency_overrides)\n    yield app.dependency_overrides.update\n    app.dependency_overrides.clear()\n    app.dependency_overrides.update(original)   # restore the baseline, not empty\n",[603,2029,2030,2034,2042,2055,2062,2066],{"__ignoreMap":835},[839,2031,2032],{"class":746,"line":841},[839,2033,1858],{"class":934},[839,2035,2036,2038,2040],{"class":746,"line":848},[839,2037,1863],{"class":851},[839,2039,1866],{"class":934},[839,2041,1521],{"class":855},[839,2043,2044,2047,2049,2052],{"class":746,"line":865},[839,2045,2046],{"class":855},"    original ",[839,2048,909],{"class":851},[839,2050,2051],{"class":941}," dict",[839,2053,2054],{"class":855},"(app.dependency_overrides)\n",[839,2056,2057,2059],{"class":746,"line":878},[839,2058,1899],{"class":851},[839,2060,2061],{"class":855}," app.dependency_overrides.update\n",[839,2063,2064],{"class":746,"line":885},[839,2065,1616],{"class":855},[839,2067,2068,2071],{"class":746,"line":898},[839,2069,2070],{"class":855},"    app.dependency_overrides.update(original)   ",[839,2072,2073],{"class":1434},"# restore the baseline, not empty\n",[2075,2076,2078],"h3",{"id":2077},"import-the-exact-object-the-route-imports","Import the exact object the route imports",[590,2080,2081,2082,2085,2086,2089,2090,2093,2094,2097],{},"The wrong-key failure is almost always an import problem. The route module does ",[603,2083,2084],{},"from app.deps import get_db","; the test does ",[603,2087,2088],{},"from app.database import get_db",", where ",[603,2091,2092],{},"app.database"," re-exports it through a wrapper, or ",[603,2095,2096],{},"app.deps"," re-imports it under a shim. Both names resolve to something callable, and only one of them is the object the route holds a reference to.",[590,2099,2100],{},"A cheap assertion turns the silent failure into a loud one:",[830,2102,2104],{"className":832,"code":2103,"language":834,"meta":835,"style":835},"def test_override_key_is_real(client, override):\n    override(**{get_current_user: fake_user})\n    # Assert the behaviour changed, not that the key is in the dict.\n    assert client.get(\"\u002Fme\").status_code != 401, \"override key did not match the route's callable\"\n",[603,2105,2106,2115,2124,2129],{"__ignoreMap":835},[839,2107,2108,2110,2113],{"class":746,"line":841},[839,2109,1863],{"class":851},[839,2111,2112],{"class":934}," test_override_key_is_real",[839,2114,1970],{"class":855},[839,2116,2117,2119,2121],{"class":746,"line":848},[839,2118,1975],{"class":855},[839,2120,1886],{"class":851},[839,2122,2123],{"class":855},"{get_current_user: fake_user})\n",[839,2125,2126],{"class":746,"line":865},[839,2127,2128],{"class":1434},"    # Assert the behaviour changed, not that the key is in the dict.\n",[839,2130,2131,2133,2135,2137,2140,2142,2145,2147],{"class":746,"line":878},[839,2132,2000],{"class":851},[839,2134,1990],{"class":855},[839,2136,1229],{"class":844},[839,2138,2139],{"class":855},").status_code ",[839,2141,981],{"class":851},[839,2143,2144],{"class":941}," 401",[839,2146,1007],{"class":855},[839,2148,2149],{"class":844},"\"override key did not match the route's callable\"\n",[590,2151,2152,2153,2156,2157,2160],{},"In practice the simplest guard is the one above: assert on the ",[795,2154,2155],{},"behaviour change",", not on the dictionary. A test that only asserts ",[603,2158,2159],{},"get_current_user in app.dependency_overrides"," passes happily in the wrong-key case, as the transcript shows.",[640,2162,2164],{"id":2163},"overriding-a-yield-dependency","Overriding a yield Dependency",[590,2166,2167,2168,2172],{},"The transcript already proved this works, but the detail worth knowing is that the replacement is treated as an ordinary dependency: if it is a generator it joins the request's exit stack and gets the same LIFO teardown and the same exception delivery described in ",[634,2169,2171],{"href":2170},"\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fyield-dependencies-and-cleanup-order\u002F","yield dependencies and cleanup order",".",[590,2174,2175,2176,2179],{},"That matters when the thing you are testing ",[795,2177,2178],{},"is"," the teardown. A rollback-on-error test needs an override that actually yields:",[830,2181,2183],{"className":832,"code":2182,"language":834,"meta":835,"style":835},"async def recording_session():\n    session = FakeSession()\n    try:\n        yield session\n        session.events.append(\"commit\")\n    except Exception:\n        session.events.append(\"rollback\")\n        raise\n    finally:\n        session.events.append(\"close\")\n",[603,2184,2185,2196,2205,2211,2217,2227,2237,2246,2251,2257],{"__ignoreMap":835},[839,2186,2187,2189,2191,2194],{"class":746,"line":841},[839,2188,928],{"class":851},[839,2190,931],{"class":851},[839,2192,2193],{"class":934}," recording_session",[839,2195,1521],{"class":855},[839,2197,2198,2200,2202],{"class":746,"line":848},[839,2199,1098],{"class":855},[839,2201,909],{"class":851},[839,2203,2204],{"class":855}," FakeSession()\n",[839,2206,2207,2209],{"class":746,"line":865},[839,2208,1130],{"class":851},[839,2210,963],{"class":855},[839,2212,2213,2215],{"class":746,"line":878},[839,2214,1138],{"class":851},[839,2216,1141],{"class":855},[839,2218,2219,2222,2225],{"class":746,"line":885},[839,2220,2221],{"class":855},"        session.events.append(",[839,2223,2224],{"class":844},"\"commit\"",[839,2226,1018],{"class":855},[839,2228,2229,2232,2235],{"class":746,"line":898},[839,2230,2231],{"class":851},"    except",[839,2233,2234],{"class":941}," Exception",[839,2236,963],{"class":855},[839,2238,2239,2241,2244],{"class":746,"line":903},[839,2240,2221],{"class":855},[839,2242,2243],{"class":844},"\"rollback\"",[839,2245,1018],{"class":855},[839,2247,2248],{"class":746,"line":915},[839,2249,2250],{"class":851},"        raise\n",[839,2252,2253,2255],{"class":746,"line":920},[839,2254,1147],{"class":851},[839,2256,963],{"class":855},[839,2258,2259,2261,2264],{"class":746,"line":925},[839,2260,2221],{"class":855},[839,2262,2263],{"class":844},"\"close\"",[839,2265,1018],{"class":855},[590,2267,2268,2269,2272,2273,2276],{},"Replacing that with a plain ",[603,2270,2271],{},"async def"," that returns a ",[603,2274,2275],{},"FakeSession"," would make the test pass while exercising none of the lifecycle.",[640,2278,2280],{"id":2279},"scoping-overrides-are-application-wide","Scoping: Overrides Are Application-Wide",[590,2282,2283,2284,1747,2287,2290,2291,2293],{},"There is no per-route override API. If ",[603,2285,2286],{},"\u002Forders",[603,2288,2289],{},"\u002Fadmin\u002Forders"," both depend on ",[603,2292,653],{}," and you want a different fake for each, you have two options.",[590,2295,2296,2299,2300,1747,2303,2305],{},[593,2297,2298],{},"Distinct providers."," Declare ",[603,2301,2302],{},"get_admin_user",[603,2304,653],{}," as separate callables. This is usually better design anyway — the two routes genuinely have different authorization requirements — and it makes the override targetable.",[590,2307,2308,2311,2312,1007,2316,2319],{},[593,2309,2310],{},"A fresh app per test."," With the ",[634,2313,2315],{"href":2314},"\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Ffastapi-app-factory-pattern-for-testing-and-deployment\u002F","application factory pattern",[603,2317,2318],{},"create_app()"," returns a new instance with an empty overrides dict, so nothing can leak between tests at all. The cost is app construction time on every test, which is why most suites use a session-scoped app plus disciplined teardown, and reserve per-test apps for tests that change configuration or the middleware stack.",[640,2321,2323],{"id":2322},"trade-offs-and-when-not-to","Trade-Offs and When Not To",[590,2325,2326,2329,2330,2333,2334,2336],{},[593,2327,2328],{},"An override is a mock with better ergonomics, and it has a mock's failure mode."," If ",[603,2331,2332],{},"fake_user"," returns a shape the real ",[603,2335,653],{}," never produces, every test passes and production breaks. Type the fake with the same return annotation and, where the shape matters, build it from the same Pydantic model.",[590,2338,2339,2342,2343,2172],{},[593,2340,2341],{},"Over-overriding hollows out the test."," Replacing the session, the user, the settings and the external client leaves a test that asserts your fakes agree with each other. Keep at least one integration-level test that runs the real graph against a real (test) database — the approach in ",[634,2344,2346],{"href":2345},"\u002Fasync-background-tasks-observability\u002Fasync-database-sessions\u002Ftesting-with-async-database-fixtures\u002F","testing with async database fixtures",[590,2348,2349,2352,2353,2357],{},[593,2350,2351],{},"Overrides do not touch middleware."," Anything registered as middleware runs unchanged in tests, which is exactly the asymmetry discussed in ",[634,2354,2356],{"href":2355},"\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fmiddleware-vs-dependencies-when-to-use-which\u002F","middleware vs dependencies",". If a behaviour must be stubbable per test, a dependency is the better home for it.",[590,2359,2360,2363,2364,2367,2368,2371,2372,2172],{},[593,2361,2362],{},"Async client, same rules."," Whether you drive the app with ",[603,2365,2366],{},"TestClient"," or ",[603,2369,2370],{},"httpx.AsyncClient"," makes no difference to overrides; both go through the same ASGI app and read the same dictionary. The choice between them is covered in ",[634,2373,2375],{"href":2374},"\u002Fasync-background-tasks-observability\u002Ftesting-fastapi-applications\u002Ftestclient-vs-httpx-asyncclient\u002F","TestClient vs httpx AsyncClient",[640,2377,2379],{"id":2378},"faq","FAQ",[590,2381,2382,2385],{},[593,2383,2384],{},"Why does my dependency override have no effect?","\nThe override dictionary is keyed by the exact callable object the route declares. If the test imports the provider from a different module path, wraps it, or the route depends on a factory-produced closure, the key never matches and the real dependency runs with no warning at all.",[590,2387,2388,2391],{},[593,2389,2390],{},"Do I have to clear dependency_overrides between tests?","\nYes. The dictionary lives on the application object, which is usually module-scoped or session-scoped in a test suite, so an override set in one test leaks into every test that runs after it. Clear it in fixture teardown, never at the end of the test body.",[590,2393,2394,2397,2398,2400],{},[593,2395,2396],{},"Can I override a dependency that uses yield?","\nYes, and the replacement should also use ",[603,2399,622],{}," if you want teardown to run. FastAPI treats the override exactly like a normal dependency, so a generator override gets the same setup, LIFO teardown and exception delivery as the original.",[590,2402,2403,2406],{},[593,2404,2405],{},"Should I override the dependency or patch the function it calls?","\nOverride the dependency. It is the documented seam, it is type-checked, and it replaces the node in the resolution graph rather than reaching inside an implementation. Reserve monkeypatching for third-party code that is not exposed as a dependency.",[590,2408,2409,2412,2413,2416],{},[593,2410,2411],{},"How do I override a dependency for only one route?","\nYou cannot scope an override to a route through ",[603,2414,2415],{},"dependency_overrides",", which is application-wide. Either give the route its own distinct provider callable, or build a fresh app instance per test with an application factory.",[590,2418,2419,2422,2423,2426],{},[593,2420,2421],{},"Does an override still get its sub-dependencies injected?","\nYes. The replacement is resolved like any other dependency, so if it declares ",[603,2424,2425],{},"Depends(...)"," parameters they are satisfied normally — including from the per-request cache. A fake that itself needs settings can simply ask for them.",[640,2428,2430],{"id":2429},"related-reading","Related Reading",[597,2432,2433,2441,2450,2458,2465],{},[600,2434,2435,1731,2438,2172],{},[593,2436,2437],{},"Up to the section:",[634,2439,2440],{"href":636},"Dependency Injection Strategies",[600,2442,2443,1731,2446,2449],{},[593,2444,2445],{},"Why the wrong key misses:",[634,2447,2448],{"href":788},"Dependency Caching and use_cache"," explains the identity rule this shares.",[600,2451,2452,1731,2455,2172],{},[593,2453,2454],{},"What a yield override must reproduce:",[634,2456,2457],{"href":2170},"Yield Dependencies and Cleanup Order",[600,2459,2460,1731,2463,2172],{},[593,2461,2462],{},"A fresh app per test:",[634,2464,401],{"href":2314},[600,2466,2467,1731,2470,2172],{},[593,2468,2469],{},"Driving the app:",[634,2471,2375],{"href":2374},[2473,2474,2475],"style",{},"html pre.shiki code .sYEJz, html code.shiki .sYEJz{--shiki-default:#032563}html pre.shiki code .sTJeM, html code.shiki .sTJeM{--shiki-default:#A0111F}html pre.shiki code .sigWx, html code.shiki .sigWx{--shiki-default:#0E1116}html pre.shiki code .s3dhs, html code.shiki .s3dhs{--shiki-default:#622CBC}html pre.shiki code .sacAq, html code.shiki .sacAq{--shiki-default:#023B95}html pre.shiki code .sV4o_, html code.shiki .sV4o_{--shiki-default:#702C00}html pre.shiki code .sFeEa, html code.shiki .sFeEa{--shiki-default:#66707B}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":835,"searchDepth":848,"depth":848,"links":2477},[2478,2479,2480,2481,2484,2485,2486,2487,2488],{"id":642,"depth":848,"text":643},{"id":772,"depth":848,"text":773},{"id":805,"depth":848,"text":806},{"id":1784,"depth":848,"text":1785,"children":2482},[2483],{"id":2077,"depth":865,"text":2078},{"id":2163,"depth":848,"text":2164},{"id":2279,"depth":848,"text":2280},{"id":2322,"depth":848,"text":2323},{"id":2378,"depth":848,"text":2379},{"id":2429,"depth":848,"text":2430},"2026-07-20","Use app.dependency_overrides safely: scoping and cleanup between tests, replacing a yield dependency, and why the wrong callable key silently does nothing.","md",[2493,2495,2497,2499,2501],{"q":2384,"a":2494},"The override dictionary is keyed by the exact callable object the route declares. If the test imports the provider from a different module path, wraps it, or the route depends on a factory-produced closure, the key never matches and the real dependency runs with no warning at all.",{"q":2390,"a":2496},"Yes. The dictionary lives on the application object, which is usually module-scoped or session-scoped in a test suite, so an override set in one test leaks into every test that runs after it. Clear it in fixture teardown, never at the end of the test body.",{"q":2396,"a":2498},"Yes, and the replacement should also use yield if you want teardown to run. FastAPI treats the override exactly like a normal dependency, so a generator override gets the same setup, LIFO teardown and exception delivery as the original.",{"q":2405,"a":2500},"Override the dependency. It is the documented seam, it is type-checked, and it replaces the node in the resolution graph rather than reaching inside an implementation. Reserve monkeypatching for third-party code that is not exposed as a dependency.",{"q":2411,"a":2502},"You cannot scope an override to a route through dependency_overrides, which is application-wide. Either give the route its own distinct provider callable, or build a fresh app instance per test with an application factory.",null,{"slug":2505,"breadcrumb":2506},"overriding-dependencies-in-tests",[2507,2510,2513,2514],{"label":2508,"path":2509},"Home","\u002F",{"label":2511,"path":2512},"Core Architecture & Routing Patterns","\u002Fcore-architecture-routing-patterns\u002F",{"label":2440,"path":636},{"label":2515,"path":2516},"Overriding Dependencies in Tests","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Foverriding-dependencies-in-tests\u002F",{"title":461,"description":2490},"article","zM-mSmuwnc3js92igCwQijcjsJ_snfcuzJexBwSdeXU",[2503,2503],1784588202739]