diff --git a/tests/ext/fastapi/test_dapractor.py b/tests/ext/fastapi/test_dapractor.py index ee863d726..f3e2f82ca 100644 --- a/tests/ext/fastapi/test_dapractor.py +++ b/tests/ext/fastapi/test_dapractor.py @@ -20,6 +20,31 @@ from dapr.ext.fastapi.actor import DaprActor, _wrap_response +EXPECTED_ACTOR_PATHS = { + '/healthz', + '/dapr/config', + '/actors/{actor_type_name}/{actor_id}', + '/actors/{actor_type_name}/{actor_id}/method/{method_name}', + '/actors/{actor_type_name}/{actor_id}/method/timer/{timer_name}', + '/actors/{actor_type_name}/{actor_id}/method/remind/{reminder_name}', +} + + +def _operation_tags(app: FastAPI) -> list[tuple[str, list[str] | None]]: + """Returns the ``(path, tags)`` pair of every operation in the app's OpenAPI schema. + + The schema is read instead of ``app.router.routes`` because FastAPI 0.137+ stores + routes registered via ``include_router`` in a nested tree rather than a flat list, so + the actor routes no longer surface as top-level ``APIRoute`` objects. The OpenAPI + schema is the public, stable surface that ``router_tags`` is meant to drive. + """ + schema = app.openapi() + return [ + (path, operation.get('tags')) + for path, operations in schema['paths'].items() + for operation in operations.values() + ] + class DaprActorTest(unittest.TestCase): def test_wrap_response_str(self): @@ -52,37 +77,20 @@ def test_router_tag(self): DaprActor(app=app2) DaprActor(app=app3, router_tags=None) - PATHS_WITH_EXPECTED_TAGS = [ - '/healthz', - '/dapr/config', - '/actors/{actor_type_name}/{actor_id}', - '/actors/{actor_type_name}/{actor_id}/method/{method_name}', - '/actors/{actor_type_name}/{actor_id}/method/timer/{timer_name}', - '/actors/{actor_type_name}/{actor_id}/method/remind/{reminder_name}', - ] - - foundTags = False - for route in app1.router.routes: - if hasattr(route, 'tags'): - self.assertIn(route.path, PATHS_WITH_EXPECTED_TAGS) - self.assertEqual(['MyTag', 'Actor'], route.tags) - foundTags = True - if not foundTags: - self.fail('No tags found') - - foundTags = False - for route in app2.router.routes: - if hasattr(route, 'tags'): - self.assertIn(route.path, PATHS_WITH_EXPECTED_TAGS) - self.assertEqual(['Actor'], route.tags) - foundTags = True - if not foundTags: - self.fail('No tags found') - - for route in app3.router.routes: - if hasattr(route, 'tags'): - if len(route.tags) > 0: - self.fail('Found tags on route that should not have any') + custom_tag_operations = _operation_tags(app1) + self.assertEqual(EXPECTED_ACTOR_PATHS, {path for path, _tags in custom_tag_operations}) + for _path, tags in custom_tag_operations: + self.assertEqual(['MyTag', 'Actor'], tags) + + default_tag_operations = _operation_tags(app2) + self.assertEqual(EXPECTED_ACTOR_PATHS, {path for path, _tags in default_tag_operations}) + for _path, tags in default_tag_operations: + self.assertEqual(['Actor'], tags) + + untagged_operations = _operation_tags(app3) + self.assertEqual(EXPECTED_ACTOR_PATHS, {path for path, _tags in untagged_operations}) + for _path, tags in untagged_operations: + self.assertFalse(tags) if __name__ == '__main__': diff --git a/uv.lock b/uv.lock index 9f7a907b7..76475cabb 100644 --- a/uv.lock +++ b/uv.lock @@ -850,7 +850,7 @@ wheels = [ [[package]] name = "fastapi" -version = "0.135.1" +version = "0.138.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-doc" }, @@ -859,9 +859,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e7/7b/f8e0211e9380f7195ba3f3d40c292594fd81ba8ec4629e3854c353aaca45/fastapi-0.135.1.tar.gz", hash = "sha256:d04115b508d936d254cea545b7312ecaa58a7b3a0f84952535b4c9afae7668cd", size = 394962, upload-time = "2026-03-01T18:18:29.369Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/58/ff455d9fe47c60abadb34b9e05a304b1f05f5ab8000ac01565156b6f5e43/fastapi-0.138.0.tar.gz", hash = "sha256:d445a4877636ad191e7053e08c9bf98cb921a6756776848400bb773d1740c061", size = 419240, upload-time = "2026-06-20T01:18:05.259Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e4/72/42e900510195b23a56bde950d26a51f8b723846bfcaa0286e90287f0422b/fastapi-0.135.1-py3-none-any.whl", hash = "sha256:46e2fc5745924b7c840f71ddd277382af29ce1cdb7d5eab5bf697e3fb9999c9e", size = 116999, upload-time = "2026-03-01T18:18:30.831Z" }, + { url = "https://files.pythonhosted.org/packages/6c/ff/8496d9847a5fedae775eb49460722d3efaa80487854273e9647ae876218c/fastapi-0.138.0-py3-none-any.whl", hash = "sha256:b6f54fd1bd72c80b0f899f172c61a600f6f7af9b43d4d772a018f35624048cb0", size = 126779, upload-time = "2026-06-20T01:18:03.483Z" }, ] [[package]]