From 9fa776095676d5a6292515ed454d4cceabf3df7c Mon Sep 17 00:00:00 2001 From: Marc Duiker Date: Thu, 2 May 2024 18:02:15 +0200 Subject: [PATCH 1/7] Fix Holopin alias (#706) Signed-off-by: Marc Duiker Signed-off-by: Kapil Sachdeva --- .github/holopin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/holopin.yml b/.github/holopin.yml index 99658a28..cffeb5ec 100644 --- a/.github/holopin.yml +++ b/.github/holopin.yml @@ -2,4 +2,4 @@ organization: dapr defaultSticker: clrqfdv4x24910fl5n4iwu5oa stickers: - id: clrqfdv4x24910fl5n4iwu5oa - alias: { id: clrqfdv4x24910fl5n4iwu5oa, alias: sdk-badge } + alias: sdk-badge From b8e17e58e316e79fd820e99072e2a0ad92c0948d Mon Sep 17 00:00:00 2001 From: Kapil Sachdeva Date: Tue, 14 May 2024 17:06:45 +0000 Subject: [PATCH 2/7] Add the support to pass user supplied actor_factory callable in ActorRuntime & ext/fastapi,flask Signed-off-by: Kapil Sachdeva --- dapr/actor/runtime/runtime.py | 5 +- .../dapr/ext/fastapi/actor.py | 6 +- ext/flask_dapr/flask_dapr/actor.py | 4 +- tests/actor/test_actor_factory.py | 88 +++++++++++++++++++ 4 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 tests/actor/test_actor_factory.py diff --git a/dapr/actor/runtime/runtime.py b/dapr/actor/runtime/runtime.py index 7a2bf7eb..b820c536 100644 --- a/dapr/actor/runtime/runtime.py +++ b/dapr/actor/runtime/runtime.py @@ -15,7 +15,7 @@ import asyncio -from typing import Dict, List, Optional, Type +from typing import Dict, List, Optional, Type, Callable from dapr.actor.id import ActorId from dapr.actor.runtime.actor import Actor @@ -47,6 +47,7 @@ async def register_actor( message_serializer: Serializer = DefaultJSONSerializer(), state_serializer: Serializer = DefaultJSONSerializer(), http_timeout_seconds: int = settings.DAPR_HTTP_TIMEOUT_SECONDS, + actor_factory: Optional[Callable[['ActorRuntimeContext', ActorId], 'Actor']] = None, ) -> None: """Registers an :class:`Actor` object with the runtime. @@ -60,7 +61,7 @@ async def register_actor( type_info = ActorTypeInformation.create(actor) # TODO: We will allow to use gRPC client later. actor_client = DaprActorHttpClient(message_serializer, timeout=http_timeout_seconds) - ctx = ActorRuntimeContext(type_info, message_serializer, state_serializer, actor_client) + ctx = ActorRuntimeContext(type_info, message_serializer, state_serializer, actor_client, actor_factory) # Create an ActorManager, override existing entry if registered again. async with cls._actor_managers_lock: diff --git a/ext/dapr-ext-fastapi/dapr/ext/fastapi/actor.py b/ext/dapr-ext-fastapi/dapr/ext/fastapi/actor.py index cf509fd6..48a10f2f 100644 --- a/ext/dapr-ext-fastapi/dapr/ext/fastapi/actor.py +++ b/ext/dapr-ext-fastapi/dapr/ext/fastapi/actor.py @@ -13,7 +13,7 @@ limitations under the License. """ -from typing import Any, Optional, Type, List +from typing import Any, Optional, Type, List, Callable from fastapi import FastAPI, APIRouter, Request, Response, status # type: ignore from fastapi.logger import logger @@ -149,6 +149,6 @@ async def actor_reminder( logger.debug(msg) return _wrap_response(status.HTTP_200_OK, msg) - async def register_actor(self, actor: Type[Actor]) -> None: - await ActorRuntime.register_actor(actor) + async def register_actor(self, actor: Type[Actor], **kwargs) -> None: + await ActorRuntime.register_actor(actor, **kwargs) logger.debug(f'registered actor: {actor.__class__.__name__}') diff --git a/ext/flask_dapr/flask_dapr/actor.py b/ext/flask_dapr/flask_dapr/actor.py index 17a40636..b717de15 100644 --- a/ext/flask_dapr/flask_dapr/actor.py +++ b/ext/flask_dapr/flask_dapr/actor.py @@ -65,8 +65,8 @@ def init_routes(self, app): def teardown(self, exception): self._app.logger.debug('actor service is shutting down.') - def register_actor(self, actor: Type[Actor]) -> None: - asyncio.run(ActorRuntime.register_actor(actor)) + def register_actor(self, actor: Type[Actor], **kwargs) -> None: + asyncio.run(ActorRuntime.register_actor(actor, **kwargs)) self._app.logger.debug(f'registered actor: {actor.__class__.__name__}') def _healthz_handler(self): diff --git a/tests/actor/test_actor_factory.py b/tests/actor/test_actor_factory.py new file mode 100644 index 00000000..ae8645ac --- /dev/null +++ b/tests/actor/test_actor_factory.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- + +""" +Copyright 2021 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +import unittest + +from dapr.actor import Actor +from dapr.actor.id import ActorId +from dapr.actor.runtime._type_information import ActorTypeInformation +from dapr.actor.runtime.manager import ActorManager +from dapr.actor.runtime.context import ActorRuntimeContext +from dapr.serializers import DefaultJSONSerializer + +from tests.actor.fake_actor_classes import ( + FakeSimpleActorInterface, +) + +from tests.actor.fake_client import FakeDaprActorClient + +from tests.actor.utils import _run + +class FakeDependency: + def __init__(self, value:str): + self.value = value + + def get_value(self) -> str: + return self.value + +class FakeSimpleActorWithDependency(Actor, FakeSimpleActorInterface): + def __init__(self, ctx, actor_id, dependency: FakeDependency): + super(FakeSimpleActorWithDependency, self).__init__(ctx, actor_id) + self.dependency = dependency + + async def actor_method(self, arg: int) -> dict: + return {'name': f'{arg}-{self.dependency.get_value()}'} + + async def _on_activate(self): + self.activated = True + self.deactivated = False + + async def _on_deactivate(self): + self.activated = False + self.deactivated = True + +def an_actor_factory(ctx: 'ActorRuntimeContext', actor_id: ActorId) -> 'Actor': + dependency = FakeDependency('some-value') + return ctx.actor_type_info.implementation_type(ctx, actor_id, dependency) + +class ActorFactoryTests(unittest.TestCase): + def setUp(self): + self._test_type_info = ActorTypeInformation.create(FakeSimpleActorWithDependency) + self._serializer = DefaultJSONSerializer() + + self._fake_client = FakeDaprActorClient + self._runtime_ctx = ActorRuntimeContext( + self._test_type_info, self._serializer, self._serializer, self._fake_client, an_actor_factory + ) + self._manager = ActorManager(self._runtime_ctx) + + def test_activate_actor(self): + """Activate ActorId(1)""" + test_actor_id = ActorId('1') + _run(self._manager.activate_actor(test_actor_id)) + + # assert + self.assertEqual(test_actor_id, self._manager._active_actors[test_actor_id.id].id) + self.assertTrue(self._manager._active_actors[test_actor_id.id].activated) + self.assertFalse(self._manager._active_actors[test_actor_id.id].deactivated) + + def test_dispatch_success(self): + """dispatch ActionMethod""" + test_actor_id = ActorId('dispatch') + _run(self._manager.activate_actor(test_actor_id)) + + test_request_body = b'5' + response = _run(self._manager.dispatch(test_actor_id, 'ActorMethod', test_request_body)) + self.assertEqual(b'{"name":"5-some-value"}', response) From adbae7b394e1c0baff28a3d2e58abf21c0329990 Mon Sep 17 00:00:00 2001 From: Kapil Sachdeva Date: Mon, 24 Jun 2024 21:19:35 +0000 Subject: [PATCH 3/7] chore - lint runtime.py & test_actor_factory.py Signed-off-by: Kapil Sachdeva --- dapr/actor/runtime/runtime.py | 4 +++- tests/actor/test_actor_factory.py | 22 +++++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/dapr/actor/runtime/runtime.py b/dapr/actor/runtime/runtime.py index b820c536..3659f147 100644 --- a/dapr/actor/runtime/runtime.py +++ b/dapr/actor/runtime/runtime.py @@ -61,7 +61,9 @@ async def register_actor( type_info = ActorTypeInformation.create(actor) # TODO: We will allow to use gRPC client later. actor_client = DaprActorHttpClient(message_serializer, timeout=http_timeout_seconds) - ctx = ActorRuntimeContext(type_info, message_serializer, state_serializer, actor_client, actor_factory) + ctx = ActorRuntimeContext( + type_info, message_serializer, state_serializer, actor_client, actor_factory + ) # Create an ActorManager, override existing entry if registered again. async with cls._actor_managers_lock: diff --git a/tests/actor/test_actor_factory.py b/tests/actor/test_actor_factory.py index ae8645ac..0715c33f 100644 --- a/tests/actor/test_actor_factory.py +++ b/tests/actor/test_actor_factory.py @@ -22,7 +22,7 @@ from dapr.actor.runtime.context import ActorRuntimeContext from dapr.serializers import DefaultJSONSerializer -from tests.actor.fake_actor_classes import ( +from tests.actor.fake_actor_classes import ( FakeSimpleActorInterface, ) @@ -30,21 +30,23 @@ from tests.actor.utils import _run + class FakeDependency: - def __init__(self, value:str): + def __init__(self, value: str): self.value = value def get_value(self) -> str: return self.value + class FakeSimpleActorWithDependency(Actor, FakeSimpleActorInterface): def __init__(self, ctx, actor_id, dependency: FakeDependency): super(FakeSimpleActorWithDependency, self).__init__(ctx, actor_id) self.dependency = dependency async def actor_method(self, arg: int) -> dict: - return {'name': f'{arg}-{self.dependency.get_value()}'} - + return {'name': f'{arg}-{self.dependency.get_value()}'} + async def _on_activate(self): self.activated = True self.deactivated = False @@ -53,9 +55,11 @@ async def _on_deactivate(self): self.activated = False self.deactivated = True + def an_actor_factory(ctx: 'ActorRuntimeContext', actor_id: ActorId) -> 'Actor': dependency = FakeDependency('some-value') - return ctx.actor_type_info.implementation_type(ctx, actor_id, dependency) + return ctx.actor_type_info.implementation_type(ctx, actor_id, dependency) + class ActorFactoryTests(unittest.TestCase): def setUp(self): @@ -64,14 +68,18 @@ def setUp(self): self._fake_client = FakeDaprActorClient self._runtime_ctx = ActorRuntimeContext( - self._test_type_info, self._serializer, self._serializer, self._fake_client, an_actor_factory + self._test_type_info, + self._serializer, + self._serializer, + self._fake_client, + an_actor_factory, ) self._manager = ActorManager(self._runtime_ctx) def test_activate_actor(self): """Activate ActorId(1)""" test_actor_id = ActorId('1') - _run(self._manager.activate_actor(test_actor_id)) + _run(self._manager.activate_actor(test_actor_id)) # assert self.assertEqual(test_actor_id, self._manager._active_actors[test_actor_id.id].id) From a2395b36b3456e00b99ce512ebeab2fb0c3bf542 Mon Sep 17 00:00:00 2001 From: Bernd Verst Date: Wed, 15 May 2024 19:06:17 -0700 Subject: [PATCH 4/7] Pin workflow SDK 0.4.1 in example (#715) * Pin workflow SDK 0.4.1 in example Signed-off-by: Bernd Verst * fix workflow dev version Signed-off-by: Bernd Verst * fix workflow example dependency Signed-off-by: Bernd Verst --------- Signed-off-by: Bernd Verst Signed-off-by: Kapil Sachdeva --- examples/workflow/requirements.txt | 3 ++- ext/dapr-ext-workflow/dapr/ext/workflow/version.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/workflow/requirements.txt b/examples/workflow/requirements.txt index b7f8da74..6a748d0e 100644 --- a/examples/workflow/requirements.txt +++ b/examples/workflow/requirements.txt @@ -1 +1,2 @@ -dapr-ext-workflow>=0.1.0 +dapr-ext-workflow-dev>=0.4.1rc1.dev +dapr-dev>=1.13.0rc1.dev diff --git a/ext/dapr-ext-workflow/dapr/ext/workflow/version.py b/ext/dapr-ext-workflow/dapr/ext/workflow/version.py index 37933993..581cb696 100644 --- a/ext/dapr-ext-workflow/dapr/ext/workflow/version.py +++ b/ext/dapr-ext-workflow/dapr/ext/workflow/version.py @@ -13,4 +13,4 @@ limitations under the License. """ -__version__ = '0.4.0rc1.dev' +__version__ = '0.4.1rc1.dev' From 97b9edde1cc21dd776e5ad74becd206b2198b0c3 Mon Sep 17 00:00:00 2001 From: "Kent (Chia-Hao), Hsu" Date: Tue, 25 Jun 2024 02:14:42 +0800 Subject: [PATCH 5/7] doc: document that users can self-assign issues (#712) * doc: document that users can self-assign issues Signed-off-by: KentHsu * doc: reorder paragraph and update CONTRIBUTING.md Signed-off-by: KentHsu --------- Signed-off-by: KentHsu Co-authored-by: Elena Kolevska Signed-off-by: Kapil Sachdeva --- CONTRIBUTING.md | 4 ++++ .../en/python-sdk-contributing/python-contributing.md | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 62b34048..d173bd04 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -120,6 +120,10 @@ A non-exclusive list of code that must be places in `vendor/`: **Thank You!** - Your contributions to open source, large or small, make projects like this possible. Thank you for taking the time to contribute. +## Github Dapr Bot Commands + +Checkout the [daprbot documentation](https://docs.dapr.io/contributing/daprbot/) for Github commands you can run in this repo for common tasks. For example, you can run the `/assign` (as a comment on an issue) to assign issues to a user or group of users. + ## Code of Conduct This project has adopted the [Contributor Covenant Code of Conduct](https://github.com/dapr/community/blob/master/CODE-OF-CONDUCT.md) diff --git a/daprdocs/content/en/python-sdk-contributing/python-contributing.md b/daprdocs/content/en/python-sdk-contributing/python-contributing.md index 3d68cde7..24ed10ef 100644 --- a/daprdocs/content/en/python-sdk-contributing/python-contributing.md +++ b/daprdocs/content/en/python-sdk-contributing/python-contributing.md @@ -20,4 +20,8 @@ The `examples` directory contains code samples for users to run to try out speci The `daprdocs` directory contains the markdown files that are rendered into the [Dapr Docs](https://docs.dapr.io) website. When the documentation website is built this repo is cloned and configured so that its contents are rendered with the docs content. When writing docs keep in mind: - All rules in the [docs guide]({{< ref contributing-docs.md >}}) should be followed in addition to these. - - All files and directories should be prefixed with `python-` to ensure all file/directory names are globally unique across all Dapr documentation. \ No newline at end of file + - All files and directories should be prefixed with `python-` to ensure all file/directory names are globally unique across all Dapr documentation. + +## Github Dapr Bot Commands + +Checkout the [daprbot documentation](https://docs.dapr.io/contributing/daprbot/) for Github commands you can run in this repo for common tasks. For example, you can run the `/assign` (as a comment on an issue) to assign issues to a user or group of users. \ No newline at end of file From cacfd9edd31e620a990eab239c8604a48a1ef4a9 Mon Sep 17 00:00:00 2001 From: Pieter de Bruin Date: Mon, 24 Jun 2024 20:22:02 +0200 Subject: [PATCH 6/7] Standardize README shield badges (#721) Signed-off-by: Pieter de Bruin Co-authored-by: Bernd Verst Signed-off-by: Kapil Sachdeva --- README.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index faa83491..9ccc02d6 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ # Dapr SDK for Python -[![PyPI version](https://badge.fury.io/py/dapr.svg)](https://badge.fury.io/py/dapr) -[![PyPI version](https://badge.fury.io/py/dapr-dev.svg)](https://badge.fury.io/py/dapr-dev) -![dapr-python](https://github.com/dapr/python-sdk/workflows/dapr-python/badge.svg?branch=master) -[![codecov](https://codecov.io/gh/dapr/python-sdk/branch/master/graph/badge.svg)](https://codecov.io/gh/dapr/python-sdk) -[![Discord](https://img.shields.io/discord/778680217417809931)](https://discord.com/channels/778680217417809931/778680217417809934) -[![License: Apache](https://img.shields.io/badge/License-Apache-yellow.svg)](http://www.apache.org/licenses/LICENSE-2.0) -[![FOSSA Status](https://app.fossa.com/api/projects/custom%2B162%2Fgithub.com%2Fdapr%2Fpython-sdk.svg?type=shield)](https://app.fossa.com/projects/custom%2B162%2Fgithub.com%2Fdapr%2Fpython-sdk?ref=badge_shield) +[![PyPI - Version](https://img.shields.io/pypi/v/dapr?style=flat&logo=pypi&logoColor=white&label=Latest%20version)](https://pypi.org/project/dapr/) +[![PyPI - Downloads](https://img.shields.io/pypi/dm/dapr?style=flat&logo=pypi&logoColor=white&label=Downloads)](https://pypi.org/project/dapr/) +[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/dapr/python-sdk/.github%2Fworkflows%2Fbuild.yaml?branch=main&label=Build&logo=github)](https://github.com/dapr/python-sdk/actions/workflows/build.yaml) +[![codecov](https://codecov.io/gh/dapr/python-sdk/branch/main/graph/badge.svg)](https://codecov.io/gh/dapr/python-sdk) +[![GitHub License](https://img.shields.io/github/license/dapr/python-sdk?style=flat&label=License&logo=github)](https://github.com/dapr/python-sdk/blob/main/LICENSE) +[![GitHub issue custom search in repo](https://img.shields.io/github/issues-search/dapr/python-sdk?query=type%3Aissue%20is%3Aopen%20label%3A%22good%20first%20issue%22&label=Good%20first%20issues&style=flat&logo=github)](https://github.com/dapr/python-sdk/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) +[![Discord](https://img.shields.io/discord/778680217417809931?label=Discord&style=flat&logo=discord)](http://bit.ly/dapr-discord) +[![YouTube Channel Views](https://img.shields.io/youtube/channel/views/UCtpSQ9BLB_3EXdWAUQYwnRA?style=flat&label=YouTube%20views&logo=youtube)](https://youtube.com/@daprdev) +[![X (formerly Twitter) Follow](https://img.shields.io/twitter/follow/daprdev?logo=x&style=flat)](https://twitter.com/daprdev) [Dapr](https://docs.dapr.io/concepts/overview/) is a portable, event-driven, serverless runtime for building distributed applications across cloud and edge. From e5607b217c192355447de221b1aabedcf12779c2 Mon Sep 17 00:00:00 2001 From: Bernd Verst Date: Wed, 26 Jun 2024 10:32:49 -0700 Subject: [PATCH 7/7] remove unneeded import Signed-off-by: Bernd Verst --- ext/dapr-ext-fastapi/dapr/ext/fastapi/actor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/dapr-ext-fastapi/dapr/ext/fastapi/actor.py b/ext/dapr-ext-fastapi/dapr/ext/fastapi/actor.py index 48a10f2f..793704f7 100644 --- a/ext/dapr-ext-fastapi/dapr/ext/fastapi/actor.py +++ b/ext/dapr-ext-fastapi/dapr/ext/fastapi/actor.py @@ -13,7 +13,7 @@ limitations under the License. """ -from typing import Any, Optional, Type, List, Callable +from typing import Any, Optional, Type, List from fastapi import FastAPI, APIRouter, Request, Response, status # type: ignore from fastapi.logger import logger