dapr-ext-fastapi-dev 1.15.0.dev43__tar.gz → 1.16.0.dev48__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (16) hide show
  1. {dapr-ext-fastapi-dev-1.15.0.dev43 → dapr_ext_fastapi_dev-1.16.0.dev48}/PKG-INFO +8 -4
  2. {dapr-ext-fastapi-dev-1.15.0.dev43 → dapr_ext_fastapi_dev-1.16.0.dev48}/dapr/ext/fastapi/__init__.py +0 -1
  3. {dapr-ext-fastapi-dev-1.15.0.dev43 → dapr_ext_fastapi_dev-1.16.0.dev48}/dapr/ext/fastapi/actor.py +2 -2
  4. {dapr-ext-fastapi-dev-1.15.0.dev43 → dapr_ext_fastapi_dev-1.16.0.dev48}/dapr/ext/fastapi/app.py +1 -0
  5. {dapr-ext-fastapi-dev-1.15.0.dev43 → dapr_ext_fastapi_dev-1.16.0.dev48}/dapr/ext/fastapi/version.py +1 -1
  6. {dapr-ext-fastapi-dev-1.15.0.dev43 → dapr_ext_fastapi_dev-1.16.0.dev48}/dapr_ext_fastapi_dev.egg-info/PKG-INFO +8 -4
  7. {dapr-ext-fastapi-dev-1.15.0.dev43 → dapr_ext_fastapi_dev-1.16.0.dev48}/dapr_ext_fastapi_dev.egg-info/SOURCES.txt +3 -1
  8. {dapr-ext-fastapi-dev-1.15.0.dev43 → dapr_ext_fastapi_dev-1.16.0.dev48}/dapr_ext_fastapi_dev.egg-info/requires.txt +1 -1
  9. {dapr-ext-fastapi-dev-1.15.0.dev43 → dapr_ext_fastapi_dev-1.16.0.dev48}/setup.cfg +1 -1
  10. dapr_ext_fastapi_dev-1.16.0.dev48/tests/test_app.py +156 -0
  11. dapr_ext_fastapi_dev-1.16.0.dev48/tests/test_dapractor.py +88 -0
  12. {dapr-ext-fastapi-dev-1.15.0.dev43 → dapr_ext_fastapi_dev-1.16.0.dev48}/LICENSE +0 -0
  13. {dapr-ext-fastapi-dev-1.15.0.dev43 → dapr_ext_fastapi_dev-1.16.0.dev48}/README.rst +0 -0
  14. {dapr-ext-fastapi-dev-1.15.0.dev43 → dapr_ext_fastapi_dev-1.16.0.dev48}/dapr_ext_fastapi_dev.egg-info/dependency_links.txt +0 -0
  15. {dapr-ext-fastapi-dev-1.15.0.dev43 → dapr_ext_fastapi_dev-1.16.0.dev48}/dapr_ext_fastapi_dev.egg-info/top_level.txt +0 -0
  16. {dapr-ext-fastapi-dev-1.15.0.dev43 → dapr_ext_fastapi_dev-1.16.0.dev48}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: dapr-ext-fastapi-dev
3
- Version: 1.15.0.dev43
3
+ Version: 1.16.0.dev48
4
4
  Summary: The developmental release for Dapr FastAPI extension.
5
5
  Home-page: https://dapr.io/
6
6
  Author: Dapr Authors
@@ -8,7 +8,6 @@ Author-email: daprweb@microsoft.com
8
8
  License: Apache
9
9
  Project-URL: Documentation, https://github.com/dapr/docs
10
10
  Project-URL: Source, https://github.com/dapr/python-sdk
11
- Platform: UNKNOWN
12
11
  Classifier: Development Status :: 5 - Production/Stable
13
12
  Classifier: Intended Audience :: Developers
14
13
  Classifier: License :: OSI Approved :: Apache Software License
@@ -21,6 +20,11 @@ Classifier: Programming Language :: Python :: 3.12
21
20
  Classifier: Programming Language :: Python :: 3.13
22
21
  Requires-Python: >=3.9
23
22
  License-File: LICENSE
23
+ Requires-Dist: dapr>=1.16.0.dev
24
+ Requires-Dist: uvicorn>=0.11.6
25
+ Requires-Dist: fastapi>=0.60.1
26
+ Dynamic: description
27
+ Dynamic: license-file
28
+ Dynamic: summary
24
29
 
25
30
  This is the developmental release for Dapr FastAPI extension.
26
-
@@ -16,5 +16,4 @@ limitations under the License.
16
16
  from .actor import DaprActor
17
17
  from .app import DaprApp
18
18
 
19
-
20
19
  __all__ = ['DaprActor', 'DaprApp']
@@ -13,12 +13,12 @@ See the License for the specific language governing permissions and
13
13
  limitations under the License.
14
14
  """
15
15
 
16
- from typing import Any, Optional, Type, List
16
+ from typing import Any, List, Optional, Type
17
17
 
18
18
  from dapr.actor import Actor, ActorRuntime
19
19
  from dapr.clients.exceptions import ERROR_CODE_UNKNOWN, DaprInternalError
20
20
  from dapr.serializers import DefaultJSONSerializer
21
- from fastapi import FastAPI, APIRouter, Request, Response, status # type: ignore
21
+ from fastapi import APIRouter, FastAPI, Request, Response, status # type: ignore
22
22
  from fastapi.logger import logger
23
23
  from fastapi.responses import JSONResponse
24
24
 
@@ -13,6 +13,7 @@ limitations under the License.
13
13
  """
14
14
 
15
15
  from typing import Dict, List, Optional
16
+
16
17
  from fastapi import FastAPI # type: ignore
17
18
 
18
19
 
@@ -13,4 +13,4 @@ See the License for the specific language governing permissions and
13
13
  limitations under the License.
14
14
  """
15
15
 
16
- __version__ = '1.15.0.dev'
16
+ __version__ = '1.16.0.dev'
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: dapr-ext-fastapi-dev
3
- Version: 1.15.0.dev43
3
+ Version: 1.16.0.dev48
4
4
  Summary: The developmental release for Dapr FastAPI extension.
5
5
  Home-page: https://dapr.io/
6
6
  Author: Dapr Authors
@@ -8,7 +8,6 @@ Author-email: daprweb@microsoft.com
8
8
  License: Apache
9
9
  Project-URL: Documentation, https://github.com/dapr/docs
10
10
  Project-URL: Source, https://github.com/dapr/python-sdk
11
- Platform: UNKNOWN
12
11
  Classifier: Development Status :: 5 - Production/Stable
13
12
  Classifier: Intended Audience :: Developers
14
13
  Classifier: License :: OSI Approved :: Apache Software License
@@ -21,6 +20,11 @@ Classifier: Programming Language :: Python :: 3.12
21
20
  Classifier: Programming Language :: Python :: 3.13
22
21
  Requires-Python: >=3.9
23
22
  License-File: LICENSE
23
+ Requires-Dist: dapr>=1.16.0.dev
24
+ Requires-Dist: uvicorn>=0.11.6
25
+ Requires-Dist: fastapi>=0.60.1
26
+ Dynamic: description
27
+ Dynamic: license-file
28
+ Dynamic: summary
24
29
 
25
30
  This is the developmental release for Dapr FastAPI extension.
26
-
@@ -10,4 +10,6 @@ dapr_ext_fastapi_dev.egg-info/PKG-INFO
10
10
  dapr_ext_fastapi_dev.egg-info/SOURCES.txt
11
11
  dapr_ext_fastapi_dev.egg-info/dependency_links.txt
12
12
  dapr_ext_fastapi_dev.egg-info/requires.txt
13
- dapr_ext_fastapi_dev.egg-info/top_level.txt
13
+ dapr_ext_fastapi_dev.egg-info/top_level.txt
14
+ tests/test_app.py
15
+ tests/test_dapractor.py
@@ -1,3 +1,3 @@
1
- dapr-dev>=1.15.0.dev
1
+ dapr>=1.16.0.dev
2
2
  uvicorn>=0.11.6
3
3
  fastapi>=0.60.1
@@ -24,7 +24,7 @@ python_requires = >=3.9
24
24
  packages = find_namespace:
25
25
  include_package_data = True
26
26
  install_requires =
27
- dapr-dev >= 1.15.0.dev
27
+ dapr >= 1.16.0.dev
28
28
  uvicorn >= 0.11.6
29
29
  fastapi >= 0.60.1
30
30
 
@@ -0,0 +1,156 @@
1
+ import unittest
2
+
3
+ from dapr.ext.fastapi import DaprApp
4
+ from fastapi import FastAPI
5
+ from fastapi.testclient import TestClient
6
+ from pydantic import BaseModel
7
+
8
+
9
+ class Message(BaseModel):
10
+ body: str
11
+
12
+
13
+ class DaprAppTest(unittest.TestCase):
14
+ def setUp(self):
15
+ self.app = FastAPI()
16
+ self.dapr_app = DaprApp(self.app)
17
+ self.client = TestClient(self.app)
18
+
19
+ def test_subscribe_subscription_registered(self):
20
+ @self.dapr_app.subscribe(pubsub='pubsub', topic='test')
21
+ def event_handler(event_data: Message):
22
+ return 'default route'
23
+
24
+ self.assertEqual(len(self.dapr_app._subscriptions), 1)
25
+
26
+ self.assertIn('/dapr/subscribe', [route.path for route in self.app.router.routes])
27
+ self.assertIn('/events/pubsub/test', [route.path for route in self.app.router.routes])
28
+
29
+ response = self.client.get('/dapr/subscribe')
30
+ self.assertEqual(
31
+ [
32
+ {
33
+ 'pubsubname': 'pubsub',
34
+ 'topic': 'test',
35
+ 'route': '/events/pubsub/test',
36
+ 'metadata': {},
37
+ }
38
+ ],
39
+ response.json(),
40
+ )
41
+
42
+ response = self.client.post('/events/pubsub/test', json={'body': 'new message'})
43
+ self.assertEqual(response.status_code, 200)
44
+ self.assertEqual(response.text, '"default route"')
45
+
46
+ def test_subscribe_with_route_subscription_registered_with_custom_route(self):
47
+ @self.dapr_app.subscribe(pubsub='pubsub', topic='test', route='/do-something')
48
+ def event_handler(event_data: Message):
49
+ return 'custom route'
50
+
51
+ self.assertEqual(len(self.dapr_app._subscriptions), 1)
52
+
53
+ self.assertIn('/dapr/subscribe', [route.path for route in self.app.router.routes])
54
+ self.assertIn('/do-something', [route.path for route in self.app.router.routes])
55
+
56
+ response = self.client.get('/dapr/subscribe')
57
+ self.assertEqual(
58
+ [{'pubsubname': 'pubsub', 'topic': 'test', 'route': '/do-something', 'metadata': {}}],
59
+ response.json(),
60
+ )
61
+
62
+ response = self.client.post('/do-something', json={'body': 'new message'})
63
+ self.assertEqual(response.status_code, 200)
64
+ self.assertEqual(response.text, '"custom route"')
65
+
66
+ def test_subscribe_metadata(self):
67
+ handler_metadata = {'rawPayload': 'true'}
68
+
69
+ @self.dapr_app.subscribe(pubsub='pubsub', topic='test', metadata=handler_metadata)
70
+ def event_handler(event_data: Message):
71
+ return 'custom metadata'
72
+
73
+ self.assertEqual((self.dapr_app._subscriptions[0]['metadata']['rawPayload']), 'true')
74
+
75
+ response = self.client.get('/dapr/subscribe')
76
+ self.assertEqual(
77
+ [
78
+ {
79
+ 'pubsubname': 'pubsub',
80
+ 'topic': 'test',
81
+ 'route': '/events/pubsub/test',
82
+ 'metadata': {'rawPayload': 'true'},
83
+ }
84
+ ],
85
+ response.json(),
86
+ )
87
+
88
+ response = self.client.post('/events/pubsub/test', json={'body': 'new message'})
89
+ self.assertEqual(response.status_code, 200)
90
+ self.assertEqual(response.text, '"custom metadata"')
91
+
92
+ def test_router_tag(self):
93
+ app1 = FastAPI()
94
+ app2 = FastAPI()
95
+ app3 = FastAPI()
96
+ DaprApp(app_instance=app1, router_tags=['MyTag', 'PubSub']).subscribe(
97
+ pubsub='mypubsub', topic='test'
98
+ )
99
+ DaprApp(app_instance=app2).subscribe(pubsub='mypubsub', topic='test')
100
+ DaprApp(app_instance=app3, router_tags=None).subscribe(pubsub='mypubsub', topic='test')
101
+
102
+ PATHS_WITH_EXPECTED_TAGS = ['/dapr/subscribe', '/events/mypubsub/test']
103
+
104
+ foundTags = False
105
+ for route in app1.router.routes:
106
+ if hasattr(route, 'tags'):
107
+ self.assertIn(route.path, PATHS_WITH_EXPECTED_TAGS)
108
+ self.assertEqual(['MyTag', 'PubSub'], route.tags)
109
+ foundTags = True
110
+ if not foundTags:
111
+ self.fail('No tags found')
112
+
113
+ foundTags = False
114
+ for route in app2.router.routes:
115
+ if hasattr(route, 'tags'):
116
+ self.assertIn(route.path, PATHS_WITH_EXPECTED_TAGS)
117
+ self.assertEqual(['PubSub'], route.tags)
118
+ foundTags = True
119
+ if not foundTags:
120
+ self.fail('No tags found')
121
+
122
+ for route in app3.router.routes:
123
+ if hasattr(route, 'tags'):
124
+ if len(route.tags) > 0:
125
+ self.fail('Found tags on route that should not have any')
126
+
127
+ def test_subscribe_dead_letter(self):
128
+ dead_letter_topic = 'dead-test'
129
+
130
+ @self.dapr_app.subscribe(pubsub='pubsub', topic='test', dead_letter_topic=dead_letter_topic)
131
+ def event_handler(event_data: Message):
132
+ return 'dead letter test'
133
+
134
+ self.assertEqual((self.dapr_app._subscriptions[0]['deadLetterTopic']), dead_letter_topic)
135
+
136
+ response = self.client.get('/dapr/subscribe')
137
+ self.assertEqual(
138
+ [
139
+ {
140
+ 'pubsubname': 'pubsub',
141
+ 'topic': 'test',
142
+ 'route': '/events/pubsub/test',
143
+ 'metadata': {},
144
+ 'deadLetterTopic': dead_letter_topic,
145
+ }
146
+ ],
147
+ response.json(),
148
+ )
149
+
150
+ response = self.client.post('/events/pubsub/test', json={'body': 'new message'})
151
+ self.assertEqual(response.status_code, 200)
152
+ self.assertEqual(response.text, '"dead letter test"')
153
+
154
+
155
+ if __name__ == '__main__':
156
+ unittest.main()
@@ -0,0 +1,88 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ Copyright 2023 The Dapr Authors
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
14
+ """
15
+
16
+ import json
17
+ import unittest
18
+
19
+ from dapr.ext.fastapi.actor import DaprActor, _wrap_response
20
+ from fastapi import FastAPI
21
+
22
+
23
+ class DaprActorTest(unittest.TestCase):
24
+ def test_wrap_response_str(self):
25
+ r = _wrap_response(200, 'fake_message')
26
+ self.assertEqual({'message': 'fake_message'}, json.loads(r.body))
27
+ self.assertEqual(200, r.status_code)
28
+
29
+ def test_wrap_response_str_err(self):
30
+ r = _wrap_response(400, 'fake_message', 'ERR_FAKE')
31
+ self.assertEqual({'message': 'fake_message', 'errorCode': 'ERR_FAKE'}, json.loads(r.body))
32
+ self.assertEqual(400, r.status_code)
33
+
34
+ def test_wrap_response_bytes_text(self):
35
+ r = _wrap_response(200, b'fake_bytes_message', content_type='text/plain')
36
+ self.assertEqual(b'fake_bytes_message', r.body)
37
+ self.assertEqual(200, r.status_code)
38
+ self.assertEqual('text/plain', r.media_type)
39
+
40
+ def test_wrap_response_obj(self):
41
+ fake_data = {'message': 'ok'}
42
+ r = _wrap_response(200, fake_data)
43
+ self.assertEqual(fake_data, json.loads(r.body))
44
+ self.assertEqual(200, r.status_code)
45
+
46
+ def test_router_tag(self):
47
+ app1 = FastAPI()
48
+ app2 = FastAPI()
49
+ app3 = FastAPI()
50
+ DaprActor(app=app1, router_tags=['MyTag', 'Actor'])
51
+ DaprActor(app=app2)
52
+ DaprActor(app=app3, router_tags=None)
53
+
54
+ PATHS_WITH_EXPECTED_TAGS = [
55
+ '/healthz',
56
+ '/dapr/config',
57
+ '/actors/{actor_type_name}/{actor_id}',
58
+ '/actors/{actor_type_name}/{actor_id}/method/{method_name}',
59
+ '/actors/{actor_type_name}/{actor_id}/method/timer/{timer_name}',
60
+ '/actors/{actor_type_name}/{actor_id}/method/remind/{reminder_name}',
61
+ ]
62
+
63
+ foundTags = False
64
+ for route in app1.router.routes:
65
+ if hasattr(route, 'tags'):
66
+ self.assertIn(route.path, PATHS_WITH_EXPECTED_TAGS)
67
+ self.assertEqual(['MyTag', 'Actor'], route.tags)
68
+ foundTags = True
69
+ if not foundTags:
70
+ self.fail('No tags found')
71
+
72
+ foundTags = False
73
+ for route in app2.router.routes:
74
+ if hasattr(route, 'tags'):
75
+ self.assertIn(route.path, PATHS_WITH_EXPECTED_TAGS)
76
+ self.assertEqual(['Actor'], route.tags)
77
+ foundTags = True
78
+ if not foundTags:
79
+ self.fail('No tags found')
80
+
81
+ for route in app3.router.routes:
82
+ if hasattr(route, 'tags'):
83
+ if len(route.tags) > 0:
84
+ self.fail('Found tags on route that should not have any')
85
+
86
+
87
+ if __name__ == '__main__':
88
+ unittest.main()