├── dapr ├── py.typed ├── __init__.pyi ├── version │ ├── __init__.py │ └── version.py ├── proto │ ├── common │ │ ├── v1 │ │ │ ├── common_pb2_grpc.py │ │ │ └── __init__.py │ │ └── __init__.py │ ├── runtime │ │ ├── __init__.py │ │ └── v1 │ │ │ └── __init__.py │ ├── README.md │ └── __init__.py ├── actor │ ├── client │ │ └── __init__.py │ ├── runtime │ │ ├── __init__.py │ │ ├── reentrancy_context.py │ │ ├── _call_type.py │ │ ├── remindable.py │ │ ├── state_change.py │ │ ├── method_dispatcher.py │ │ └── _method_context.py │ ├── __init__.py │ ├── id.py │ └── actor_interface.py ├── clients │ ├── grpc │ │ └── __init__.py │ ├── http │ │ ├── __init__.py │ │ ├── conf.py │ │ └── helpers.py │ ├── _constants.py │ └── base.py ├── aio │ └── clients │ │ └── grpc │ │ └── __init__.py ├── serializers │ ├── __init__.py │ └── base.py └── conf │ ├── __init__.py │ └── global_settings.py ├── tests ├── __init__.py ├── actor │ ├── utils.py │ ├── __init__.py │ ├── test_actor_id.py │ ├── test_type_information.py │ └── test_timer_data.py ├── clients │ ├── __init__.py │ ├── test_http_helpers.py │ ├── test_dapr_grpc_response_async.py │ ├── test_client_interceptor.py │ └── test_timeout_interceptor_async.py └── serializers │ └── __init__.py ├── ext ├── dapr-ext-fastapi │ ├── tests │ │ └── __init__.py │ ├── dapr │ │ └── ext │ │ │ └── fastapi │ │ │ ├── py.typed │ │ │ ├── version.py │ │ │ └── __init__.py │ ├── README.rst │ ├── setup.cfg │ └── setup.py ├── dapr-ext-grpc │ ├── tests │ │ ├── __init__.py │ │ ├── test_health_servicer.py │ │ └── test_topic_event_response.py │ ├── dapr │ │ └── ext │ │ │ └── grpc │ │ │ ├── py.typed │ │ │ ├── version.py │ │ │ ├── _health_servicer.py │ │ │ └── __init__.py │ ├── README.rst │ ├── setup.cfg │ └── setup.py ├── flask_dapr │ ├── flask_dapr │ │ ├── py.typed │ │ ├── version.py │ │ └── __init__.py │ ├── README.rst │ ├── setup.cfg │ └── setup.py ├── dapr-ext-workflow │ ├── dapr │ │ └── ext │ │ │ └── workflow │ │ │ ├── py.typed │ │ │ ├── logger │ │ │ ├── __init__.py │ │ │ ├── logger.py │ │ │ └── options.py │ │ │ ├── version.py │ │ │ ├── aio │ │ │ └── __init__.py │ │ │ ├── util.py │ │ │ ├── __init__.py │ │ │ └── workflow_activity_context.py │ ├── README.rst │ ├── tests │ │ ├── __init__.py │ │ ├── test_workflow_util.py │ │ └── test_workflow_activity_context.py │ └── setup.cfg └── dapr-ext-langgraph │ ├── dapr │ └── ext │ │ └── langgraph │ │ ├── py.typed │ │ ├── version.py │ │ └── __init__.py │ ├── README.rst │ ├── tests │ └── __init__.py │ └── setup.cfg ├── tools └── requirements.txt ├── examples ├── demo_actor │ ├── demo_actor │ │ ├── requirements.txt │ │ ├── Dockerfile │ │ ├── demo_actor_interface.py │ │ ├── demo_actor_service.py │ │ ├── test_demo_actor.py │ │ └── demo_actor_flask.py │ └── deploy │ │ ├── redis.yml │ │ ├── demo_actor_client.yml │ │ └── demo_actor_service.yml ├── demo_workflow │ ├── demo_workflow │ │ └── requirements.txt │ └── components │ │ └── state_redis.yaml ├── workflow │ ├── requirements.txt │ ├── cross-app3.py │ ├── child_workflow.py │ ├── cross-app2.py │ └── cross-app1.py ├── invoke-simple │ ├── requirements.txt │ ├── Dockerfile │ ├── invoke-receiver.py │ ├── invoke-caller.py │ └── deploy │ │ ├── invoke-caller.yaml │ │ └── invoke-receiver.yaml ├── validate.sh ├── crypto │ ├── desert.jpg │ └── components │ │ └── crypto-localstorage.yaml ├── secret_store │ ├── secrets.json │ ├── config.yaml │ ├── components │ │ └── localsecretstore.yaml │ └── example.py ├── langgraph-checkpointer │ ├── requirements.txt │ ├── components │ │ └── statestore.yaml │ ├── README.md │ └── agent.py ├── w3c-tracing │ ├── img │ │ ├── service.png │ │ ├── zipkin-details.png │ │ ├── zipkin-landing.png │ │ └── zipkin-result.png │ ├── requirements.txt │ └── Dockerfile ├── conversation │ ├── config │ │ └── conversation-echo.yaml │ ├── .env.example │ ├── conversation_alpha1.py │ └── conversation_alpha2.py ├── invoke-custom-data │ ├── proto │ │ ├── response.proto │ │ ├── response_pb2_grpc.py │ │ └── response_pb2.py │ ├── invoke-receiver.py │ └── invoke-caller.py ├── state_store_query │ ├── components │ │ └── mongodb.yml │ ├── query.json │ ├── query-token.json │ ├── state_store_query.py │ └── dataset.json ├── invoke-binding │ ├── invoke-input-binding.py │ ├── components │ │ ├── pubsub.yaml │ │ ├── statestore.yaml │ │ └── kafka-binding.yaml │ ├── invoke-output-binding.py │ └── docker-compose-single-kafka.yml ├── metadata │ ├── components │ │ ├── pubsub.yaml │ │ ├── lockstore.yaml │ │ └── statestore.yaml │ └── app.py ├── state_store │ └── components │ │ ├── pubsub.yaml │ │ └── statestore.yaml ├── distributed_lock │ ├── components │ │ └── lockstore.yaml │ └── lock.py ├── grpc_proxying │ ├── config.yaml │ ├── proto │ │ └── helloworld_service.proto │ ├── invoke-caller.py │ ├── invoke-receiver.py │ ├── deploy │ │ ├── invoke-caller.yaml │ │ └── invoke-receiver.yaml │ └── helloworld_service_pb2.py ├── configuration │ ├── components │ │ └── configurationstore.yaml │ ├── configuration.py │ └── README.md ├── error_handling │ ├── components │ │ └── state_redis.yaml │ └── error_handling.py ├── invoke-http │ ├── invoke-receiver.py │ ├── invoke-caller.py │ └── README.md ├── pubsub-streaming │ ├── subscriber-handler.py │ └── publisher.py ├── README.md └── pubsub-streaming-async │ ├── subscriber-handler.py │ └── publisher.py ├── docs ├── actor │ ├── modules.rst │ ├── actor.client.rst │ ├── actor.rst │ └── actor.runtime.rst ├── proto │ ├── modules.rst │ ├── proto.dapr.rst │ ├── proto.common.rst │ ├── proto.runtime.rst │ ├── proto.rst │ ├── proto.daprclient.rst │ ├── proto.dapr.v1.rst │ ├── proto.common.v1.rst │ ├── proto.daprclient.v1.rst │ └── proto.runtime.v1.rst ├── clients │ ├── modules.rst │ ├── clients.http.rst │ ├── clients.rst │ └── clients.grpc.rst ├── serializers │ ├── modules.rst │ └── serializers.rst ├── index.rst ├── Makefile └── make.bat ├── CODEOWNERS ├── .github ├── holopin.yml ├── ISSUE_TEMPLATE │ ├── question.md │ ├── workflow_question.md │ ├── feature_request.md │ ├── workflow_feature_request.md │ ├── config.yml │ ├── bug_report.md │ └── workflow_bug_report.md ├── pull_request_template.md ├── dependabot.yml └── workflows │ ├── build.yaml │ └── fossa.yaml ├── .devcontainer ├── postCreateCommand.sh └── devcontainer.json ├── .codecov.yml ├── mypy.ini ├── dev-requirements.txt ├── pyproject.toml ├── setup.cfg ├── .gitignore └── setup.py /dapr/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dapr/__init__.pyi: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ext/dapr-ext-fastapi/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ext/dapr-ext-grpc/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ext/flask_dapr/flask_dapr/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ext/dapr-ext-grpc/dapr/ext/grpc/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ext/dapr-ext-fastapi/dapr/ext/fastapi/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ext/dapr-ext-workflow/dapr/ext/workflow/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ext/dapr-ext-langgraph/dapr/ext/langgraph/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tools/requirements.txt: -------------------------------------------------------------------------------- 1 | grpcio-tools==1.62.3 2 | mypy-protobuf==3.7.0 3 | -------------------------------------------------------------------------------- /examples/demo_actor/demo_actor/requirements.txt: -------------------------------------------------------------------------------- 1 | dapr-ext-fastapi>=1.16.0.dev 2 | -------------------------------------------------------------------------------- /examples/demo_workflow/demo_workflow/requirements.txt: -------------------------------------------------------------------------------- 1 | dapr-ext-workflow>=1.16.0.dev 2 | -------------------------------------------------------------------------------- /examples/workflow/requirements.txt: -------------------------------------------------------------------------------- 1 | dapr-ext-workflow>=1.16.0.dev 2 | dapr>=1.16.0.dev 3 | -------------------------------------------------------------------------------- /examples/invoke-simple/requirements.txt: -------------------------------------------------------------------------------- 1 | dapr-ext-grpc >= 1.16.0.dev 2 | dapr >= 1.16.0.dev 3 | -------------------------------------------------------------------------------- /examples/validate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "Home: $HOME" 3 | 4 | cd $1 && mm.py -l README.md 5 | -------------------------------------------------------------------------------- /docs/actor/modules.rst: -------------------------------------------------------------------------------- 1 | actor 2 | ===== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | actor 8 | -------------------------------------------------------------------------------- /docs/proto/modules.rst: -------------------------------------------------------------------------------- 1 | proto 2 | ===== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | proto 8 | -------------------------------------------------------------------------------- /examples/crypto/desert.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dapr/python-sdk/HEAD/examples/crypto/desert.jpg -------------------------------------------------------------------------------- /dapr/version/__init__.py: -------------------------------------------------------------------------------- 1 | from dapr.version.version import __version__ 2 | 3 | __all__ = ['__version__'] 4 | -------------------------------------------------------------------------------- /docs/clients/modules.rst: -------------------------------------------------------------------------------- 1 | clients 2 | ======= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | clients 8 | -------------------------------------------------------------------------------- /examples/secret_store/secrets.json: -------------------------------------------------------------------------------- 1 | { 2 | "secretKey": "secretValue", 3 | "random": "randomValue" 4 | } -------------------------------------------------------------------------------- /examples/langgraph-checkpointer/requirements.txt: -------------------------------------------------------------------------------- 1 | langchain-core>=1.0.7 2 | langgraph>=1.0.3 3 | langchain-ollama>=1.0.0 -------------------------------------------------------------------------------- /examples/w3c-tracing/img/service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dapr/python-sdk/HEAD/examples/w3c-tracing/img/service.png -------------------------------------------------------------------------------- /docs/serializers/modules.rst: -------------------------------------------------------------------------------- 1 | serializers 2 | =========== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | serializers 8 | -------------------------------------------------------------------------------- /examples/w3c-tracing/img/zipkin-details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dapr/python-sdk/HEAD/examples/w3c-tracing/img/zipkin-details.png -------------------------------------------------------------------------------- /examples/w3c-tracing/img/zipkin-landing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dapr/python-sdk/HEAD/examples/w3c-tracing/img/zipkin-landing.png -------------------------------------------------------------------------------- /examples/w3c-tracing/img/zipkin-result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dapr/python-sdk/HEAD/examples/w3c-tracing/img/zipkin-result.png -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners are the maintainers and approvers of this repo 2 | * @dapr/maintainers-python-sdk @dapr/approvers-python-sdk 3 | -------------------------------------------------------------------------------- /.github/holopin.yml: -------------------------------------------------------------------------------- 1 | organization: dapr 2 | defaultSticker: clrqfdv4x24910fl5n4iwu5oa 3 | stickers: 4 | - id: clrqfdv4x24910fl5n4iwu5oa 5 | alias: sdk-badge 6 | -------------------------------------------------------------------------------- /examples/conversation/config/conversation-echo.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: echo 5 | spec: 6 | type: conversation.echo 7 | version: v1 -------------------------------------------------------------------------------- /examples/invoke-custom-data/proto/response.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | message CustomResponse { 4 | bool isSuccess = 1; 5 | int32 code = 2; 6 | string message = 3; 7 | } -------------------------------------------------------------------------------- /examples/w3c-tracing/requirements.txt: -------------------------------------------------------------------------------- 1 | dapr-ext-grpc >= 1.16.0.dev 2 | dapr >= 1.16.0.dev 3 | opentelemetry-sdk 4 | opentelemetry-instrumentation-grpc 5 | opentelemetry-exporter-zipkin 6 | -------------------------------------------------------------------------------- /examples/invoke-custom-data/proto/response_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | -------------------------------------------------------------------------------- /dapr/proto/common/v1/common_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /ext/dapr-ext-workflow/dapr/ext/workflow/logger/__init__.py: -------------------------------------------------------------------------------- 1 | from dapr.ext.workflow.logger.logger import Logger 2 | from dapr.ext.workflow.logger.options import LoggerOptions 3 | 4 | __all__ = ['LoggerOptions', 'Logger'] 5 | -------------------------------------------------------------------------------- /examples/invoke-simple/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim 2 | 3 | WORKDIR /app 4 | 5 | ADD requirements.txt . 6 | RUN pip install -r requirements.txt 7 | 8 | COPY *.py /app/ 9 | 10 | CMD [ "python", "invoke-receiver.py" ] 11 | -------------------------------------------------------------------------------- /examples/w3c-tracing/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim 2 | 3 | WORKDIR /app 4 | 5 | ADD requirements.txt . 6 | RUN pip install -r requirements.txt 7 | 8 | COPY *.py /app/ 9 | 10 | CMD [ "python", "invoke-receiver.py" ] 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question (not workflow) 3 | about: Ask a question about the python sdk (not workflow) 4 | title: '[QUESTION] ' 5 | labels: kind/question 6 | assignees: '' 7 | 8 | --- 9 | ## Ask your question here 10 | -------------------------------------------------------------------------------- /examples/state_store_query/components/mongodb.yml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: statestore 5 | spec: 6 | type: state.mongodb 7 | version: v1 8 | metadata: 9 | - name: host 10 | value: localhost:27017 11 | -------------------------------------------------------------------------------- /examples/invoke-binding/invoke-input-binding.py: -------------------------------------------------------------------------------- 1 | from dapr.ext.grpc import App, BindingRequest 2 | 3 | app = App() 4 | 5 | 6 | @app.binding('kafkaBinding') 7 | def binding(request: BindingRequest): 8 | print(request.text(), flush=True) 9 | 10 | 11 | app.run(50051) 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/workflow_question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: WORKFLOW Question 3 | about: Ask a question about workflow 4 | title: '[WORKFLOW QUESTION] <title>' 5 | labels: ["kind/question", "dapr-ext-workflow"] 6 | assignees: '' 7 | 8 | --- 9 | ## Ask your WORKFLOW SDK question here 10 | -------------------------------------------------------------------------------- /examples/invoke-binding/components/pubsub.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: pubsub 5 | spec: 6 | type: pubsub.redis 7 | metadata: 8 | - name: redisHost 9 | value: localhost:6379 10 | - name: redisPassword 11 | value: "" 12 | -------------------------------------------------------------------------------- /examples/secret_store/config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Configuration 3 | metadata: 4 | name: daprConfig 5 | spec: 6 | secrets: 7 | scopes: 8 | - storeName: "localsecretstore" 9 | defaultAccess: "deny" 10 | allowedSecrets: ["secretKey",] -------------------------------------------------------------------------------- /examples/metadata/components/pubsub.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: pubsub 5 | spec: 6 | type: pubsub.redis 7 | version: v1 8 | metadata: 9 | - name: redisHost 10 | value: localhost:6379 11 | - name: redisPassword 12 | value: "" 13 | -------------------------------------------------------------------------------- /.devcontainer/postCreateCommand.sh: -------------------------------------------------------------------------------- 1 | # Install a project in a editable mode 2 | pip3 install -e . 3 | pip3 install -e ./ext/dapr-ext-grpc/ 4 | pip3 install -e ./ext/dapr-ext-fastapi/ 5 | pip3 install -e ./ext/dapr-ext-workflow/ 6 | 7 | # Install required packages 8 | pip3 install -r ./dev-requirements.txt 9 | -------------------------------------------------------------------------------- /examples/state_store/components/pubsub.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: pubsub 5 | spec: 6 | type: pubsub.redis 7 | version: v1 8 | metadata: 9 | - name: redisHost 10 | value: localhost:6379 11 | - name: redisPassword 12 | value: "" 13 | -------------------------------------------------------------------------------- /examples/metadata/components/lockstore.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: lockstore 5 | namespace: default 6 | spec: 7 | type: lock.redis 8 | metadata: 9 | - name: redisHost 10 | value: localhost:6379 11 | - name: redisPassword 12 | value: "" 13 | -------------------------------------------------------------------------------- /examples/distributed_lock/components/lockstore.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: lockstore 5 | namespace: default 6 | spec: 7 | type: lock.redis 8 | metadata: 9 | - name: redisHost 10 | value: localhost:6379 11 | - name: redisPassword 12 | value: "" 13 | -------------------------------------------------------------------------------- /examples/grpc_proxying/config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Configuration 3 | metadata: 4 | name: serverconfig 5 | spec: 6 | tracing: 7 | samplingRate: "1" 8 | zipkin: 9 | endpointAddress: http://localhost:9411/api/v2/spans 10 | features: 11 | - name: proxy.grpc 12 | enabled: true -------------------------------------------------------------------------------- /docs/proto/proto.dapr.rst: -------------------------------------------------------------------------------- 1 | proto.dapr package 2 | ================== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | proto.dapr.v1 11 | 12 | Module contents 13 | --------------- 14 | 15 | .. automodule:: proto.dapr 16 | :members: 17 | :undoc-members: 18 | :show-inheritance: 19 | -------------------------------------------------------------------------------- /examples/configuration/components/configurationstore.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: configurationstore 5 | namespace: default 6 | spec: 7 | type: configuration.redis 8 | metadata: 9 | - name: redisHost 10 | value: localhost:6379 11 | - name: redisPassword 12 | value: "" -------------------------------------------------------------------------------- /examples/secret_store/components/localsecretstore.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: localsecretstore 5 | namespace: default 6 | spec: 7 | type: secretstores.local.file 8 | metadata: 9 | - name: secretsFile 10 | value: secrets.json 11 | - name: nestedSeparator 12 | value: ":" -------------------------------------------------------------------------------- /docs/proto/proto.common.rst: -------------------------------------------------------------------------------- 1 | proto.common package 2 | ==================== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | proto.common.v1 11 | 12 | Module contents 13 | --------------- 14 | 15 | .. automodule:: proto.common 16 | :members: 17 | :undoc-members: 18 | :show-inheritance: 19 | -------------------------------------------------------------------------------- /docs/proto/proto.runtime.rst: -------------------------------------------------------------------------------- 1 | proto.runtime package 2 | ===================== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | proto.runtime.v1 11 | 12 | Module contents 13 | --------------- 14 | 15 | .. automodule:: proto.runtime 16 | :members: 17 | :undoc-members: 18 | :show-inheritance: 19 | -------------------------------------------------------------------------------- /examples/crypto/components/crypto-localstorage.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: crypto-localstorage 5 | spec: 6 | type: crypto.dapr.localstorage 7 | version: v1 8 | metadata: 9 | - name: path 10 | # Path is relative to the folder where the example is located 11 | value: ./keys -------------------------------------------------------------------------------- /examples/invoke-binding/components/statestore.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: statestore 5 | spec: 6 | type: state.redis 7 | metadata: 8 | - name: redisHost 9 | value: localhost:6379 10 | - name: redisPassword 11 | value: "" 12 | - name: actorStateStore 13 | value: "true" 14 | -------------------------------------------------------------------------------- /docs/proto/proto.rst: -------------------------------------------------------------------------------- 1 | proto package 2 | ============= 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | proto.common 11 | proto.dapr 12 | proto.daprclient 13 | 14 | Module contents 15 | --------------- 16 | 17 | .. automodule:: proto 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | -------------------------------------------------------------------------------- /docs/proto/proto.daprclient.rst: -------------------------------------------------------------------------------- 1 | proto.daprclient package 2 | ======================== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | proto.daprclient.v1 11 | 12 | Module contents 13 | --------------- 14 | 15 | .. automodule:: proto.daprclient 16 | :members: 17 | :undoc-members: 18 | :show-inheritance: 19 | -------------------------------------------------------------------------------- /examples/metadata/components/statestore.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: statestore 5 | spec: 6 | type: state.redis 7 | version: v1 8 | metadata: 9 | - name: redisHost 10 | value: localhost:6379 11 | - name: redisPassword 12 | value: "" 13 | - name: actorStateStore 14 | value: "true" 15 | -------------------------------------------------------------------------------- /examples/langgraph-checkpointer/components/statestore.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: statestore 5 | spec: 6 | type: state.redis 7 | version: v1 8 | metadata: 9 | - name: redisHost 10 | value: localhost:6379 11 | - name: redisPassword 12 | value: "" 13 | - name: actorStateStore 14 | value: "true" 15 | -------------------------------------------------------------------------------- /examples/error_handling/components/state_redis.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: statestore 5 | spec: 6 | type: state.redis 7 | version: v1 8 | initTimeout: 1m 9 | metadata: 10 | - name: redisHost 11 | value: localhost:6379 12 | - name: redisPassword 13 | value: "" 14 | - name: actorStateStore 15 | value: "true" -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | # basic 6 | target: auto 7 | threshold: 0% 8 | 9 | ignore: 10 | - dapr/proto # - Generated GRPC client 11 | - tests # - tests 12 | - .tox # - environment 13 | - ext/dapr-ext-fastapi/tests # - fastapi extention tests 14 | -------------------------------------------------------------------------------- /docs/actor/actor.client.rst: -------------------------------------------------------------------------------- 1 | actor.client package 2 | ==================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | 8 | .. automodule:: actor.client.proxy 9 | :members: 10 | :undoc-members: 11 | :show-inheritance: 12 | 13 | 14 | Module contents 15 | --------------- 16 | 17 | .. automodule:: actor.client 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | -------------------------------------------------------------------------------- /examples/demo_workflow/components/state_redis.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: statestore-actors 5 | spec: 6 | type: state.redis 7 | version: v1 8 | initTimeout: 1m 9 | metadata: 10 | - name: redisHost 11 | value: localhost:6379 12 | - name: redisPassword 13 | value: "" 14 | - name: actorStateStore 15 | value: "true" -------------------------------------------------------------------------------- /docs/clients/clients.http.rst: -------------------------------------------------------------------------------- 1 | clients.http package 2 | ==================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | 8 | .. automodule:: clients.http.dapr_actor_http_client 9 | :members: 10 | :undoc-members: 11 | :show-inheritance: 12 | 13 | 14 | Module contents 15 | --------------- 16 | 17 | .. automodule:: clients.http 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | -------------------------------------------------------------------------------- /examples/grpc_proxying/proto/helloworld_service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | message HelloRequest { 4 | string name = 1; 5 | } 6 | 7 | // The response message containing the greetings 8 | message HelloReply { 9 | string message = 1; 10 | } 11 | 12 | // The greeting service definition. 13 | service HelloWorldService { 14 | // Sends a greeting 15 | rpc SayHello (HelloRequest) returns (HelloReply) {} 16 | } -------------------------------------------------------------------------------- /examples/demo_actor/deploy/redis.yml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: statestore 5 | namespace: default 6 | spec: 7 | type: state.redis 8 | version: v1 9 | metadata: 10 | - name: redisHost 11 | value: redis-master.default.svc.cluster.local:6379 12 | - name: redisPassword 13 | secretKeyRef: 14 | name: redis 15 | key: redis-password 16 | - name: actorStateStore 17 | value: "true" 18 | -------------------------------------------------------------------------------- /examples/invoke-simple/invoke-receiver.py: -------------------------------------------------------------------------------- 1 | from dapr.ext.grpc import App, InvokeMethodRequest, InvokeMethodResponse 2 | 3 | app = App() 4 | 5 | 6 | @app.method(name='my-method') 7 | def mymethod(request: InvokeMethodRequest) -> InvokeMethodResponse: 8 | print(request.metadata, flush=True) 9 | print(request.text(), flush=True) 10 | 11 | return InvokeMethodResponse(b'INVOKE_RECEIVED', 'text/plain; charset=UTF-8') 12 | 13 | 14 | app.run(50051) 15 | -------------------------------------------------------------------------------- /examples/state_store/components/statestore.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: statestore 5 | spec: 6 | type: state.redis 7 | version: v1 8 | metadata: 9 | - name: redisHost 10 | value: localhost:6379 11 | - name: redisPassword 12 | value: "" 13 | - name: actorStateStore 14 | value: "true" 15 | - name: outboxPublishPubsub 16 | value: "pubsub" 17 | - name: outboxPublishTopic 18 | value: "test" -------------------------------------------------------------------------------- /examples/invoke-custom-data/invoke-receiver.py: -------------------------------------------------------------------------------- 1 | import proto.response_pb2 as response_messages 2 | from dapr.ext.grpc import App, InvokeMethodRequest 3 | 4 | app = App() 5 | 6 | 7 | @app.method('my_method') 8 | def mymethod(request: InvokeMethodRequest): 9 | print(request.metadata, flush=True) 10 | print(request.text(), flush=True) 11 | 12 | return response_messages.CustomResponse( 13 | isSuccess=True, code=200, message='Hello World - Success!' 14 | ) 15 | 16 | 17 | app.run(50051) 18 | -------------------------------------------------------------------------------- /docs/proto/proto.dapr.v1.rst: -------------------------------------------------------------------------------- 1 | proto.dapr.v1 package 2 | ===================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | 8 | .. automodule:: proto.dapr.v1.dapr_pb2 9 | :members: 10 | :undoc-members: 11 | :show-inheritance: 12 | 13 | 14 | .. automodule:: proto.dapr.v1.dapr_pb2_grpc 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | 20 | Module contents 21 | --------------- 22 | 23 | .. automodule:: proto.dapr.v1 24 | :members: 25 | :undoc-members: 26 | :show-inheritance: 27 | -------------------------------------------------------------------------------- /ext/dapr-ext-grpc/README.rst: -------------------------------------------------------------------------------- 1 | dapr-ext-grpc extension 2 | ======================= 3 | 4 | |pypi| 5 | 6 | .. |pypi| image:: https://badge.fury.io/py/dapr-ext-grpc.svg 7 | :target: https://pypi.org/project/dapr-ext-grpc/ 8 | 9 | This gRPC extension is used for gRPC appcallback 10 | 11 | Installation 12 | ------------ 13 | 14 | :: 15 | 16 | pip install dapr-ext-grpc 17 | 18 | References 19 | ---------- 20 | 21 | * `Dapr <https://github.com/dapr/dapr>`_ 22 | * `Dapr Python-SDK <https://github.com/dapr/python-sdk>`_ 23 | -------------------------------------------------------------------------------- /docs/proto/proto.common.v1.rst: -------------------------------------------------------------------------------- 1 | proto.common.v1 package 2 | ======================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | 8 | .. automodule:: proto.common.v1.common_pb2 9 | :members: 10 | :undoc-members: 11 | :show-inheritance: 12 | 13 | 14 | .. automodule:: proto.common.v1.common_pb2_grpc 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | 20 | Module contents 21 | --------------- 22 | 23 | .. automodule:: proto.common.v1 24 | :members: 25 | :undoc-members: 26 | :show-inheritance: 27 | -------------------------------------------------------------------------------- /ext/dapr-ext-fastapi/README.rst: -------------------------------------------------------------------------------- 1 | dapr-ext-fastapi extension 2 | ========================== 3 | 4 | |pypi| 5 | 6 | .. |pypi| image:: https://badge.fury.io/py/dapr-ext-fastapi.svg 7 | :target: https://pypi.org/project/dapr-ext-fastapi/ 8 | 9 | This FastAPI extension is used for FastAPI http server. 10 | 11 | Installation 12 | ------------ 13 | 14 | :: 15 | 16 | pip install dapr-ext-fastapi 17 | 18 | References 19 | ---------- 20 | 21 | * `Dapr <https://github.com/dapr/dapr>`_ 22 | * `Dapr Python-SDK <https://github.com/dapr/python-sdk>`_ 23 | -------------------------------------------------------------------------------- /tests/actor/utils.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from unittest import mock 3 | 4 | 5 | def _async_mock(*args, **kwargs): 6 | m = mock.MagicMock(*args, **kwargs) 7 | 8 | async def mock_coro(*args, **kwargs): 9 | return m(*args, **kwargs) 10 | 11 | mock_coro.mock = m 12 | return mock_coro 13 | 14 | 15 | def _run(coro): 16 | try: 17 | loop = asyncio.get_running_loop() 18 | except RuntimeError: 19 | loop = asyncio.new_event_loop() 20 | asyncio.set_event_loop(loop) 21 | return loop.run_until_complete(coro) 22 | -------------------------------------------------------------------------------- /ext/dapr-ext-langgraph/README.rst: -------------------------------------------------------------------------------- 1 | dapr-ext-langgraph extension 2 | ======================= 3 | 4 | |pypi| 5 | 6 | .. |pypi| image:: https://badge.fury.io/py/dapr-ext-langgraph.svg 7 | :target: https://pypi.org/project/dapr-ext-langgraph/ 8 | 9 | This is the Dapr Checkpointer extension for LangGraph 10 | 11 | Installation 12 | ------------ 13 | 14 | :: 15 | 16 | pip install dapr-ext-langgraph 17 | 18 | References 19 | ---------- 20 | 21 | * `Dapr <https://github.com/dapr/dapr>`_ 22 | * `Dapr Python-SDK <https://github.com/dapr/python-sdk>`_ 23 | -------------------------------------------------------------------------------- /examples/invoke-binding/invoke-output-binding.py: -------------------------------------------------------------------------------- 1 | import json 2 | import time 3 | 4 | from dapr.clients import DaprClient 5 | 6 | with DaprClient() as d: 7 | n = 0 8 | while True: 9 | n += 1 10 | req_data = {'id': n, 'message': 'hello world'} 11 | 12 | print(f'Sending message id: {req_data["id"]}, message "{req_data["message"]}"', flush=True) 13 | 14 | # Create a typed message with content type and body 15 | resp = d.invoke_binding('kafkaBinding', 'create', json.dumps(req_data)) 16 | 17 | time.sleep(1) 18 | -------------------------------------------------------------------------------- /docs/proto/proto.daprclient.v1.rst: -------------------------------------------------------------------------------- 1 | proto.daprclient.v1 package 2 | =========================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | 8 | .. automodule:: proto.daprclient.v1.daprclient_pb2 9 | :members: 10 | :undoc-members: 11 | :show-inheritance: 12 | 13 | 14 | .. automodule:: proto.daprclient.v1.daprclient_pb2_grpc 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | 20 | Module contents 21 | --------------- 22 | 23 | .. automodule:: proto.daprclient.v1 24 | :members: 25 | :undoc-members: 26 | :show-inheritance: 27 | -------------------------------------------------------------------------------- /ext/dapr-ext-workflow/README.rst: -------------------------------------------------------------------------------- 1 | dapr-ext-workflow extension 2 | =========================== 3 | 4 | |pypi| 5 | 6 | .. |pypi| image:: https://badge.fury.io/py/dapr-ext-workflow.svg 7 | :target: https://pypi.org/project/dapr-ext-workflow/ 8 | 9 | This is the workflow authoring extension for Dapr Workflow 10 | 11 | 12 | Installation 13 | ------------ 14 | 15 | :: 16 | 17 | pip install dapr-ext-workflow 18 | 19 | References 20 | ---------- 21 | 22 | * `Dapr <https://github.com/dapr/dapr>`_ 23 | * `Dapr Python-SDK <https://github.com/dapr/python-sdk>`_ 24 | -------------------------------------------------------------------------------- /mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | python_version = 3.9 3 | warn_unused_configs = True 4 | warn_redundant_casts = True 5 | show_error_codes = True 6 | check_untyped_defs = True 7 | install_types = True 8 | non_interactive = True 9 | 10 | files = 11 | dapr/actor/**/*.py, 12 | dapr/clients/**/*.py, 13 | dapr/conf/**/*.py, 14 | dapr/serializers/**/*.py, 15 | ext/dapr-ext-grpc/dapr/**/*.py, 16 | ext/dapr-ext-fastapi/dapr/**/*.py, 17 | ext/flask_dapr/flask_dapr/*.py, 18 | examples/demo_actor/**/*.py 19 | 20 | [mypy-dapr.proto.*] 21 | ignore_errors = True 22 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | _Please explain the changes you've made_ 4 | 5 | ## Issue reference 6 | 7 | We strive to have all PR being opened based on an issue, where the problem or feature have been discussed prior to implementation. 8 | 9 | Please reference the issue this PR will close: #_[issue number]_ 10 | 11 | ## Checklist 12 | 13 | Please make sure you've completed the relevant tasks for this PR, out of the following list: 14 | 15 | * [ ] Code compiles correctly 16 | * [ ] Created/updated tests 17 | * [ ] Extended the documentation 18 | -------------------------------------------------------------------------------- /examples/conversation/.env.example: -------------------------------------------------------------------------------- 1 | # LLM Provider API Keys 2 | # Add your API keys for the providers you want to test 3 | 4 | # OpenAI 5 | OPENAI_API_KEY=your_openai_api_key_here 6 | 7 | # Anthropic 8 | ANTHROPIC_API_KEY=your_anthropic_api_key_here 9 | 10 | # Mistral AI 11 | MISTRAL_API_KEY=your_mistral_api_key_here 12 | 13 | # DeepSeek 14 | DEEPSEEK_API_KEY=your_deepseek_api_key_here 15 | 16 | # Google AI (Gemini/Vertex) 17 | GOOGLE_API_KEY=your_google_api_key_here 18 | 19 | # Optional: Default component to use if not specified 20 | DAPR_LLM_COMPONENT_DEFAULT=openai 21 | -------------------------------------------------------------------------------- /examples/invoke-custom-data/invoke-caller.py: -------------------------------------------------------------------------------- 1 | import proto.response_pb2 as response_messages 2 | 3 | from dapr.clients import DaprClient 4 | 5 | with DaprClient() as d: 6 | # Create a typed message with content type and body 7 | resp = d.invoke_method( 8 | app_id='invoke-receiver', 9 | method_name='my_method', 10 | data=b'SOME_DATA', 11 | content_type='text/plain; charset=UTF-8', 12 | ) 13 | 14 | res = response_messages.CustomResponse() 15 | resp.unpack(res) 16 | 17 | # Print Result 18 | print(res, flush=True) 19 | -------------------------------------------------------------------------------- /examples/invoke-binding/components/kafka-binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: kafkaBinding 5 | spec: 6 | type: bindings.kafka 7 | metadata: 8 | # Kafka broker connection setting 9 | - name: brokers 10 | value: localhost:9092 11 | # consumer configuration: topic and consumer group 12 | - name: topics 13 | value: sample 14 | - name: consumerGroup 15 | value: group1 16 | # publisher configuration: topic 17 | - name: publishTopic 18 | value: sample 19 | - name: authRequired 20 | value: "false" 21 | -------------------------------------------------------------------------------- /docs/clients/clients.rst: -------------------------------------------------------------------------------- 1 | clients package 2 | =============== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | clients.http 11 | 12 | Submodules 13 | ---------- 14 | 15 | 16 | .. automodule:: clients.base 17 | :members: 18 | :undoc-members: 19 | :show-inheritance: 20 | 21 | 22 | .. automodule:: clients.exceptions 23 | :members: 24 | :undoc-members: 25 | :show-inheritance: 26 | 27 | 28 | Module contents 29 | --------------- 30 | 31 | .. automodule:: clients 32 | :members: 33 | :undoc-members: 34 | :show-inheritance: 35 | -------------------------------------------------------------------------------- /docs/actor/actor.rst: -------------------------------------------------------------------------------- 1 | actor package 2 | ============= 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | actor.client 11 | actor.runtime 12 | 13 | Submodules 14 | ---------- 15 | 16 | 17 | .. automodule:: actor.actor_interface 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | 22 | 23 | .. automodule:: actor.id 24 | :members: 25 | :undoc-members: 26 | :show-inheritance: 27 | 28 | 29 | Module contents 30 | --------------- 31 | 32 | .. automodule:: actor 33 | :members: 34 | :undoc-members: 35 | :show-inheritance: 36 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "pip" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | - package-ecosystem: "pip" 8 | directory: "/ext/dapr-ext-fastapi" 9 | schedule: 10 | interval: "daily" 11 | - package-ecosystem: "pip" 12 | directory: "/ext/dapr-ext-grpc" 13 | schedule: 14 | interval: "daily" 15 | - package-ecosystem: "pip" 16 | directory: "/ext/flask_dapr" 17 | schedule: 18 | interval: "daily" 19 | - package-ecosystem: "github-actions" 20 | directory: "/" 21 | schedule: 22 | interval: "daily" -------------------------------------------------------------------------------- /docs/serializers/serializers.rst: -------------------------------------------------------------------------------- 1 | serializers package 2 | =================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | 8 | .. automodule:: serializers.base 9 | :members: 10 | :undoc-members: 11 | :show-inheritance: 12 | 13 | 14 | .. automodule:: serializers.json 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | 20 | .. automodule:: serializers.util 21 | :members: 22 | :undoc-members: 23 | :show-inheritance: 24 | 25 | 26 | Module contents 27 | --------------- 28 | 29 | .. automodule:: serializers 30 | :members: 31 | :undoc-members: 32 | :show-inheritance: 33 | -------------------------------------------------------------------------------- /docs/clients/clients.grpc.rst: -------------------------------------------------------------------------------- 1 | clients.grpc package 2 | ==================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | 8 | .. automodule:: clients.grpc.client 9 | :members: 10 | :undoc-members: 11 | :show-inheritance: 12 | 13 | 14 | .. automodule:: clients.grpc.interceptors 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | 20 | .. automodule:: clients.grpc.subscription 21 | :members: 22 | :undoc-members: 23 | :show-inheritance: 24 | 25 | Module contents 26 | --------------- 27 | 28 | .. automodule:: clients.grpc 29 | :members: 30 | :undoc-members: 31 | :show-inheritance: 32 | -------------------------------------------------------------------------------- /dev-requirements.txt: -------------------------------------------------------------------------------- 1 | mypy>=1.2.0 2 | mypy-extensions>=0.4.3 3 | mypy-protobuf>=2.9 4 | tox>=4.3.0 5 | coverage>=5.3 6 | wheel 7 | # used in unit test only 8 | opentelemetry-sdk 9 | opentelemetry-instrumentation-grpc 10 | httpx>=0.24 11 | pyOpenSSL>=23.2.0 12 | # needed for type checking 13 | Flask>=1.1 14 | # needed for auto fix 15 | ruff===0.14.1 16 | # needed for dapr-ext-workflow 17 | durabletask-dapr >= 0.2.0a9 18 | # needed for .env file loading in examples 19 | python-dotenv>=1.0.0 20 | # needed for enhanced schema generation from function features 21 | pydantic>=2.0.0 22 | # needed for yaml file generation in examples 23 | PyYAML>=6.0.2 24 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.ruff] 2 | target-version = "py310" 3 | line-length = 100 4 | fix = true 5 | extend-exclude = [".github", "dapr/proto"] 6 | 7 | [tool.ruff.lint] 8 | select = [ 9 | "I", # isort 10 | "W", # pycodestyle warnings 11 | "F", # pyflakes 12 | "E", # pycodestyle errors 13 | 14 | # TODO: Add those back progressively as we fix the issues 15 | # "C", # flake8-comprehensions 16 | # "B", # flake8-bugbear 17 | # "UP", # pyupgrade 18 | ] 19 | 20 | # TODO: Add those back progressively as we fix the issues 21 | ignore = ["E501","E203", "E712", "E722", "E713"] 22 | 23 | [tool.ruff.format] 24 | quote-style = 'single' 25 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. dapr-python-sdk documentation master file, created by 2 | sphinx-quickstart on Mon May 25 22:52:51 2020. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | ============================ 7 | Welcome to Dapr-Python-Sdk 8 | ============================ 9 | .. toctree:: 10 | :maxdepth: 4 11 | :caption: Contents: 12 | 13 | actor/modules 14 | client/modules 15 | proto/modules 16 | serializers/modules 17 | 18 | 19 | Indices and tables 20 | ================== 21 | 22 | * :ref:`genindex` 23 | * :ref:`modindex` 24 | * :ref:`search` 25 | -------------------------------------------------------------------------------- /tests/actor/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Copyright 2021 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 | -------------------------------------------------------------------------------- /tests/clients/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Copyright 2021 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 | -------------------------------------------------------------------------------- /dapr/actor/client/__init__.py: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /dapr/actor/runtime/__init__.py: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /dapr/clients/grpc/__init__.py: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /dapr/clients/http/__init__.py: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /dapr/proto/common/__init__.py: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /dapr/proto/runtime/__init__.py: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /examples/invoke-simple/invoke-caller.py: -------------------------------------------------------------------------------- 1 | import json 2 | import time 3 | 4 | from dapr.clients import DaprClient 5 | 6 | with DaprClient() as d: 7 | req_data = {'id': 1, 'message': 'hello world'} 8 | 9 | while True: 10 | # Create a typed message with content type and body 11 | resp = d.invoke_method( 12 | 'invoke-receiver', 13 | 'my-method', 14 | data=json.dumps(req_data), 15 | ) 16 | 17 | # Print the response 18 | print(resp.content_type, flush=True) 19 | print(resp.text(), flush=True) 20 | print(str(resp.status_code), flush=True) 21 | 22 | time.sleep(2) 23 | -------------------------------------------------------------------------------- /tests/serializers/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Copyright 2021 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 | -------------------------------------------------------------------------------- /dapr/aio/clients/grpc/__init__.py: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /dapr/proto/common/v1/__init__.py: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /dapr/proto/runtime/v1/__init__.py: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /ext/dapr-ext-langgraph/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Copyright 2025 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 | -------------------------------------------------------------------------------- /ext/dapr-ext-workflow/tests/__init__.py: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Python Dapr Client SDK Feature Request (not workflow) 3 | about: Create a Feature Request for python-sdk (not dapr-ext-workflow) 4 | title: '[FEATURE REQUEST] <title>' 5 | labels: kind/enhancement 6 | assignees: '' 7 | 8 | --- 9 | ## Describe the feature 10 | 11 | ## Release Note 12 | <!-- How should this new feature be announced in our release notes? It can be populated later. --> 13 | <!-- Keep it as a single line. Examples: --> 14 | 15 | <!-- RELEASE NOTE: **ADD** New feature in Dapr. --> 16 | <!-- RELEASE NOTE: **FIX** Bug in runtime. --> 17 | <!-- RELEASE NOTE: **UPDATE** Runtime dependency. --> 18 | 19 | RELEASE NOTE: 20 | -------------------------------------------------------------------------------- /dapr/version/version.py: -------------------------------------------------------------------------------- 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 | __version__ = '1.16.0.dev' 17 | -------------------------------------------------------------------------------- /ext/flask_dapr/flask_dapr/version.py: -------------------------------------------------------------------------------- 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 | __version__ = '1.16.0.dev' 17 | -------------------------------------------------------------------------------- /ext/dapr-ext-grpc/dapr/ext/grpc/version.py: -------------------------------------------------------------------------------- 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 | __version__ = '1.16.0.dev' 17 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /ext/dapr-ext-fastapi/dapr/ext/fastapi/version.py: -------------------------------------------------------------------------------- 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 | __version__ = '1.16.0.dev' 17 | -------------------------------------------------------------------------------- /ext/dapr-ext-langgraph/dapr/ext/langgraph/version.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Copyright 2025 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 | __version__ = '1.16.0.dev' 17 | -------------------------------------------------------------------------------- /ext/dapr-ext-workflow/dapr/ext/workflow/version.py: -------------------------------------------------------------------------------- 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 | __version__ = '1.16.0.dev' 17 | -------------------------------------------------------------------------------- /examples/grpc_proxying/invoke-caller.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | 4 | import grpc 5 | import helloworld_service_pb2_grpc 6 | from helloworld_service_pb2 import HelloRequest 7 | 8 | 9 | async def run() -> None: 10 | async with grpc.aio.insecure_channel('127.0.0.1:50007') as channel: 11 | metadata = (('dapr-app-id', 'invoke-receiver'),) 12 | stub = helloworld_service_pb2_grpc.HelloWorldServiceStub(channel) 13 | response = await stub.SayHello(request=HelloRequest(name='you'), metadata=metadata) 14 | print('Greeter client received: ' + response.message) 15 | 16 | 17 | if __name__ == '__main__': 18 | print('I am in main') 19 | logging.basicConfig() 20 | asyncio.run(run()) 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/workflow_feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: WORKFLOW SDK Feature Request 3 | about: Create a Feature Request for dapr-ext-workflow 4 | title: '[WORKFLOW SDK FEATURE REQUEST] <title>' 5 | labels: ["kind/enhancement","dapr-ext-workflow"] 6 | assignees: 7 | - cgillum 8 | - DeepanshuA 9 | 10 | --- 11 | ## Describe the WORKFLOW SDK feature 12 | 13 | ## Release Note 14 | <!-- How should this new feature be announced in our release notes? It can be populated later. --> 15 | <!-- Keep it as a single line. Examples: --> 16 | 17 | <!-- RELEASE NOTE: **ADD** New feature in Dapr. --> 18 | <!-- RELEASE NOTE: **FIX** Bug in runtime. --> 19 | <!-- RELEASE NOTE: **UPDATE** Runtime dependency. --> 20 | 21 | RELEASE NOTE: 22 | -------------------------------------------------------------------------------- /dapr/proto/README.md: -------------------------------------------------------------------------------- 1 | ## Generating gRPC interface and Protobuf 2 | 3 | As a good practice create a python virtual environment: 4 | 5 | ```sh 6 | python3 -m venv <env_name> 7 | source <env_name>/bin/activate 8 | ``` 9 | 10 | ### Linux and MacOS 11 | 12 | Run the following commands: 13 | 14 | ```sh 15 | pip3 install -r tools/requirements.txt 16 | export DAPR_BRANCH=release-1.16 # Optional, defaults to master 17 | ./tools/regen_grpcclient.sh 18 | ``` 19 | 20 | > Note: To use the newly generated protobuf stubs and gRPC interface replace `daprd` with `edge` version of `daprd` built from master branch. Refer [this](https://github.com/dapr/dapr/blob/master/docs/development/developing-dapr.md#build-the-dapr-binaries) for instructions on how to build `daprd` from master. 21 | -------------------------------------------------------------------------------- /examples/state_store_query/query.json: -------------------------------------------------------------------------------- 1 | { 2 | "filter": { 3 | "OR": [ 4 | { 5 | "EQ": { "person.org": "Dev Ops" } 6 | }, 7 | { 8 | "AND": [ 9 | { 10 | "EQ": { "person.org": "Finance" } 11 | }, 12 | { 13 | "IN": { "state": [ "CA", "WA" ] } 14 | } 15 | ] 16 | } 17 | ] 18 | }, 19 | "sort": [ 20 | { 21 | "key": "state", 22 | "order": "DESC" 23 | }, 24 | { 25 | "key": "person.id" 26 | } 27 | ], 28 | "page": { 29 | "limit": 3 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ext/flask_dapr/flask_dapr/__init__.py: -------------------------------------------------------------------------------- 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 | from .actor import DaprActor 17 | from .app import DaprApp 18 | 19 | __all__ = ['DaprActor', 'DaprApp'] 20 | -------------------------------------------------------------------------------- /examples/state_store_query/query-token.json: -------------------------------------------------------------------------------- 1 | { 2 | "filter": { 3 | "OR": [ 4 | { 5 | "EQ": { "person.org": "Dev Ops" } 6 | }, 7 | { 8 | "AND": [ 9 | { 10 | "EQ": { "person.org": "Finance" } 11 | }, 12 | { 13 | "IN": { "state": [ "CA", "WA" ] } 14 | } 15 | ] 16 | } 17 | ] 18 | }, 19 | "sort": [ 20 | { 21 | "key": "state", 22 | "order": "DESC" 23 | }, 24 | { 25 | "key": "person.id" 26 | } 27 | ], 28 | "page": { 29 | "limit": 3, 30 | "token": "3" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ext/dapr-ext-fastapi/dapr/ext/fastapi/__init__.py: -------------------------------------------------------------------------------- 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 | from .actor import DaprActor 17 | from .app import DaprApp 18 | 19 | __all__ = ['DaprActor', 'DaprApp'] 20 | -------------------------------------------------------------------------------- /docs/proto/proto.runtime.v1.rst: -------------------------------------------------------------------------------- 1 | proto.runtime.v1 package 2 | ======================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | 8 | .. automodule:: proto.runtime.v1.appcallback_pb2 9 | :members: 10 | :undoc-members: 11 | :show-inheritance: 12 | 13 | 14 | .. automodule:: proto.runtime.v1.appcallback_pb2_grpc 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | 20 | .. automodule:: proto.runtime.v1.dapr_pb2 21 | :members: 22 | :undoc-members: 23 | :show-inheritance: 24 | 25 | 26 | .. automodule:: proto.runtime.v1.dapr_pb2_grpc 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | Module contents 32 | --------------- 33 | 34 | .. automodule:: proto.runtime.v1 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | -------------------------------------------------------------------------------- /ext/dapr-ext-workflow/dapr/ext/workflow/aio/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Copyright 2025 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 | from .dapr_workflow_client import DaprWorkflowClient 17 | 18 | __all__ = [ 19 | 'DaprWorkflowClient', 20 | ] 21 | -------------------------------------------------------------------------------- /examples/grpc_proxying/invoke-receiver.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | import grpc 4 | import helloworld_service_pb2_grpc 5 | from dapr.ext.grpc import App 6 | from helloworld_service_pb2 import HelloReply, HelloRequest 7 | 8 | 9 | class HelloWorldService(helloworld_service_pb2_grpc.HelloWorldService): 10 | def SayHello(self, request: HelloRequest, context: grpc.aio.ServicerContext) -> HelloReply: 11 | logging.info(request) 12 | return HelloReply(message='Hello, %s!' % request.name) 13 | 14 | 15 | app = App() 16 | 17 | if __name__ == '__main__': 18 | print('starting the HelloWorld Service') 19 | logging.basicConfig(level=logging.INFO) 20 | app.add_external_service( 21 | helloworld_service_pb2_grpc.add_HelloWorldServiceServicer_to_server, HelloWorldService() 22 | ) 23 | app.run(50051) 24 | -------------------------------------------------------------------------------- /examples/demo_actor/demo_actor/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Dapr Authors 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | FROM python:3.9-slim-buster 13 | 14 | WORKDIR /app 15 | COPY . . 16 | 17 | RUN pip install -r requirements.txt 18 | 19 | ENTRYPOINT ["python"] 20 | CMD ["demo_actor_service.py"] 21 | -------------------------------------------------------------------------------- /dapr/serializers/__init__.py: -------------------------------------------------------------------------------- 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 | from dapr.serializers.base import Serializer 17 | from dapr.serializers.json import DefaultJSONSerializer 18 | 19 | __all__ = ['Serializer', 'DefaultJSONSerializer'] 20 | -------------------------------------------------------------------------------- /tests/clients/test_http_helpers.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from unittest.mock import patch 3 | 4 | from dapr.clients.http.helpers import get_api_url 5 | from dapr.conf import settings 6 | 7 | 8 | class DaprHttpClientHelpersTests(unittest.TestCase): 9 | def test_get_api_url_default(self, dapr=None): 10 | self.assertEqual( 11 | 'http://{}:{}/{}'.format( 12 | settings.DAPR_RUNTIME_HOST, settings.DAPR_HTTP_PORT, settings.DAPR_API_VERSION 13 | ), 14 | get_api_url(), 15 | ) 16 | 17 | @patch.object(settings, 'DAPR_HTTP_ENDPOINT', 'https://domain1.com:5000') 18 | def test_get_api_url_endpoint_as_env_variable(self): 19 | self.assertEqual( 20 | 'https://domain1.com:5000/{}'.format(settings.DAPR_API_VERSION), 21 | get_api_url(), 22 | ) 23 | -------------------------------------------------------------------------------- /dapr/actor/runtime/reentrancy_context.py: -------------------------------------------------------------------------------- 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 | from contextvars import ContextVar 17 | from typing import Optional 18 | 19 | reentrancy_ctx: ContextVar[Optional[str]] = ContextVar('reentrancy_ctx', default=None) 20 | -------------------------------------------------------------------------------- /ext/dapr-ext-grpc/tests/test_health_servicer.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from unittest.mock import MagicMock 3 | 4 | from dapr.ext.grpc._health_servicer import _HealthCheckServicer 5 | 6 | 7 | class OnInvokeTests(unittest.TestCase): 8 | def setUp(self): 9 | self._health_servicer = _HealthCheckServicer() 10 | 11 | def test_healthcheck_cb_called(self): 12 | health_cb = MagicMock() 13 | self._health_servicer.register_health_check(health_cb) 14 | self._health_servicer.HealthCheck(None, MagicMock()) 15 | health_cb.assert_called_once() 16 | 17 | def test_no_healthcheck_cb(self): 18 | with self.assertRaises(NotImplementedError) as exception_context: 19 | self._health_servicer.HealthCheck(None, MagicMock()) 20 | self.assertIn('Method not implemented!', exception_context.exception.args[0]) 21 | -------------------------------------------------------------------------------- /ext/dapr-ext-langgraph/dapr/ext/langgraph/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Copyright 2025 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 your main classes here 17 | from dapr.ext.langgraph.dapr_checkpointer import DaprCheckpointer 18 | 19 | __all__ = [ 20 | 'DaprCheckpointer', 21 | ] 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Dapr Discord Python SDK channel 4 | url: https://discord.com/channels/778680217417809931/782286950983663617 5 | about: Please use this channel for general Dapr Python SDK questions. 6 | - name: Dapr Discord Workflow SDK channel 7 | url: https://discord.com/channels/778680217417809931/1075836407156850698 8 | about: Please use this channel for general Dapr Workflow questions. 9 | - name: Dapr Community Support (Discord Invitation, Community meetings, etc.) 10 | url: https://github.com/dapr/community 11 | about: More information about the Dapr community and how to get involved. 12 | - name: Reporting security issues 13 | url: https://docs.dapr.io/operations/support/support-security-issues/ 14 | about: Please report security vulnerabilities here. -------------------------------------------------------------------------------- /examples/invoke-http/invoke-receiver.py: -------------------------------------------------------------------------------- 1 | # from dapr.ext.grpc import App, InvokeMethodRequest, InvokeMethodResponse 2 | import json 3 | 4 | from flask import Flask, request 5 | 6 | app = Flask(__name__) 7 | 8 | 9 | @app.route('/my-method', methods=['POST']) 10 | def getOrder(): 11 | data = request.json 12 | print('Order received : ' + json.dumps(data), flush=True) 13 | return json.dumps({'success': True}), 200, {'ContentType': 'application/json'} 14 | 15 | 16 | @app.route('/my-method-err', methods=['POST']) 17 | def getOrderErr(): 18 | data = request.json 19 | print('Order error : ' + json.dumps(data), flush=True) 20 | resp = {'message': 'error occurred', 'errorCode': 'MY_CODE'} 21 | return json.dumps(resp), 503, {'ContentType': 'application/json'} 22 | 23 | 24 | print('Starting Flask app on port 8088...', flush=True) 25 | app.run(port=8088) 26 | -------------------------------------------------------------------------------- /examples/state_store_query/state_store_query.py: -------------------------------------------------------------------------------- 1 | """ 2 | dapr run python3 state_store_query.py 3 | """ 4 | 5 | import json 6 | 7 | from dapr.clients import DaprClient 8 | 9 | with DaprClient() as d: 10 | store_name = 'statestore' 11 | 12 | # Query the state store 13 | 14 | query = open('query.json', 'r').read() 15 | res = d.query_state(store_name=store_name, query=query) 16 | for r in res.results: 17 | print(r.key, json.dumps(json.loads(str(r.value, 'UTF-8')), sort_keys=True)) 18 | print('Token:', res.token) 19 | 20 | # Get more results using a pagination token 21 | 22 | query = open('query-token.json', 'r').read() 23 | res = d.query_state(store_name=store_name, query=query) 24 | for r in res.results: 25 | print(r.key, json.dumps(json.loads(str(r.value, 'UTF-8')), sort_keys=True)) 26 | print('Token:', res.token) 27 | -------------------------------------------------------------------------------- /dapr/clients/http/conf.py: -------------------------------------------------------------------------------- 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 | from dapr.version import __version__ 17 | 18 | CONTENT_TYPE_HEADER = 'content-type' 19 | DAPR_API_TOKEN_HEADER = 'dapr-api-token' 20 | USER_AGENT_HEADER = 'User-Agent' 21 | DAPR_USER_AGENT = f'dapr-sdk-python/{__version__}' 22 | -------------------------------------------------------------------------------- /ext/flask_dapr/README.rst: -------------------------------------------------------------------------------- 1 | Dapr flask extension 2 | ==================== 3 | 4 | |pypi| 5 | 6 | .. |pypi| image:: https://badge.fury.io/py/flask-dapr.svg 7 | :target: https://pypi.org/project/flask-dapr/ 8 | 9 | This flask extension is used to: 10 | - run the actor service 11 | - subscribe to PubSub events 12 | 13 | Installation 14 | ------------ 15 | 16 | :: 17 | 18 | pip install flask-dapr 19 | 20 | PubSub Events 21 | ------------- 22 | 23 | ```python 24 | from flask import Flask, request 25 | from flask_dapr import DaprApp 26 | 27 | app = Flask('myapp') 28 | dapr_app = DaprApp(app) 29 | @dapr_app.subscribe(pubsub='pubsub', topic='some_topic', route='/some_endpoint') 30 | def my_event_handler(): 31 | # request.data contains pubsub event 32 | pass 33 | ``` 34 | 35 | References 36 | ---------- 37 | 38 | * `Dapr <https://github.com/dapr/dapr>`_ 39 | * `Dapr Python-SDK <https://github.com/dapr/python-sdk>`_ 40 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Python Dapr Client SDK Bug report (not workflow SDK) 3 | about: Report a bug in python-sdk (not dapr-ext-workflow) 4 | title: '[BUG] <title>' 5 | labels: kind/bug 6 | assignees: '' 7 | 8 | --- 9 | ## Expected Behavior 10 | 11 | <!-- Briefly describe what you expect to happen --> 12 | 13 | 14 | ## Actual Behavior 15 | 16 | <!-- Briefly describe what is actually happening --> 17 | 18 | 19 | ## Steps to Reproduce the Problem 20 | 21 | <!-- How can a maintainer reproduce this issue (be detailed) --> 22 | 23 | ## Release Note 24 | <!-- How should the fix for this issue be communicated in our release notes? It can be populated later. --> 25 | <!-- Keep it as a single line. Examples: --> 26 | 27 | <!-- RELEASE NOTE: **ADD** New feature in Dapr. --> 28 | <!-- RELEASE NOTE: **FIX** Bug in runtime. --> 29 | <!-- RELEASE NOTE: **UPDATE** Runtime dependency. --> 30 | 31 | RELEASE NOTE: 32 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/workflow_bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: WORKFLOW SDK Bug report 3 | about: Report a bug in dapr-ext-workflow 4 | title: '[WORKFLOW SDK BUG] <title>' 5 | labels: ["kind/enhancement","dapr-ext-workflow"] 6 | assignees: 7 | - cgillum 8 | - DeepanshuA 9 | 10 | --- 11 | ## Expected Behavior 12 | 13 | <!-- Briefly describe what you expect to happen --> 14 | 15 | 16 | ## Actual Behavior 17 | 18 | <!-- Briefly describe what is actually happening --> 19 | 20 | 21 | ## Steps to Reproduce the Problem 22 | 23 | <!-- How can a maintainer reproduce this issue (be detailed) --> 24 | 25 | ## Release Note 26 | <!-- How should the fix for this issue be communicated in our release notes? It can be populated later. --> 27 | <!-- Keep it as a single line. Examples: --> 28 | 29 | <!-- RELEASE NOTE: **ADD** New feature in Dapr. --> 30 | <!-- RELEASE NOTE: **FIX** Bug in runtime. --> 31 | <!-- RELEASE NOTE: **UPDATE** Runtime dependency. --> 32 | 33 | RELEASE NOTE: 34 | -------------------------------------------------------------------------------- /dapr/clients/http/helpers.py: -------------------------------------------------------------------------------- 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 | from dapr.conf import settings 17 | 18 | 19 | def get_api_url() -> str: 20 | if settings.DAPR_HTTP_ENDPOINT: 21 | return '{}/{}'.format(settings.DAPR_HTTP_ENDPOINT, settings.DAPR_API_VERSION) 22 | 23 | return 'http://{}:{}/{}'.format( 24 | settings.DAPR_RUNTIME_HOST, settings.DAPR_HTTP_PORT, settings.DAPR_API_VERSION 25 | ) 26 | -------------------------------------------------------------------------------- /dapr/clients/_constants.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Copyright 2025 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 | """ 17 | Internal constants for the Dapr clients package. 18 | 19 | This module contains shared constants that can be imported by various 20 | client modules without creating circular dependencies. 21 | """ 22 | 23 | # Encoding and content type constants 24 | DEFAULT_ENCODING = 'utf-8' 25 | DEFAULT_JSON_CONTENT_TYPE = f'application/json; charset={DEFAULT_ENCODING}' 26 | -------------------------------------------------------------------------------- /ext/flask_dapr/setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | url = https://dapr.io/ 3 | author = Dapr Authors 4 | author_email = daprweb@microsoft.com 5 | license = Apache 6 | license_file = LICENSE 7 | classifiers = 8 | Development Status :: 5 - Production/Stable 9 | Intended Audience :: Developers 10 | License :: OSI Approved :: Apache Software License 11 | Operating System :: OS Independent 12 | Programming Language :: Python 13 | Programming Language :: Python :: 3.9 14 | Programming Language :: Python :: 3.10 15 | Programming Language :: Python :: 3.11 16 | Programming Language :: Python :: 3.12 17 | Programming Language :: Python :: 3.13 18 | project_urls = 19 | Documentation = https://github.com/dapr/docs 20 | Source = https://github.com/dapr/python-sdk 21 | 22 | [options] 23 | python_requires = >=3.9 24 | packages = find: 25 | include_package_data = true 26 | zip_safe = false 27 | install_requires = 28 | Flask >= 1.1 29 | dapr >= 1.16.0.dev 30 | 31 | [options.package_data] 32 | flask_dapr = 33 | py.typed 34 | -------------------------------------------------------------------------------- /ext/dapr-ext-grpc/setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | url = https://dapr.io/ 3 | author = Dapr Authors 4 | author_email = daprweb@microsoft.com 5 | license = Apache 6 | license_file = LICENSE 7 | classifiers = 8 | Development Status :: 5 - Production/Stable 9 | Intended Audience :: Developers 10 | License :: OSI Approved :: Apache Software License 11 | Operating System :: OS Independent 12 | Programming Language :: Python 13 | Programming Language :: Python :: 3.9 14 | Programming Language :: Python :: 3.10 15 | Programming Language :: Python :: 3.11 16 | Programming Language :: Python :: 3.12 17 | Programming Language :: Python :: 3.13 18 | project_urls = 19 | Documentation = https://github.com/dapr/docs 20 | Source = https://github.com/dapr/python-sdk 21 | 22 | [options] 23 | python_requires = >=3.9 24 | packages = find_namespace: 25 | include_package_data = True 26 | install_requires = 27 | dapr >= 1.16.0.dev 28 | cloudevents >= 1.0.0 29 | 30 | [options.packages.find] 31 | include = 32 | dapr.* 33 | 34 | exclude = 35 | tests 36 | 37 | [options.package_data] 38 | dapr.ext.grpc = 39 | py.typed -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/vscode-remote/devcontainer.json. 2 | { 3 | "name": "Dapr - Python SDK", 4 | "context": "..", 5 | "dockerFile": "Dockerfile", 6 | 7 | // Set *default* container specific settings.json values on container create. 8 | "settings": { 9 | "terminal.integrated.shell.linux": "/bin/bash", 10 | "python.pythonPath": "/usr/local/bin/python", 11 | "python.linting.enabled": true, 12 | "python.linting.mypyEnabled": true, 13 | }, 14 | 15 | // Add the IDs of extensions you want installed when the container is created. 16 | "extensions": [ 17 | "ms-python.python", 18 | "ms-azuretools.vscode-dapr" 19 | ], 20 | 21 | "mounts": [ 22 | "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind", 23 | ], 24 | 25 | "postCreateCommand": ".devcontainer/postCreateCommand.sh", 26 | 27 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 28 | // "forwardPorts": [], 29 | // Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root. 30 | // "remoteUser": "vscode" 31 | } 32 | -------------------------------------------------------------------------------- /ext/dapr-ext-workflow/setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | url = https://dapr.io/ 3 | author = Dapr Authors 4 | author_email = daprweb@microsoft.com 5 | license = Apache 6 | license_file = LICENSE 7 | classifiers = 8 | Development Status :: 5 - Production/Stable 9 | Intended Audience :: Developers 10 | License :: OSI Approved :: Apache Software License 11 | Operating System :: OS Independent 12 | Programming Language :: Python 13 | Programming Language :: Python :: 3.9 14 | Programming Language :: Python :: 3.10 15 | Programming Language :: Python :: 3.11 16 | Programming Language :: Python :: 3.12 17 | Programming Language :: Python :: 3.13 18 | project_urls = 19 | Documentation = https://github.com/dapr/docs 20 | Source = https://github.com/dapr/python-sdk 21 | 22 | [options] 23 | python_requires = >=3.9 24 | packages = find_namespace: 25 | include_package_data = True 26 | install_requires = 27 | dapr >= 1.16.0.dev 28 | durabletask-dapr >= 0.2.0a12 29 | 30 | [options.packages.find] 31 | include = 32 | dapr.* 33 | 34 | exclude = 35 | tests 36 | 37 | [options.package_data] 38 | dapr.ext.workflow = 39 | py.typed 40 | -------------------------------------------------------------------------------- /ext/dapr-ext-fastapi/setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | url = https://dapr.io/ 3 | author = Dapr Authors 4 | author_email = daprweb@microsoft.com 5 | license = Apache 6 | license_file = LICENSE 7 | classifiers = 8 | Development Status :: 5 - Production/Stable 9 | Intended Audience :: Developers 10 | License :: OSI Approved :: Apache Software License 11 | Operating System :: OS Independent 12 | Programming Language :: Python 13 | Programming Language :: Python :: 3.9 14 | Programming Language :: Python :: 3.10 15 | Programming Language :: Python :: 3.11 16 | Programming Language :: Python :: 3.12 17 | Programming Language :: Python :: 3.13 18 | project_urls = 19 | Documentation = https://github.com/dapr/docs 20 | Source = https://github.com/dapr/python-sdk 21 | 22 | [options] 23 | python_requires = >=3.9 24 | packages = find_namespace: 25 | include_package_data = True 26 | install_requires = 27 | dapr >= 1.16.0.dev 28 | uvicorn >= 0.11.6 29 | fastapi >= 0.60.1 30 | 31 | [options.packages.find] 32 | include = 33 | dapr.* 34 | 35 | exclude = 36 | tests 37 | 38 | [options.package_data] 39 | dapr.ext.fastapi = 40 | py.typed 41 | -------------------------------------------------------------------------------- /examples/invoke-binding/docker-compose-single-kafka.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------ 2 | # Copyright 2021 The Dapr Authors 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | # ------------------------------------------------------------ 13 | 14 | version: '2' 15 | services: 16 | zookeeper: 17 | image: wurstmeister/zookeeper:latest 18 | ports: 19 | - "2181:2181" 20 | kafka: 21 | image: wurstmeister/kafka:latest 22 | ports: 23 | - "9092:9092" 24 | environment: 25 | KAFKA_ADVERTISED_HOST_NAME: 127.0.0.1 26 | KAFKA_CREATE_TOPICS: "sample:1:1" 27 | KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 28 | -------------------------------------------------------------------------------- /dapr/actor/__init__.py: -------------------------------------------------------------------------------- 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 | from dapr.actor.actor_interface import ActorInterface, actormethod 17 | from dapr.actor.client.proxy import ActorProxy, ActorProxyFactory 18 | from dapr.actor.id import ActorId 19 | from dapr.actor.runtime.actor import Actor 20 | from dapr.actor.runtime.remindable import Remindable 21 | from dapr.actor.runtime.runtime import ActorRuntime 22 | 23 | __all__ = [ 24 | 'ActorInterface', 25 | 'ActorProxy', 26 | 'ActorProxyFactory', 27 | 'ActorId', 28 | 'Actor', 29 | 'ActorRuntime', 30 | 'Remindable', 31 | 'actormethod', 32 | ] 33 | -------------------------------------------------------------------------------- /ext/dapr-ext-workflow/dapr/ext/workflow/util.py: -------------------------------------------------------------------------------- 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 | from typing import Optional 17 | 18 | from dapr.conf import settings 19 | 20 | 21 | def getAddress(host: Optional[str] = None, port: Optional[str] = None) -> str: 22 | if not host and not port: 23 | address = settings.DAPR_GRPC_ENDPOINT or ( 24 | f'{settings.DAPR_RUNTIME_HOST}:{settings.DAPR_GRPC_PORT}' 25 | ) 26 | else: 27 | host = host or settings.DAPR_RUNTIME_HOST 28 | port = port or settings.DAPR_GRPC_PORT 29 | address = f'{host}:{port}' 30 | 31 | return address 32 | -------------------------------------------------------------------------------- /dapr/serializers/base.py: -------------------------------------------------------------------------------- 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 | from abc import ABC, abstractmethod 17 | from typing import Any, Callable, Optional, Type 18 | 19 | 20 | class Serializer(ABC): 21 | """Serializer base class.""" 22 | 23 | @abstractmethod 24 | def serialize( 25 | self, obj: object, custom_hook: Optional[Callable[[object], bytes]] = None 26 | ) -> bytes: ... 27 | 28 | @abstractmethod 29 | def deserialize( 30 | self, 31 | data: bytes, 32 | data_type: Optional[Type] = object, 33 | custom_hook: Optional[Callable[[bytes], object]] = None, 34 | ) -> Any: ... 35 | -------------------------------------------------------------------------------- /examples/invoke-http/invoke-caller.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from dapr.clients import DaprClient 4 | from dapr.clients.exceptions import DaprHttpError 5 | 6 | with DaprClient() as d: 7 | req_data = {'id': 1, 'message': 'hello world'} 8 | 9 | # First message: success 10 | # Create a typed message with content type and body 11 | resp1 = d.invoke_method( 12 | 'invoke-receiver', 13 | 'my-method', 14 | http_verb='POST', 15 | data=json.dumps(req_data), 16 | ) 17 | 18 | # Print the response 19 | print(resp1.content_type, flush=True) 20 | print(resp1.text(), flush=True) 21 | print(str(resp1.status_code), flush=True) 22 | 23 | # Second message: error 24 | req_data = {'id': 2, 'message': 'hello world'} 25 | try: 26 | resp2 = d.invoke_method( 27 | 'invoke-receiver', 28 | 'my-method-err', 29 | http_verb='POST', 30 | data=json.dumps(req_data), 31 | ) 32 | except DaprHttpError as e: 33 | print(e.message, flush=True) 34 | print(e.error_code, flush=True) 35 | print(e.raw_response_bytes, flush=True) 36 | print(str(e.status_code), flush=True) 37 | print(e.reason, flush=True) 38 | -------------------------------------------------------------------------------- /ext/dapr-ext-langgraph/setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | url = https://dapr.io/ 3 | author = Dapr Authors 4 | author_email = daprweb@microsoft.com 5 | license = Apache 6 | license_file = LICENSE 7 | classifiers = 8 | Development Status :: 5 - Production/Stable 9 | Intended Audience :: Developers 10 | License :: OSI Approved :: Apache Software License 11 | Operating System :: OS Independent 12 | Programming Language :: Python 13 | Programming Language :: Python :: 3.10 14 | Programming Language :: Python :: 3.11 15 | Programming Language :: Python :: 3.12 16 | Programming Language :: Python :: 3.13 17 | Programming Language :: Python :: 3.14 18 | project_urls = 19 | Documentation = https://github.com/dapr/docs 20 | Source = https://github.com/dapr/python-sdk 21 | 22 | [options] 23 | python_requires = >=3.10 24 | packages = find_namespace: 25 | include_package_data = True 26 | install_requires = 27 | dapr >= 1.16.1rc1 28 | langgraph >= 0.3.6 29 | langchain >= 0.1.17 30 | python-ulid >= 3.0.0 31 | msgpack-python >= 0.4.5 32 | 33 | [options.packages.find] 34 | include = 35 | dapr.* 36 | 37 | exclude = 38 | tests 39 | 40 | [options.package_data] 41 | dapr.ext.langgraph = 42 | py.typed -------------------------------------------------------------------------------- /ext/dapr-ext-grpc/dapr/ext/grpc/_health_servicer.py: -------------------------------------------------------------------------------- 1 | from typing import Callable, Optional 2 | 3 | import grpc 4 | from dapr.proto import appcallback_service_v1 5 | from dapr.proto.runtime.v1.appcallback_pb2 import HealthCheckResponse 6 | 7 | HealthCheckCallable = Optional[Callable[[], None]] 8 | 9 | 10 | class _HealthCheckServicer(appcallback_service_v1.AppCallbackHealthCheckServicer): 11 | """The implementation of HealthCheck Server. 12 | 13 | :class:`App` provides useful decorators to register method, topic, input bindings. 14 | """ 15 | 16 | def __init__(self): 17 | self._health_check_cb: Optional[HealthCheckCallable] = None 18 | 19 | def register_health_check(self, cb: HealthCheckCallable) -> None: 20 | if not cb: 21 | raise ValueError('health check callback must be defined') 22 | self._health_check_cb = cb 23 | 24 | def HealthCheck(self, request, context): 25 | """Health check.""" 26 | 27 | if not self._health_check_cb: 28 | context.set_code(grpc.StatusCode.UNIMPLEMENTED) # type: ignore 29 | context.set_details('Method not implemented!') 30 | raise NotImplementedError('Method not implemented!') 31 | self._health_check_cb() 32 | return HealthCheckResponse() 33 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | url = https://dapr.io/ 3 | author = Dapr Authors 4 | author_email = dapr@dapr.io 5 | license = Apache 6 | license_file = LICENSE 7 | classifiers = 8 | Development Status :: 5 - Production/Stable 9 | Intended Audience :: Developers 10 | License :: OSI Approved :: Apache Software License 11 | Operating System :: OS Independent 12 | Programming Language :: Python 13 | Programming Language :: Python :: 3.9 14 | Programming Language :: Python :: 3.10 15 | Programming Language :: Python :: 3.11 16 | Programming Language :: Python :: 3.12 17 | Programming Language :: Python :: 3.13 18 | project_urls = 19 | Documentation = https://github.com/dapr/docs 20 | Source = https://github.com/dapr/python-sdk 21 | 22 | [options] 23 | python_requires = >=3.9 24 | packages = find_namespace: 25 | include_package_data = True 26 | zip_safe = False 27 | install_requires = 28 | protobuf >= 4.22 29 | grpcio >= 1.37.0 30 | grpcio-status>=1.37.0 31 | aiohttp >= 3.9.0b0 32 | python-dateutil >= 2.8.1 33 | typing-extensions>=4.4.0 34 | 35 | [options.packages.find] 36 | include = 37 | dapr 38 | dapr.* 39 | exclude = 40 | ext 41 | examples 42 | tests 43 | 44 | [options.package_data] 45 | dapr = 46 | py.typed 47 | -------------------------------------------------------------------------------- /ext/dapr-ext-grpc/dapr/ext/grpc/__init__.py: -------------------------------------------------------------------------------- 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 | from dapr.ext.grpc.app import App, Rule # type:ignore 17 | 18 | from dapr.clients.grpc._jobs import ConstantFailurePolicy, DropFailurePolicy, FailurePolicy, Job 19 | from dapr.clients.grpc._request import BindingRequest, InvokeMethodRequest, JobEvent 20 | from dapr.clients.grpc._response import InvokeMethodResponse, TopicEventResponse 21 | 22 | __all__ = [ 23 | 'App', 24 | 'Rule', 25 | 'InvokeMethodRequest', 26 | 'InvokeMethodResponse', 27 | 'BindingRequest', 28 | 'TopicEventResponse', 29 | 'Job', 30 | 'JobEvent', 31 | 'FailurePolicy', 32 | 'DropFailurePolicy', 33 | 'ConstantFailurePolicy', 34 | ] 35 | -------------------------------------------------------------------------------- /dapr/actor/runtime/_call_type.py: -------------------------------------------------------------------------------- 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 | from enum import Enum 17 | 18 | 19 | class ActorCallType(Enum): 20 | """A enumeration that represents the call-type associated with the actor method. 21 | :class:`ActorMethodContext` includes :class:`ActorCallType` passing to 22 | :meth:`Actor._on_pre_actor_method` and :meth:`Actor._on_post_actor_method` 23 | """ 24 | 25 | # Specifies that the method invoked is an actor interface method for a given client request. 26 | actor_interface_method = 0 27 | # Specifies that the method invoked is a timer callback method. 28 | timer_method = 1 29 | # Specifies that the method is when a reminder fires. 30 | reminder_method = 2 31 | -------------------------------------------------------------------------------- /examples/invoke-simple/deploy/invoke-caller.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Dapr Authors 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | apiVersion: apps/v1 13 | kind: Deployment 14 | metadata: 15 | name: invokecaller 16 | labels: 17 | app: invokecaller 18 | spec: 19 | replicas: 1 20 | selector: 21 | matchLabels: 22 | app: invokecaller 23 | template: 24 | metadata: 25 | labels: 26 | app: invokecaller 27 | annotations: 28 | dapr.io/enabled: "true" 29 | dapr.io/app-id: "invoke-caller" 30 | dapr.io/app-protocol: "grpc" 31 | spec: 32 | containers: 33 | - name: invokecaller 34 | image: invokesimple:latest # EDIT HERE: Replace the image name 35 | command: ["python"] 36 | args: ["/app/invoke-caller.py"] 37 | imagePullPolicy: Always 38 | -------------------------------------------------------------------------------- /examples/grpc_proxying/deploy/invoke-caller.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Dapr Authors 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | apiVersion: apps/v1 13 | kind: Deployment 14 | metadata: 15 | name: invokecaller 16 | labels: 17 | app: invokecaller 18 | spec: 19 | replicas: 1 20 | selector: 21 | matchLabels: 22 | app: invokecaller 23 | template: 24 | metadata: 25 | labels: 26 | app: invokecaller 27 | annotations: 28 | dapr.io/enabled: "true" 29 | dapr.io/app-id: "invoke-caller" 30 | dapr.io/app-protocol: "grpc" 31 | spec: 32 | containers: 33 | - name: invokecaller 34 | image: invokegrpcproxy:latest # EDIT HERE: Replace the image name 35 | command: ["python"] 36 | args: ["/app/invoke-caller.py"] 37 | imagePullPolicy: Always 38 | -------------------------------------------------------------------------------- /ext/dapr-ext-workflow/tests/test_workflow_util.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from unittest.mock import patch 3 | 4 | from dapr.ext.workflow.util import getAddress 5 | 6 | from dapr.conf import settings 7 | 8 | 9 | class DaprWorkflowUtilTest(unittest.TestCase): 10 | def test_get_address_default(self): 11 | expected = f'{settings.DAPR_RUNTIME_HOST}:{settings.DAPR_GRPC_PORT}' 12 | self.assertEqual(expected, getAddress()) 13 | 14 | def test_get_address_with_constructor_arguments(self): 15 | self.assertEqual('test.com:5000', getAddress('test.com', '5000')) 16 | 17 | def test_get_address_with_partial_constructor_arguments(self): 18 | expected = f'{settings.DAPR_RUNTIME_HOST}:5000' 19 | self.assertEqual(expected, getAddress(port='5000')) 20 | 21 | expected = f'test.com:{settings.DAPR_GRPC_PORT}' 22 | self.assertEqual(expected, getAddress(host='test.com')) 23 | 24 | @patch.object(settings, 'DAPR_GRPC_ENDPOINT', 'https://domain1.com:5000') 25 | def test_get_address_with_constructor_arguments_and_env_variable(self): 26 | self.assertEqual('test.com:5000', getAddress('test.com', '5000')) 27 | 28 | @patch.object(settings, 'DAPR_GRPC_ENDPOINT', 'https://domain1.com:5000') 29 | def test_get_address_with_env_variable(self): 30 | self.assertEqual('https://domain1.com:5000', getAddress()) 31 | -------------------------------------------------------------------------------- /ext/dapr-ext-workflow/dapr/ext/workflow/logger/logger.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from typing import Union 3 | 4 | from dapr.ext.workflow.logger.options import LoggerOptions 5 | 6 | 7 | class Logger: 8 | def __init__(self, name: str, options: Union[LoggerOptions, None] = None): 9 | # If options is None, then create a new LoggerOptions object 10 | if options is None: 11 | options = LoggerOptions() 12 | log_handler = options.log_handler 13 | log_handler.setLevel(options.log_level) 14 | log_handler.setFormatter(options.log_formatter) 15 | logger = logging.getLogger(name) 16 | logger.handlers.append(log_handler) 17 | self._logger_options = options 18 | self._logger = logger 19 | 20 | def get_options(self) -> LoggerOptions: 21 | return self._logger_options 22 | 23 | def debug(self, msg, *args, **kwargs): 24 | self._logger.debug(msg, *args, **kwargs) 25 | 26 | def info(self, msg, *args, **kwargs): 27 | self._logger.info(msg, *args, **kwargs) 28 | 29 | def warning(self, msg, *args, **kwargs): 30 | self._logger.warning(msg, *args, **kwargs) 31 | 32 | def error(self, msg, *args, **kwargs): 33 | self._logger.error(msg, *args, **kwargs) 34 | 35 | def critical(self, msg, *args, **kwargs): 36 | self._logger.critical(msg, *args, **kwargs) 37 | -------------------------------------------------------------------------------- /examples/workflow/cross-app3.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2025 The Dapr Authors 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | import os 13 | import time 14 | 15 | import dapr.ext.workflow as wf 16 | 17 | wfr = wf.WorkflowRuntime() 18 | 19 | 20 | @wfr.activity 21 | def app3_activity(ctx: wf.DaprWorkflowContext) -> int: 22 | print('app3 - received activity call', flush=True) 23 | if os.getenv('ERROR_ACTIVITY_MODE', 'false') == 'true': 24 | print('app3 - raising error in activity due to error mode being enabled', flush=True) 25 | raise ValueError('Error in activity due to error mode being enabled') 26 | print('app3 - returning activity result', flush=True) 27 | return 3 28 | 29 | 30 | if __name__ == '__main__': 31 | wfr.start() 32 | time.sleep(15) # wait for workflow runtime to start 33 | wfr.shutdown() 34 | -------------------------------------------------------------------------------- /examples/demo_actor/deploy/demo_actor_client.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Dapr Authors 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | apiVersion: apps/v1 13 | kind: Deployment 14 | metadata: 15 | name: demoactor-client-app 16 | labels: 17 | app: demoactor-client 18 | spec: 19 | replicas: 1 20 | selector: 21 | matchLabels: 22 | app: demoactor-client 23 | template: 24 | metadata: 25 | labels: 26 | app: demoactor-client 27 | annotations: 28 | dapr.io/enabled: "true" 29 | dapr.io/app-id: "demoactor-client" 30 | spec: 31 | containers: 32 | - name: demoactor-client 33 | image: demo_actor:latest # EDIT HERE: Replace the image nmae with [docker registry]/demo_actor:latest 34 | command: ["python"] 35 | args: ["/app/demo_actor_client.py"] 36 | imagePullPolicy: Always 37 | -------------------------------------------------------------------------------- /examples/pubsub-streaming/subscriber-handler.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import time 3 | 4 | from dapr.clients import DaprClient 5 | from dapr.clients.grpc._response import TopicEventResponse 6 | 7 | counter = 0 8 | 9 | parser = argparse.ArgumentParser(description='Publish events to a Dapr pub/sub topic.') 10 | parser.add_argument('--topic', type=str, required=True, help='The topic name to publish to.') 11 | args = parser.parse_args() 12 | 13 | topic_name = args.topic 14 | dlq_topic_name = topic_name + '_DEAD' 15 | 16 | 17 | def process_message(message): 18 | # Process the message here 19 | global counter 20 | counter += 1 21 | print(f'Processing message: {message.data()} from {message.topic()}...', flush=True) 22 | return TopicEventResponse('success') 23 | 24 | 25 | def main(): 26 | with DaprClient() as client: 27 | # This will start a new thread that will listen for messages 28 | # and process them in the `process_message` function 29 | close_fn = client.subscribe_with_handler( 30 | pubsub_name='pubsub', 31 | topic=topic_name, 32 | handler_fn=process_message, 33 | dead_letter_topic=dlq_topic_name, 34 | ) 35 | 36 | while counter < 5: 37 | time.sleep(1) 38 | 39 | print('Closing subscription...') 40 | close_fn() 41 | 42 | 43 | if __name__ == '__main__': 44 | main() 45 | -------------------------------------------------------------------------------- /examples/invoke-simple/deploy/invoke-receiver.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Dapr Authors 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | apiVersion: apps/v1 13 | kind: Deployment 14 | metadata: 15 | name: invokereceiver 16 | labels: 17 | app: invokereceiver 18 | spec: 19 | replicas: 1 20 | selector: 21 | matchLabels: 22 | app: invokereceiver 23 | template: 24 | metadata: 25 | labels: 26 | app: invokereceiver 27 | annotations: 28 | dapr.io/enabled: "true" 29 | dapr.io/app-id: "invoke-receiver" 30 | dapr.io/app-protocol: "grpc" 31 | dapr.io/app-port: "50051" 32 | spec: 33 | containers: 34 | - name: invokereceiver 35 | image: invokesimple:latest # EDIT HERE: Replace the image name 36 | command: ["python"] 37 | args: ["/app/invoke-receiver.py"] 38 | ports: 39 | - containerPort: 3000 40 | imagePullPolicy: Always 41 | -------------------------------------------------------------------------------- /examples/grpc_proxying/deploy/invoke-receiver.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Dapr Authors 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | apiVersion: apps/v1 13 | kind: Deployment 14 | metadata: 15 | name: invokereceiver 16 | labels: 17 | app: invokereceiver 18 | spec: 19 | replicas: 1 20 | selector: 21 | matchLabels: 22 | app: invokereceiver 23 | template: 24 | metadata: 25 | labels: 26 | app: invokereceiver 27 | annotations: 28 | dapr.io/enabled: "true" 29 | dapr.io/app-id: "invoke-receiver" 30 | dapr.io/app-protocol: "grpc" 31 | dapr.io/app-port: "50051" 32 | spec: 33 | containers: 34 | - name: invokereceiver 35 | image: invokegrpcproxy:latest # EDIT HERE: Replace the image name 36 | command: ["python"] 37 | args: ["/app/invoke-receiver.py"] 38 | ports: 39 | - containerPort: 50051 40 | imagePullPolicy: Always 41 | -------------------------------------------------------------------------------- /examples/secret_store/example.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------ 2 | # Copyright 2021 The Dapr Authors 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | # ------------------------------------------------------------ 13 | 14 | from dapr.clients import DaprClient 15 | 16 | with DaprClient() as d: 17 | key = 'secretKey' 18 | randomKey = 'random' 19 | storeName = 'localsecretstore' 20 | 21 | resp = d.get_secret(store_name=storeName, key=key) 22 | print('Got!') 23 | print(resp.secret) 24 | resp = d.get_bulk_secret(store_name=storeName) 25 | print('Got!') 26 | # Converts dict into sorted list of tuples for deterministic output. 27 | print(sorted(resp.secrets.items())) 28 | try: 29 | resp = d.get_secret(store_name=storeName, key=randomKey) 30 | print('Got!') 31 | print(resp.secret) 32 | except: 33 | print('Got expected error for accessing random key') 34 | -------------------------------------------------------------------------------- /examples/demo_actor/deploy/demo_actor_service.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Dapr Authors 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | apiVersion: apps/v1 13 | kind: Deployment 14 | metadata: 15 | name: demoactorapp 16 | labels: 17 | app: demoactor 18 | spec: 19 | replicas: 1 20 | selector: 21 | matchLabels: 22 | app: demoactor 23 | template: 24 | metadata: 25 | labels: 26 | app: demoactor 27 | annotations: 28 | dapr.io/enabled: "true" 29 | dapr.io/app-id: "demoactor" 30 | dapr.io/app-port: "3000" 31 | spec: 32 | containers: 33 | - name: demoactor 34 | image: demo_actor:latest # EDIT HERE: Replace the image nmae with [docker registry]/demo_actor:latest 35 | command: ["uvicorn"] 36 | args: ["--port", "3000", "--reload-dir", "/app", "demo_actor_service:app"] 37 | ports: 38 | - containerPort: 3000 39 | imagePullPolicy: Always 40 | -------------------------------------------------------------------------------- /ext/dapr-ext-workflow/dapr/ext/workflow/__init__.py: -------------------------------------------------------------------------------- 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 your main classes here 17 | from dapr.ext.workflow.dapr_workflow_client import DaprWorkflowClient 18 | from dapr.ext.workflow.dapr_workflow_context import DaprWorkflowContext, when_all, when_any 19 | from dapr.ext.workflow.retry_policy import RetryPolicy 20 | from dapr.ext.workflow.workflow_activity_context import WorkflowActivityContext 21 | from dapr.ext.workflow.workflow_runtime import WorkflowRuntime, alternate_name 22 | from dapr.ext.workflow.workflow_state import WorkflowState, WorkflowStatus 23 | 24 | __all__ = [ 25 | 'WorkflowRuntime', 26 | 'DaprWorkflowClient', 27 | 'DaprWorkflowContext', 28 | 'WorkflowActivityContext', 29 | 'WorkflowState', 30 | 'WorkflowStatus', 31 | 'when_all', 32 | 'when_any', 33 | 'alternate_name', 34 | 'RetryPolicy', 35 | ] 36 | -------------------------------------------------------------------------------- /examples/conversation/conversation_alpha1.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------ 2 | # Copyright 2025 The Dapr Authors 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | # ------------------------------------------------------------ 13 | from dapr.clients import DaprClient 14 | from dapr.clients.grpc.conversation import ConversationInput 15 | 16 | with DaprClient() as d: 17 | inputs = [ 18 | ConversationInput(content="What's Dapr?", role='user', scrub_pii=True), 19 | ConversationInput(content='Give a brief overview.', role='user', scrub_pii=True), 20 | ] 21 | 22 | metadata = { 23 | 'model': 'foo', 24 | 'key': 'authKey', 25 | 'cacheTTL': '10m', 26 | } 27 | 28 | response = d.converse_alpha1( 29 | name='echo', inputs=inputs, temperature=0.7, context_id='chat-123', metadata=metadata 30 | ) 31 | 32 | print('Result: ', end='') 33 | for output in response.outputs: 34 | print(output.result) 35 | -------------------------------------------------------------------------------- /examples/invoke-custom-data/proto/response_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: response.proto 4 | """Generated protocol buffer code.""" 5 | 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import message as _message 9 | from google.protobuf import reflection as _reflection 10 | from google.protobuf import symbol_database as _symbol_database 11 | 12 | # @@protoc_insertion_point(imports) 13 | 14 | _sym_db = _symbol_database.Default() 15 | 16 | 17 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( 18 | b'\n\x0eresponse.proto"B\n\x0e\x43ustomResponse\x12\x11\n\tisSuccess\x18\x01 \x01(\x08\x12\x0c\n\x04\x63ode\x18\x02 \x01(\x05\x12\x0f\n\x07message\x18\x03 \x01(\tb\x06proto3' 19 | ) 20 | 21 | 22 | _CUSTOMRESPONSE = DESCRIPTOR.message_types_by_name['CustomResponse'] 23 | CustomResponse = _reflection.GeneratedProtocolMessageType( 24 | 'CustomResponse', 25 | (_message.Message,), 26 | { 27 | 'DESCRIPTOR': _CUSTOMRESPONSE, 28 | '__module__': 'response_pb2', 29 | # @@protoc_insertion_point(class_scope:CustomResponse) 30 | }, 31 | ) 32 | _sym_db.RegisterMessage(CustomResponse) 33 | 34 | if _descriptor._USE_C_DESCRIPTORS == False: 35 | DESCRIPTOR._options = None 36 | _CUSTOMRESPONSE._serialized_start = 18 37 | _CUSTOMRESPONSE._serialized_end = 84 38 | # @@protoc_insertion_point(module_scope) 39 | -------------------------------------------------------------------------------- /tests/actor/test_actor_id.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Copyright 2021 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 unittest 17 | 18 | from dapr.actor.id import ActorId 19 | 20 | 21 | class ActorIdTests(unittest.TestCase): 22 | def test_create_actor_id(self): 23 | actor_id_1 = ActorId('1') 24 | self.assertEqual('1', actor_id_1.id) 25 | 26 | def test_create_random_id(self): 27 | actor_id_random = ActorId.create_random_id() 28 | self.assertEqual(len('f56d5aec5b3b11ea9121acde48001122'), len(actor_id_random.id)) 29 | 30 | def test_get_hash(self): 31 | actor_test_id = ActorId('testId') 32 | self.assertIsNotNone(actor_test_id.__hash__) 33 | 34 | def test_comparison(self): 35 | actor_id_1 = ActorId('1') 36 | actor_id_1a = ActorId('1') 37 | self.assertTrue(actor_id_1 == actor_id_1a) 38 | 39 | actor_id_2 = ActorId('2') 40 | self.assertFalse(actor_id_1 == actor_id_2) 41 | -------------------------------------------------------------------------------- /dapr/conf/__init__.py: -------------------------------------------------------------------------------- 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 os 17 | 18 | from dapr.conf import global_settings 19 | 20 | 21 | class Settings: 22 | def __init__(self): 23 | for setting in dir(global_settings): 24 | default_value = getattr(global_settings, setting) 25 | env_variable = os.environ.get(setting) 26 | if env_variable: 27 | val = ( 28 | type(default_value)(env_variable) if default_value is not None else env_variable 29 | ) 30 | setattr(self, setting, val) 31 | else: 32 | setattr(self, setting, default_value) 33 | 34 | def __getattr__(self, name): 35 | if name not in dir(global_settings): 36 | raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'") 37 | return getattr(self, name) 38 | 39 | 40 | settings = Settings() 41 | -------------------------------------------------------------------------------- /dapr/proto/__init__.py: -------------------------------------------------------------------------------- 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 os 17 | import grpc 18 | 19 | from contextlib import contextmanager 20 | from typing import Optional 21 | from dapr.conf import settings 22 | 23 | from dapr.proto.common.v1 import common_pb2 as common_v1 24 | from dapr.proto.runtime.v1 import dapr_pb2 as api_v1 25 | from dapr.proto.runtime.v1 import dapr_pb2_grpc as api_service_v1 26 | from dapr.proto.runtime.v1 import appcallback_pb2 as appcallback_v1 27 | from dapr.proto.runtime.v1 import appcallback_pb2_grpc as appcallback_service_v1 28 | 29 | 30 | @contextmanager 31 | def connect_dapr(port: Optional[int] = -1): 32 | if port == -1: 33 | port = settings.DAPR_GRPC_PORT 34 | channel = grpc.insecure_channel(f"127.0.0.1:{port}") 35 | stub = api_service_v1.DaprStub(channel) 36 | yield stub 37 | channel.close() 38 | 39 | 40 | __all__ = [ 41 | 'connect_dapr', 42 | 'common_v1', 43 | 'api_v1', 44 | 'appcallback_v1', 45 | 'appcallback_service_v1', 46 | ] 47 | -------------------------------------------------------------------------------- /examples/demo_actor/demo_actor/demo_actor_interface.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2021 The Dapr Authors 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | 13 | from abc import abstractmethod 14 | 15 | from dapr.actor import ActorInterface, actormethod 16 | 17 | 18 | class DemoActorInterface(ActorInterface): 19 | @abstractmethod 20 | @actormethod(name='GetMyData') 21 | async def get_my_data(self) -> object: ... 22 | 23 | @abstractmethod 24 | @actormethod(name='SetMyData') 25 | async def set_my_data(self, data: object) -> None: ... 26 | 27 | @abstractmethod 28 | @actormethod(name='ClearMyData') 29 | async def clear_my_data(self) -> None: ... 30 | 31 | @abstractmethod 32 | @actormethod(name='SetReminder') 33 | async def set_reminder(self, enabled: bool) -> None: ... 34 | 35 | @abstractmethod 36 | @actormethod(name='SetTimer') 37 | async def set_timer(self, enabled: bool) -> None: ... 38 | 39 | @abstractmethod 40 | @actormethod(name='GetReentrancyStatus') 41 | async def get_reentrancy_status(self) -> bool: ... 42 | -------------------------------------------------------------------------------- /examples/conversation/conversation_alpha2.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------ 2 | # Copyright 2025 The Dapr Authors 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | # ------------------------------------------------------------ 13 | from dapr.clients import DaprClient 14 | from dapr.clients.grpc.conversation import ( 15 | ConversationInputAlpha2, 16 | create_user_message, 17 | ) 18 | 19 | with DaprClient() as d: 20 | inputs = [ 21 | ConversationInputAlpha2(messages=[create_user_message("What's Dapr?")], scrub_pii=True), 22 | ConversationInputAlpha2( 23 | messages=[create_user_message('Give a brief overview.')], scrub_pii=True 24 | ), 25 | ] 26 | 27 | metadata = { 28 | 'model': 'foo', 29 | 'key': 'authKey', 30 | 'cacheTTL': '10m', 31 | } 32 | 33 | response = d.converse_alpha2( 34 | name='echo', inputs=inputs, temperature=0.7, context_id='chat-123', metadata=metadata 35 | ) 36 | 37 | print('Result: ', end='') 38 | for output in response.outputs: 39 | print(output.choices[0].message.content) 40 | -------------------------------------------------------------------------------- /examples/langgraph-checkpointer/README.md: -------------------------------------------------------------------------------- 1 | # Dapr For Agents - LangGraph Checkpointer 2 | 3 | Supporting Dapr backed Checkpointer for LangGraph based Agents. 4 | 5 | ## Pre-requisites 6 | 7 | - [Dapr CLI and initialized environment](https://docs.dapr.io/getting-started) 8 | - [Install Python 3.10+](https://www.python.org/downloads/) 9 | 10 | ## Install Dapr python-SDK 11 | 12 | <!-- Our CI/CD pipeline automatically installs the correct version, so we can skip this step in the automation --> 13 | 14 | <!-- STEP 15 | name: Install deps 16 | --> 17 | 18 | ```sh 19 | pip3 install -r requirements.txt 20 | ``` 21 | 22 | <!-- END_STEP --> 23 | 24 | ## Run the example 25 | 26 | Export your `OPENAI_API_KEY`: 27 | 28 | ```bash 29 | export OPENAI_API_KEY="SK-..." 30 | ``` 31 | 32 | Run the following command in a terminal/command prompt: 33 | 34 | <!-- STEP 35 | name: Run subscriber 36 | expected_stdout_lines: 37 | - '== APP == Add 3 and 4.' 38 | - '== APP == a: 3' 39 | - '== APP == b: 4' 40 | - '== APP == 7' 41 | - '== APP == Args:' 42 | - '== APP == a: 7' 43 | - '== APP == b: 2' 44 | - '== APP == 14' 45 | 46 | output_match_mode: substring 47 | background: true 48 | match_order: none 49 | sleep: 15 50 | --> 51 | 52 | ```bash 53 | # 1. Run the LangGraph agent 54 | dapr run --app-id langgraph-checkpointer --app-port 5001 --resources-path ./components -- python3 agent.py 55 | ``` 56 | 57 | <!-- END_STEP --> 58 | 59 | ## Cleanup 60 | 61 | Either press CTRL + C to quit the app or run the following command in a new terminal to stop the app: 62 | 63 | ```bash 64 | dapr stop --app-id langgraph-checkpointer 65 | ``` 66 | 67 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Dapr Python SDK examples 2 | 3 | These examples demonstrate how to use the Dapr Python SDK: 4 | 5 | | Example | Description | 6 | |-------------------------------------------------------|-------------| 7 | | [Service invocation](./invoke-simple) | Invoke service by passing bytes data 8 | | [Service invocation (advanced)](./invoke-custom-data) | Invoke service by using custom protobuf message 9 | | [State management](./state_store) | Save and get state to/from the state store 10 | | [Publish & subscribe](./pubsub-simple) | Publish and subscribe to events 11 | | [Error handling](./error_handling) | Error handling 12 | | [Bindings](./invoke-binding) | Invoke an output binding to interact with external resources 13 | | [Virtual actors](./demo_actor) | Try Dapr virtual actor features 14 | | [Secrets](./secret_store) | Get secrets from a defined secret store 15 | | [Distributed tracing](./w3c-tracing) | Leverage Dapr's built-in tracing support 16 | | [Distributed lock](./distributed_lock) | Keep your application safe from race conditions by using distributed locks 17 | | [Workflow](./demo_workflow) | Run a workflow to simulate an order processor 18 | | [Cryptography](./crypto) | Perform cryptographic operations without exposing keys to your application 19 | 20 | ## More information 21 | 22 | - [Dapr Python SDK docs](https://docs.dapr.io/developing-applications/sdks/python) 23 | -------------------------------------------------------------------------------- /dapr/conf/global_settings.py: -------------------------------------------------------------------------------- 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 | # Default environment settings that environment variables overrides 17 | 18 | HTTP_APP_PORT = 3000 19 | GRPC_APP_PORT = 3010 20 | 21 | DAPR_API_TOKEN = None 22 | DAPR_HTTP_ENDPOINT = None 23 | DAPR_GRPC_ENDPOINT = None 24 | DAPR_RUNTIME_HOST = '127.0.0.1' 25 | DAPR_HTTP_PORT = 3500 26 | DAPR_GRPC_PORT = 50001 27 | DAPR_API_VERSION = 'v1.0' 28 | DAPR_HEALTH_TIMEOUT = 60 # seconds 29 | 30 | DAPR_API_MAX_RETRIES = 0 31 | DAPR_API_TIMEOUT_SECONDS = 60 32 | 33 | DAPR_API_METHOD_INVOCATION_PROTOCOL = 'http' 34 | 35 | DAPR_HTTP_TIMEOUT_SECONDS = 60 36 | 37 | # ----- Conversation API settings ------ 38 | 39 | # Configuration for handling large enums to avoid massive JSON schemas that can exceed LLM token limits 40 | DAPR_CONVERSATION_TOOLS_MAX_ENUM_ITEMS = 100 41 | # What to do when an enum has more than DAPR_CONVERSATION_TOOLS_MAX_ENUM_ITEMS items. Convert to String message or raise an exception 42 | # possible values: 'string' (default), 'error' 43 | DAPR_CONVERSATION_TOOLS_LARGE_ENUM_BEHAVIOR = 'string' 44 | -------------------------------------------------------------------------------- /examples/error_handling/error_handling.py: -------------------------------------------------------------------------------- 1 | from dapr.clients import DaprClient 2 | from dapr.clients.exceptions import DaprGrpcError 3 | 4 | with DaprClient() as d: 5 | storeName = 'statestore' 6 | 7 | key = 'key||' 8 | value = 'value_1' 9 | 10 | # Save single state. 11 | try: 12 | d.save_state(store_name=storeName, key=key, value=value) 13 | except DaprGrpcError as err: 14 | print(f'Status code: {err.code()}', flush=True) 15 | print(f'Message: {err.details()}', flush=True) 16 | print(f'Error code: {err.error_code()}', flush=True) 17 | 18 | if err.status_details().error_info is not None: 19 | print(f'Error info(reason): {err.status_details().error_info["reason"]}', flush=True) 20 | if err.status_details().resource_info is not None: 21 | print( 22 | f'Resource info (resource type): {err.status_details().resource_info["resource_type"]}', 23 | flush=True, 24 | ) 25 | print( 26 | f'Resource info (resource name): {err.status_details().resource_info["resource_name"]}', 27 | flush=True, 28 | ) 29 | if err.status_details().bad_request is not None: 30 | print( 31 | f'Bad request (field): {err.status_details().bad_request["field_violations"][0]["field"]}', 32 | flush=True, 33 | ) 34 | print( 35 | f'Bad request (description): {err.status_details().bad_request["field_violations"][0]["description"]}', 36 | flush=True, 37 | ) 38 | print(f'JSON: {err.json()}', flush=True) 39 | -------------------------------------------------------------------------------- /examples/pubsub-streaming-async/subscriber-handler.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import asyncio 3 | 4 | from dapr.aio.clients import DaprClient 5 | from dapr.clients.grpc._response import TopicEventResponse 6 | 7 | parser = argparse.ArgumentParser(description='Publish events to a Dapr pub/sub topic.') 8 | parser.add_argument('--topic', type=str, required=True, help='The topic name to publish to.') 9 | args = parser.parse_args() 10 | 11 | topic_name = args.topic 12 | dlq_topic_name = topic_name + '_DEAD' 13 | 14 | counter = 0 15 | 16 | 17 | async def process_message(message) -> TopicEventResponse: 18 | """ 19 | Asynchronously processes the message and returns a TopicEventResponse. 20 | """ 21 | 22 | print(f'Processing message: {message.data()} from {message.topic()}...', flush=True) 23 | global counter 24 | counter += 1 25 | return TopicEventResponse('success') 26 | 27 | 28 | async def main(): 29 | """ 30 | Main function to subscribe to a pubsub topic and handle messages asynchronously. 31 | """ 32 | async with DaprClient() as client: 33 | # Subscribe to the pubsub topic with the message handler 34 | close_fn = await client.subscribe_with_handler( 35 | pubsub_name='pubsub', 36 | topic=topic_name, 37 | handler_fn=process_message, 38 | dead_letter_topic=dlq_topic_name, 39 | ) 40 | 41 | # Wait until 5 messages are processed 42 | global counter 43 | while counter < 5: 44 | await asyncio.sleep(1) 45 | 46 | print('Closing subscription...') 47 | await close_fn() 48 | 49 | 50 | if __name__ == '__main__': 51 | asyncio.run(main()) 52 | -------------------------------------------------------------------------------- /examples/demo_actor/demo_actor/demo_actor_service.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2021 The Dapr Authors 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | 13 | from dapr.ext.fastapi import DaprActor # type: ignore 14 | from demo_actor import DemoActor 15 | from fastapi import FastAPI # type: ignore 16 | 17 | from dapr.actor.runtime.config import ActorReentrancyConfig, ActorRuntimeConfig, ActorTypeConfig 18 | from dapr.actor.runtime.runtime import ActorRuntime 19 | 20 | app = FastAPI(title=f'{DemoActor.__name__}Service') 21 | 22 | # This is an optional advanced configuration which enables reentrancy only for the 23 | # specified actor type. By default reentrancy is not enabled for all actor types. 24 | config = ActorRuntimeConfig() # init with default values 25 | config.update_actor_type_configs( 26 | [ActorTypeConfig(actor_type=DemoActor.__name__, reentrancy=ActorReentrancyConfig(enabled=True))] 27 | ) 28 | ActorRuntime.set_actor_config(config) 29 | 30 | # Add Dapr Actor Extension 31 | actor = DaprActor(app) 32 | 33 | 34 | @app.on_event('startup') 35 | async def startup_event(): 36 | # Register DemoActor 37 | await actor.register_actor(DemoActor) 38 | -------------------------------------------------------------------------------- /ext/dapr-ext-workflow/dapr/ext/workflow/workflow_activity_context.py: -------------------------------------------------------------------------------- 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 | from __future__ import annotations 17 | 18 | from typing import Callable, TypeVar 19 | 20 | from durabletask import task 21 | 22 | T = TypeVar('T') 23 | TInput = TypeVar('TInput') 24 | TOutput = TypeVar('TOutput') 25 | 26 | 27 | class WorkflowActivityContext: 28 | """Defines properties and methods for task activity context objects.""" 29 | 30 | def __init__(self, ctx: task.ActivityContext): 31 | self.__obj = ctx 32 | 33 | @property 34 | def workflow_id(self) -> str: 35 | """Gets the unique ID of the current workflow instance""" 36 | return self.__obj.orchestration_id 37 | 38 | @property 39 | def task_id(self) -> int: 40 | """Gets the unique ID of the current workflow task""" 41 | return self.__obj.task_id 42 | 43 | def get_inner_context(self) -> task.ActivityContext: 44 | return self.__obj 45 | 46 | 47 | # Activities are simple functions that can be scheduled by workflows 48 | Activity = Callable[..., TOutput] 49 | -------------------------------------------------------------------------------- /ext/dapr-ext-workflow/dapr/ext/workflow/logger/options.py: -------------------------------------------------------------------------------- 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 logging 17 | from typing import Union 18 | 19 | 20 | class LoggerOptions: 21 | def __init__( 22 | self, 23 | log_level: Union[str, None] = None, 24 | log_handler: Union[logging.Handler, None] = None, 25 | log_formatter: Union[logging.Formatter, None] = None, 26 | ): 27 | # Set default log level to INFO if none is provided 28 | if log_level is None: 29 | log_level = logging.INFO 30 | # Add a default log handler if none is provided 31 | if log_handler is None: 32 | log_handler = logging.StreamHandler() 33 | # Set a default log formatter if none is provided 34 | if log_formatter is None: 35 | log_formatter = logging.Formatter( 36 | fmt='%(asctime)s.%(msecs)03d %(name)s %(levelname)s: %(message)s', 37 | datefmt='%Y-%m-%d %H:%M:%S', 38 | ) 39 | self.log_level = log_level 40 | self.log_handler = log_handler 41 | self.log_formatter = log_formatter 42 | -------------------------------------------------------------------------------- /examples/pubsub-streaming/publisher.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------ 2 | # Copyright 2022 The Dapr Authors 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | # ------------------------------------------------------------ 13 | import argparse 14 | import json 15 | import time 16 | 17 | from dapr.clients import DaprClient 18 | 19 | parser = argparse.ArgumentParser(description='Publish events to a Dapr pub/sub topic.') 20 | parser.add_argument('--topic', type=str, required=True, help='The topic name to publish to.') 21 | args = parser.parse_args() 22 | 23 | topic_name = args.topic 24 | 25 | with DaprClient() as d: 26 | id = 0 27 | while id < 5: 28 | id += 1 29 | req_data = {'id': id, 'message': 'hello world'} 30 | 31 | # Create a typed message with content type and body 32 | resp = d.publish_event( 33 | pubsub_name='pubsub', 34 | topic_name=topic_name, 35 | data=json.dumps(req_data), 36 | data_content_type='application/json', 37 | publish_metadata={'ttlInSeconds': '100', 'rawPayload': 'false'}, 38 | ) 39 | 40 | # Print the request 41 | print(req_data, flush=True) 42 | 43 | time.sleep(1) 44 | -------------------------------------------------------------------------------- /examples/demo_actor/demo_actor/test_demo_actor.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from demo_actor import DemoActor 4 | 5 | from dapr.actor.runtime.mock_actor import create_mock_actor 6 | 7 | 8 | class DemoActorTests(unittest.IsolatedAsyncioTestCase): 9 | def test_create_actor(self): 10 | mockactor = create_mock_actor(DemoActor, '1') 11 | self.assertEqual(mockactor.id.id, '1') 12 | 13 | async def test_get_data(self): 14 | mockactor = create_mock_actor(DemoActor, '1') 15 | self.assertFalse(mockactor._state_manager._mock_state) # type: ignore 16 | val = await mockactor.get_my_data() 17 | self.assertIsNone(val) 18 | 19 | async def test_set_data(self): 20 | mockactor = create_mock_actor(DemoActor, '1') 21 | await mockactor.set_my_data({'state': 5}) 22 | val = await mockactor.get_my_data() 23 | self.assertIs(val['state'], 5) # type: ignore 24 | 25 | async def test_clear_data(self): 26 | mockactor = create_mock_actor(DemoActor, '1') 27 | await mockactor.set_my_data({'state': 5}) 28 | val = await mockactor.get_my_data() 29 | self.assertIs(val['state'], 5) # type: ignore 30 | await mockactor.clear_my_data() 31 | val = await mockactor.get_my_data() 32 | self.assertIsNone(val) 33 | 34 | async def test_reminder(self): 35 | mockactor = create_mock_actor(DemoActor, '1') 36 | self.assertFalse(mockactor._state_manager._mock_reminders) # type: ignore 37 | await mockactor.set_reminder(True) 38 | self.assertTrue('demo_reminder' in mockactor._state_manager._mock_reminders) # type: ignore 39 | await mockactor.set_reminder(False) 40 | self.assertFalse(mockactor._state_manager._mock_reminders) # type: ignore 41 | -------------------------------------------------------------------------------- /ext/dapr-ext-grpc/tests/test_topic_event_response.py: -------------------------------------------------------------------------------- 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 unittest 17 | 18 | from dapr.clients.grpc._response import TopicEventResponse, TopicEventResponseStatus 19 | 20 | 21 | class TopicEventResponseTests(unittest.TestCase): 22 | def test_topic_event_response_creation_from_enum(self): 23 | for status in TopicEventResponseStatus: 24 | response = TopicEventResponse(status) 25 | self.assertEqual(response.status.value, status.value) 26 | 27 | def test_topic_event_response_creation_fails(self): 28 | with self.assertRaises(KeyError): 29 | TopicEventResponse('invalid') 30 | 31 | def test_topic_event_response_creation_from_str(self): 32 | for status in TopicEventResponseStatus: 33 | response = TopicEventResponse(status.name) 34 | self.assertEqual(response.status.value, status.value) 35 | 36 | def test_topic_event_response_creation_fails_with_object(self): 37 | with self.assertRaises(ValueError): 38 | TopicEventResponse(None) 39 | 40 | 41 | if __name__ == '__main__': 42 | unittest.main() 43 | -------------------------------------------------------------------------------- /examples/workflow/child_workflow.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2023 The Dapr Authors 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | 13 | import time 14 | 15 | import dapr.ext.workflow as wf 16 | 17 | wfr = wf.WorkflowRuntime() 18 | 19 | 20 | @wfr.workflow 21 | def main_workflow(ctx: wf.DaprWorkflowContext): 22 | try: 23 | instance_id = ctx.instance_id 24 | child_instance_id = instance_id + '-child' 25 | print(f'*** Calling child workflow {child_instance_id}', flush=True) 26 | yield ctx.call_child_workflow( 27 | workflow=child_workflow, input=None, instance_id=child_instance_id 28 | ) 29 | except Exception as e: 30 | print(f'*** Exception: {e}') 31 | 32 | return 33 | 34 | 35 | @wfr.workflow 36 | def child_workflow(ctx: wf.DaprWorkflowContext): 37 | instance_id = ctx.instance_id 38 | print(f'*** Child workflow {instance_id} called', flush=True) 39 | 40 | 41 | if __name__ == '__main__': 42 | wfr.start() 43 | time.sleep(10) # wait for workflow runtime to start 44 | 45 | wf_client = wf.DaprWorkflowClient() 46 | instance_id = wf_client.schedule_new_workflow(workflow=main_workflow) 47 | 48 | # Wait for the workflow to complete 49 | time.sleep(5) 50 | 51 | wfr.shutdown() 52 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: dapr-python 2 | 3 | on: 4 | push: 5 | branches: 6 | - feature/* 7 | pull_request: 8 | branches: 9 | - main 10 | - release-* 11 | - feature/* 12 | workflow_dispatch: 13 | merge_group: 14 | 15 | jobs: 16 | lint: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v6 20 | - name: Set up Python 3.10 21 | uses: actions/setup-python@v6 22 | with: 23 | python-version: '3.10' 24 | - name: Install dependencies 25 | run: | 26 | python -m pip install --upgrade pip 27 | pip install setuptools wheel tox 28 | - name: Run Autoformatter 29 | run: | 30 | tox -e ruff 31 | statusResult=$(git status -u --porcelain) 32 | if [ -z $statusResult ] 33 | then 34 | exit 0 35 | else 36 | echo "Source files are not formatted correctly. Run 'tox -e ruff' to autoformat." 37 | exit 1 38 | fi 39 | 40 | build: 41 | needs: lint 42 | runs-on: ubuntu-latest 43 | strategy: 44 | fail-fast: false 45 | matrix: 46 | python_ver: ["3.10", "3.11", "3.12", "3.13"] 47 | steps: 48 | - uses: actions/checkout@v6 49 | - name: Set up Python ${{ matrix.python_ver }} 50 | uses: actions/setup-python@v6 51 | with: 52 | python-version: ${{ matrix.python_ver }} 53 | - name: Install dependencies 54 | run: | 55 | python -m pip install --upgrade pip 56 | pip install setuptools wheel tox 57 | - name: Check Typing 58 | run: | 59 | tox -e type 60 | - name: Run unit-tests 61 | run: | 62 | tox -e py`echo "${{ matrix.python_ver }}" | sed 's/\.//g'` 63 | - name: Upload test coverage 64 | uses: codecov/codecov-action@v5 65 | -------------------------------------------------------------------------------- /examples/demo_actor/demo_actor/demo_actor_flask.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2021 The Dapr Authors 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | 13 | from demo_actor import DemoActor 14 | from flask import Flask, jsonify 15 | from flask_dapr.actor import DaprActor 16 | 17 | from dapr.actor.runtime.config import ActorReentrancyConfig, ActorRuntimeConfig, ActorTypeConfig 18 | from dapr.actor.runtime.runtime import ActorRuntime 19 | from dapr.conf import settings 20 | 21 | app = Flask(f'{DemoActor.__name__}Service') 22 | 23 | # This is an optional advanced configuration which enables reentrancy only for the 24 | # specified actor type. By default reentrancy is not enabled for all actor types. 25 | config = ActorRuntimeConfig() # init with default values 26 | config.update_actor_type_configs( 27 | [ActorTypeConfig(actor_type=DemoActor.__name__, reentrancy=ActorReentrancyConfig(enabled=True))] 28 | ) 29 | ActorRuntime.set_actor_config(config) 30 | 31 | # Enable DaprActor Flask extension 32 | actor = DaprActor(app) 33 | # Register DemoActor 34 | actor.register_actor(DemoActor) 35 | 36 | 37 | # This route is optional. 38 | @app.route('/') 39 | def index(): 40 | return jsonify({'status': 'ok'}), 200 41 | 42 | 43 | if __name__ == '__main__': 44 | app.run(port=settings.HTTP_APP_PORT) 45 | -------------------------------------------------------------------------------- /ext/dapr-ext-workflow/tests/test_workflow_activity_context.py: -------------------------------------------------------------------------------- 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 unittest 17 | from unittest import mock 18 | 19 | from dapr.ext.workflow.workflow_activity_context import WorkflowActivityContext 20 | from durabletask import task 21 | 22 | mock_orchestration_id = 'orchestration001' 23 | mock_task = 10 24 | 25 | 26 | class FakeActivityContext: 27 | @property 28 | def orchestration_id(self): 29 | return mock_orchestration_id 30 | 31 | @property 32 | def task_id(self): 33 | return mock_task 34 | 35 | 36 | class WorkflowActivityContextTest(unittest.TestCase): 37 | def test_workflow_activity_context(self): 38 | with mock.patch('durabletask.task.ActivityContext', return_value=FakeActivityContext()): 39 | fake_act_ctx = task.ActivityContext( 40 | orchestration_id=mock_orchestration_id, task_id=mock_task 41 | ) 42 | act_ctx = WorkflowActivityContext(fake_act_ctx) 43 | actual_orchestration_id = act_ctx.workflow_id 44 | assert actual_orchestration_id == mock_orchestration_id 45 | 46 | actual_task_id = act_ctx.task_id 47 | assert actual_task_id == mock_task 48 | -------------------------------------------------------------------------------- /.github/workflows/fossa.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2021 The Dapr Authors 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | # 13 | 14 | name: fossa 15 | on: 16 | repository_dispatch: 17 | types: [fossa] 18 | push: 19 | branches: 20 | - main 21 | - release-* 22 | - feature/* 23 | tags: 24 | - v* 25 | - workflow-v* 26 | - grpc-v* 27 | - flask-v* 28 | - fastapi-v* 29 | pull_request: 30 | branches: 31 | - main 32 | - release-* 33 | - feature/* 34 | workflow_dispatch: {} 35 | jobs: 36 | fossa-scan: 37 | if: github.repository_owner == 'dapr' # FOSSA is not intended to run on forks. 38 | runs-on: ubuntu-latest 39 | env: 40 | FOSSA_API_KEY: b88e1f4287c3108c8751bf106fb46db6 # This is a push-only token that is safe to be exposed. 41 | steps: 42 | - name: "Checkout code" 43 | uses: actions/checkout@v6 44 | 45 | - name: "Run FOSSA Scan" 46 | uses: fossas/fossa-action@v1.7.0 # Use a specific version if locking is preferred 47 | with: 48 | api-key: ${{ env.FOSSA_API_KEY }} 49 | 50 | - name: "Run FOSSA Test" 51 | uses: fossas/fossa-action@v1.7.0 # Use a specific version if locking is preferred 52 | with: 53 | api-key: ${{ env.FOSSA_API_KEY }} 54 | run-tests: true 55 | -------------------------------------------------------------------------------- /dapr/clients/base.py: -------------------------------------------------------------------------------- 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 | from abc import ABC, abstractmethod 17 | from typing import Optional 18 | 19 | 20 | class DaprActorClientBase(ABC): 21 | """A base class that represents Dapr Actor Client.""" 22 | 23 | @abstractmethod 24 | async def invoke_method( 25 | self, actor_type: str, actor_id: str, method: str, data: Optional[bytes] = None 26 | ) -> bytes: ... 27 | 28 | @abstractmethod 29 | async def save_state_transactionally( 30 | self, actor_type: str, actor_id: str, data: bytes 31 | ) -> None: ... 32 | 33 | @abstractmethod 34 | async def get_state(self, actor_type: str, actor_id: str, name: str) -> bytes: ... 35 | 36 | @abstractmethod 37 | async def register_reminder( 38 | self, actor_type: str, actor_id: str, name: str, data: bytes 39 | ) -> None: ... 40 | 41 | @abstractmethod 42 | async def unregister_reminder(self, actor_type: str, actor_id: str, name: str) -> None: ... 43 | 44 | @abstractmethod 45 | async def register_timer( 46 | self, actor_type: str, actor_id: str, name: str, data: bytes 47 | ) -> None: ... 48 | 49 | @abstractmethod 50 | async def unregister_timer(self, actor_type: str, actor_id: str, name: str) -> None: ... 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Editor config 51 | .idea 52 | .vscode 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | 63 | # Flask stuff: 64 | instance/ 65 | .webassets-cache 66 | 67 | # Scrapy stuff: 68 | .scrapy 69 | 70 | # Sphinx documentation 71 | docs/_build/ 72 | 73 | # PyBuilder 74 | target/ 75 | 76 | # Jupyter Notebook 77 | .ipynb_checkpoints 78 | 79 | # pyenv 80 | .python-version 81 | 82 | # celery beat schedule file 83 | celerybeat-schedule 84 | 85 | # SageMath parsed files 86 | *.sage.py 87 | 88 | # Environments 89 | .env 90 | .venv 91 | env/ 92 | venv/ 93 | ENV/ 94 | env.bak/ 95 | venv.bak/ 96 | 97 | # Spyder project settings 98 | .spyderproject 99 | .spyproject 100 | 101 | # Rope project settings 102 | .ropeproject 103 | 104 | # mkdocs documentation 105 | /site 106 | 107 | # mypy 108 | .mypy_cache/ 109 | 110 | # macOS specific files 111 | .DS_Store 112 | -------------------------------------------------------------------------------- /dapr/actor/runtime/remindable.py: -------------------------------------------------------------------------------- 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 | from abc import ABC, abstractmethod 17 | from datetime import timedelta 18 | from typing import Optional 19 | 20 | 21 | class Remindable(ABC): 22 | """An interface that actors must implement to consume reminders registered 23 | using :meth:`Remindable.register_reminder`. 24 | """ 25 | 26 | @abstractmethod 27 | async def receive_reminder( 28 | self, 29 | name: str, 30 | state: bytes, 31 | due_time: timedelta, 32 | period: timedelta, 33 | ttl: Optional[timedelta] = None, 34 | ) -> None: 35 | """A callback which will be called when reminder is triggered. 36 | 37 | Args: 38 | name (str): the name of the reminder to register. the name must be unique per actor. 39 | state (bytes): the user state passed to the reminder invocation. 40 | due_time (datetime.timedelta): the amount of time to delay before invoking the reminder 41 | for the first time. 42 | period (datetime.timedelta): the time interval between reminder invocations 43 | after the first invocation. 44 | ttl (datetime.timedelta): the time interval before the reminder stops firing 45 | """ 46 | ... 47 | -------------------------------------------------------------------------------- /dapr/actor/id.py: -------------------------------------------------------------------------------- 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 uuid 17 | 18 | 19 | class ActorId: 20 | """ActorId that represents the identity of an actor. 21 | 22 | Example:: 23 | 24 | # create actorid with id 1 25 | actor_id = ActorId('1') 26 | 27 | # create random hex ActorId 28 | actor_random_id = ActorId.create_random_id() 29 | 30 | """ 31 | 32 | def __init__(self, actor_id: str): 33 | if not isinstance(actor_id, str): 34 | raise TypeError(f'Argument actor_id must be of type str, not {type(actor_id)}') 35 | self._id = actor_id 36 | 37 | @classmethod 38 | def create_random_id(cls): 39 | """Creates new object of :class:`ActorId` with the random id value.""" 40 | random_id = uuid.uuid1().hex 41 | return ActorId(random_id) 42 | 43 | @property 44 | def id(self) -> str: 45 | """Gets Actor ID string.""" 46 | return self._id 47 | 48 | def __hash__(self): 49 | return hash(self._id) 50 | 51 | def __str__(self): 52 | return self._id 53 | 54 | def __eq__(self, other): 55 | if not other: 56 | return False 57 | return self._id == other.id 58 | 59 | def __ne__(self, other): 60 | if not other: 61 | return False 62 | 63 | return self._id != other.id 64 | -------------------------------------------------------------------------------- /dapr/actor/actor_interface.py: -------------------------------------------------------------------------------- 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 | from abc import ABC 17 | from typing import Optional 18 | 19 | 20 | class ActorInterface(ABC): 21 | """A base class that Dapr Actor inherits. 22 | 23 | Actor requires to inherit ActorInterface as a base class. 24 | 25 | Example:: 26 | 27 | class DaprActorInterface(ActorInterface): 28 | @actormethod('DoActorMethod1') 29 | async def do_actor_method1(self, param): 30 | ... 31 | 32 | @actormethod('DoActorMethod2') 33 | async def do_actor_method2(self, param): 34 | ... 35 | """ 36 | 37 | ... 38 | 39 | 40 | def actormethod(name: Optional[str] = None): 41 | """Decorate actor method to define the method invoked by the remote actor. 42 | 43 | This allows users to call the decorated name via the proxy client. 44 | 45 | Example:: 46 | 47 | class DaprActorInterface(ActorInterface): 48 | @actormethod(name='DoActorCall') 49 | async def do_actor_call(self, param): 50 | ... 51 | 52 | Args: 53 | name (str, optional): the name of actor method. 54 | """ 55 | 56 | def wrapper(funcobj): 57 | funcobj.__actormethod__ = name 58 | funcobj.__isabstractmethod__ = True 59 | return funcobj 60 | 61 | return wrapper 62 | -------------------------------------------------------------------------------- /examples/invoke-http/README.md: -------------------------------------------------------------------------------- 1 | # Example - Invoke a service 2 | 3 | This example utilizes a receiver and a caller for the `invoke_method` functionality. 4 | 5 | > **Note:** Make sure to use the latest proto bindings 6 | 7 | ## Pre-requisites 8 | 9 | - [Dapr CLI and initialized environment](https://docs.dapr.io/getting-started) 10 | - [Install Python 3.8+](https://www.python.org/downloads/) 11 | 12 | ### Install requirements 13 | 14 | You can install dapr SDK package using pip command: 15 | 16 | <!-- STEP 17 | name: Install requirements 18 | --> 19 | 20 | ```sh 21 | pip3 install dapr Flask 22 | ``` 23 | 24 | <!-- END_STEP --> 25 | 26 | ## Run the example 27 | 28 | To run this example, the following code can be utilized: 29 | 30 | Start the receiver: 31 | <!-- STEP 32 | name: Run invoke http example 33 | expected_stdout_lines: 34 | - '== APP == Order received : {"id": 1, "message": "hello world"}' 35 | - '== APP == Order error : {"id": 2, "message": "hello world"}' 36 | background: true 37 | sleep: 5 38 | --> 39 | 40 | ```bash 41 | dapr run --app-id=invoke-receiver --app-port=8088 --app-protocol http -- python3 invoke-receiver.py 42 | ``` 43 | <!-- END_STEP --> 44 | 45 | Start the caller: 46 | <!-- STEP 47 | name: Run invoke http example 48 | expected_stdout_lines: 49 | - '== APP == text/html' 50 | - '== APP == {"success": true}' 51 | - '== APP == 200' 52 | - '== APP == error occurred' 53 | - '== APP == MY_CODE' 54 | - '== APP == {"message": "error occurred", "errorCode": "MY_CODE"}' 55 | - '== APP == 503' 56 | - '== APP == Internal Server Error' 57 | background: true 58 | sleep: 5 59 | --> 60 | 61 | ```bash 62 | dapr run --app-id=invoke-caller -- python3 invoke-caller.py 63 | ``` 64 | <!-- END_STEP --> 65 | 66 | ## Cleanup 67 | 68 | <!-- STEP 69 | expected_stdout_lines: 70 | - '✅ app stopped successfully: invoke-receiver' 71 | name: Shutdown dapr 72 | --> 73 | 74 | ```bash 75 | dapr stop --app-id invoke-receiver 76 | ``` 77 | 78 | <!-- END_STEP --> -------------------------------------------------------------------------------- /examples/configuration/configuration.py: -------------------------------------------------------------------------------- 1 | """ 2 | dapr run --app-id configexample --resources-path components/ -- python3 configuration.py 3 | """ 4 | 5 | import asyncio 6 | from time import sleep 7 | 8 | from dapr.clients import DaprClient 9 | from dapr.clients.grpc._response import ConfigurationResponse, ConfigurationWatcher 10 | 11 | configuration: ConfigurationWatcher = ConfigurationWatcher() 12 | 13 | 14 | def handler(id: str, resp: ConfigurationResponse): 15 | for key in resp.items: 16 | print( 17 | f'Subscribe key={key} value={resp.items[key].value} ' 18 | f'version={resp.items[key].version} ' 19 | f'metadata={resp.items[key].metadata}', 20 | flush=True, 21 | ) 22 | 23 | 24 | async def executeConfiguration(): 25 | with DaprClient() as d: 26 | storeName = 'configurationstore' 27 | 28 | keys = ['orderId1', 'orderId2'] 29 | 30 | global configuration 31 | 32 | # Get one configuration by key. 33 | configuration = d.get_configuration(store_name=storeName, keys=keys, config_metadata={}) 34 | for key in configuration.items: 35 | print( 36 | f'Got key={key} ' 37 | f'value={configuration.items[key].value} ' 38 | f'version={configuration.items[key].version} ' 39 | f'metadata={configuration.items[key].metadata}', 40 | flush=True, 41 | ) 42 | 43 | # Subscribe to configuration for keys {orderId1,orderId2}. 44 | id = d.subscribe_configuration( 45 | store_name=storeName, keys=keys, handler=handler, config_metadata={} 46 | ) 47 | print('Subscription ID is', id, flush=True) 48 | sleep(10) 49 | 50 | # Unsubscribe from configuration 51 | isSuccess = d.unsubscribe_configuration(store_name=storeName, id=id) 52 | print(f'Unsubscribed successfully? {isSuccess}', flush=True) 53 | 54 | 55 | asyncio.run(executeConfiguration()) 56 | -------------------------------------------------------------------------------- /docs/actor/actor.runtime.rst: -------------------------------------------------------------------------------- 1 | actor.runtime package 2 | ===================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | 8 | .. automodule:: actor.runtime.actor 9 | :members: 10 | :undoc-members: 11 | :show-inheritance: 12 | 13 | 14 | .. automodule:: actor.runtime._call_type 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | 20 | .. automodule:: actor.runtime.config 21 | :members: 22 | :undoc-members: 23 | :show-inheritance: 24 | 25 | 26 | .. automodule:: actor.runtime.context 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | 32 | .. automodule:: actor.runtime.manager 33 | :members: 34 | :undoc-members: 35 | :show-inheritance: 36 | 37 | 38 | .. automodule:: actor.runtime._method_context 39 | :members: 40 | :undoc-members: 41 | :show-inheritance: 42 | 43 | 44 | .. automodule:: actor.runtime.method_dispatcher 45 | :members: 46 | :undoc-members: 47 | :show-inheritance: 48 | 49 | 50 | .. automodule:: actor.runtime.remindable 51 | :members: 52 | :undoc-members: 53 | :show-inheritance: 54 | 55 | 56 | .. automodule:: actor.runtime._reminder_data 57 | :members: 58 | :undoc-members: 59 | :show-inheritance: 60 | 61 | 62 | .. automodule:: actor.runtime.runtime 63 | :members: 64 | :undoc-members: 65 | :show-inheritance: 66 | 67 | 68 | .. automodule:: actor.runtime.state_change 69 | :members: 70 | :undoc-members: 71 | :show-inheritance: 72 | 73 | 74 | .. automodule:: actor.runtime.state_manager 75 | :members: 76 | :undoc-members: 77 | :show-inheritance: 78 | 79 | 80 | .. automodule:: actor.runtime._state_provider 81 | :members: 82 | :undoc-members: 83 | :show-inheritance: 84 | 85 | 86 | .. automodule:: actor.runtime._timer_data 87 | :members: 88 | :undoc-members: 89 | :show-inheritance: 90 | 91 | 92 | Module contents 93 | --------------- 94 | 95 | .. automodule:: actor.runtime 96 | :members: 97 | :undoc-members: 98 | :show-inheritance: 99 | -------------------------------------------------------------------------------- /examples/langgraph-checkpointer/agent.py: -------------------------------------------------------------------------------- 1 | from dapr.ext.langgraph import DaprCheckpointer 2 | from langchain_core.messages import HumanMessage, SystemMessage 3 | from langchain_ollama import ChatOllama 4 | from langgraph.graph import START, MessagesState, StateGraph 5 | from langgraph.prebuilt import ToolNode, tools_condition 6 | 7 | 8 | def add(a: int, b: int) -> int: 9 | """Adds a and b. 10 | 11 | Args: 12 | a: first int 13 | b: second int 14 | """ 15 | return a + b 16 | 17 | 18 | def multiply(a: int, b: int) -> int: 19 | """Multiply a and b. 20 | 21 | Args: 22 | a: first int 23 | b: second int 24 | """ 25 | return a * b 26 | 27 | 28 | tools = [add, multiply] 29 | llm = ChatOllama(model='llama3.2:latest') 30 | llm_with_tools = llm.bind_tools(tools) 31 | 32 | sys_msg = SystemMessage( 33 | content='You are a helpful assistant tasked with performing arithmetic on a set of inputs.' 34 | ) 35 | 36 | 37 | def assistant(state: MessagesState): 38 | return {'messages': [llm_with_tools.invoke([sys_msg] + state['messages'])]} 39 | 40 | 41 | builder = StateGraph(MessagesState) 42 | 43 | builder.add_node('assistant', assistant) 44 | builder.add_node('tools', ToolNode(tools)) 45 | 46 | builder.add_edge(START, 'assistant') 47 | builder.add_conditional_edges( 48 | 'assistant', 49 | tools_condition, 50 | ) 51 | builder.add_edge('tools', 'assistant') 52 | 53 | memory = DaprCheckpointer(store_name='statestore', key_prefix='dapr') 54 | react_graph_memory = builder.compile(checkpointer=memory) 55 | 56 | config = {'configurable': {'thread_id': '1'}} 57 | 58 | messages = [HumanMessage(content='Add 3 and 4.')] 59 | messages = react_graph_memory.invoke({'messages': messages}, config) 60 | for m in messages['messages']: 61 | m.pretty_print() 62 | 63 | messages = [HumanMessage(content='Multiply the result by 2.')] 64 | messages = react_graph_memory.invoke({'messages': messages}, config) 65 | for m in messages['messages']: 66 | m.pretty_print() 67 | -------------------------------------------------------------------------------- /examples/pubsub-streaming-async/publisher.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------ 2 | # Copyright 2022 The Dapr Authors 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | # ------------------------------------------------------------ 13 | import argparse 14 | import asyncio 15 | import json 16 | 17 | from dapr.aio.clients import DaprClient 18 | 19 | parser = argparse.ArgumentParser(description='Publish events to a Dapr pub/sub topic.') 20 | parser.add_argument('--topic', type=str, required=True, help='The topic name to publish to.') 21 | args = parser.parse_args() 22 | 23 | topic_name = args.topic 24 | 25 | 26 | async def publish_events(): 27 | """ 28 | Publishes events to a pubsub topic asynchronously 29 | """ 30 | 31 | async with DaprClient() as d: 32 | id = 0 33 | while id < 5: 34 | id += 1 35 | req_data = {'id': id, 'message': 'hello world'} 36 | 37 | # Create a typed message with content type and body 38 | await d.publish_event( 39 | pubsub_name='pubsub', 40 | topic_name=topic_name, 41 | data=json.dumps(req_data), 42 | data_content_type='application/json', 43 | publish_metadata={'ttlInSeconds': '100', 'rawPayload': 'false'}, 44 | ) 45 | 46 | # Print the request 47 | print(req_data, flush=True) 48 | 49 | await asyncio.sleep(1) 50 | 51 | 52 | asyncio.run(publish_events()) 53 | -------------------------------------------------------------------------------- /dapr/actor/runtime/state_change.py: -------------------------------------------------------------------------------- 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 | from enum import Enum 17 | from typing import Generic, Optional, TypeVar 18 | 19 | T = TypeVar('T') 20 | 21 | 22 | class StateChangeKind(Enum): 23 | """A enumeration that represents the kind of state change for an actor state 24 | when saves change is called to a set of actor states. 25 | """ 26 | 27 | # No change in state 28 | none = 0 29 | # The state needs to be added 30 | add = 1 31 | # The state needs to be updated 32 | update = 2 33 | # The state needs to be removed 34 | remove = 3 35 | 36 | 37 | class ActorStateChange(Generic[T]): 38 | def __init__( 39 | self, 40 | state_name: str, 41 | value: T, 42 | change_kind: StateChangeKind, 43 | ttl_in_seconds: Optional[int] = None, 44 | ): 45 | self._state_name = state_name 46 | self._value = value 47 | self._change_kind = change_kind 48 | self._ttl_in_seconds = ttl_in_seconds 49 | 50 | @property 51 | def state_name(self) -> str: 52 | return self._state_name 53 | 54 | @property 55 | def value(self) -> T: 56 | return self._value 57 | 58 | @property 59 | def change_kind(self) -> StateChangeKind: 60 | return self._change_kind 61 | 62 | @property 63 | def ttl_in_seconds(self) -> Optional[int]: 64 | return self._ttl_in_seconds 65 | -------------------------------------------------------------------------------- /dapr/actor/runtime/method_dispatcher.py: -------------------------------------------------------------------------------- 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 | from typing import Any, Dict, List 17 | 18 | from dapr.actor.runtime._type_information import ActorTypeInformation 19 | from dapr.actor.runtime._type_utils import get_dispatchable_attrs 20 | from dapr.actor.runtime.actor import Actor 21 | 22 | 23 | class ActorMethodDispatcher: 24 | def __init__(self, type_info: ActorTypeInformation): 25 | self._dispatch_mapping = get_dispatchable_attrs(type_info.implementation_type) 26 | 27 | async def dispatch(self, actor: Actor, name: str, *args, **kwargs) -> Any: 28 | self._check_name_exist(name) 29 | return await getattr(actor, self._dispatch_mapping[name]['method_name'])(*args, **kwargs) 30 | 31 | def get_arg_names(self, name: str) -> List[str]: 32 | self._check_name_exist(name) 33 | return self._dispatch_mapping[name]['arg_names'] 34 | 35 | def get_arg_types(self, name: str) -> List[Any]: 36 | self._check_name_exist(name) 37 | return self._dispatch_mapping[name]['arg_types'] 38 | 39 | def get_return_type(self, name: str) -> Dict[str, Any]: 40 | self._check_name_exist(name) 41 | return self._dispatch_mapping[name]['return_types'] 42 | 43 | def _check_name_exist(self, name: str): 44 | if name not in self._dispatch_mapping: 45 | raise AttributeError(f'type object {self.__class__.__name__} has no method {name}') 46 | -------------------------------------------------------------------------------- /tests/actor/test_type_information.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Copyright 2021 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 unittest 17 | 18 | from dapr.actor.runtime._type_information import ActorTypeInformation 19 | from tests.actor.fake_actor_classes import ( 20 | FakeActorCls1Interface, 21 | FakeActorCls2Interface, 22 | FakeMultiInterfacesActor, 23 | FakeSimpleActor, 24 | ReentrantActorInterface, 25 | ) 26 | 27 | 28 | class ActorTypeInformationTests(unittest.TestCase): 29 | def setUp(self): 30 | pass 31 | 32 | def test_actor_type_name(self): 33 | type_info = ActorTypeInformation.create(FakeSimpleActor) 34 | self.assertEqual(FakeSimpleActor.__name__, type_info.type_name) 35 | 36 | def test_implementation_type_returns_correct_type(self): 37 | type_info = ActorTypeInformation.create(FakeSimpleActor) 38 | self.assertEqual(FakeSimpleActor, type_info.implementation_type) 39 | 40 | def test_actor_interfaces_returns_actor_classes(self): 41 | type_info = ActorTypeInformation.create(FakeMultiInterfacesActor) 42 | 43 | self.assertEqual(FakeMultiInterfacesActor.__name__, type_info.type_name) 44 | self.assertEqual(3, len(type_info.actor_interfaces)) 45 | self.assertTrue(type_info.actor_interfaces.index(FakeActorCls1Interface) >= 0) 46 | self.assertTrue(type_info.actor_interfaces.index(FakeActorCls2Interface) >= 0) 47 | self.assertTrue(type_info.actor_interfaces.index(ReentrantActorInterface) >= 0) 48 | -------------------------------------------------------------------------------- /examples/workflow/cross-app2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2025 The Dapr Authors 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | 13 | import os 14 | import time 15 | from datetime import timedelta 16 | 17 | import dapr.ext.workflow as wf 18 | from durabletask.task import TaskFailedError 19 | 20 | wfr = wf.WorkflowRuntime() 21 | 22 | 23 | @wfr.workflow 24 | def app2_workflow(ctx: wf.DaprWorkflowContext): 25 | print('app2 - received workflow call', flush=True) 26 | if os.getenv('ERROR_WORKFLOW_MODE', 'false') == 'true': 27 | print('app2 - raising error in workflow due to error mode being enabled', flush=True) 28 | raise ValueError('Error in workflow due to error mode being enabled') 29 | print('app2 - triggering app3 activity', flush=True) 30 | try: 31 | retry_policy = wf.RetryPolicy( 32 | max_number_of_attempts=2, 33 | first_retry_interval=timedelta(milliseconds=100), 34 | max_retry_interval=timedelta(seconds=3), 35 | ) 36 | yield ctx.call_activity( 37 | 'app3_activity', input=None, app_id='wfexample3', retry_policy=retry_policy 38 | ) 39 | print('app2 - received activity result', flush=True) 40 | except TaskFailedError: 41 | print('app2 - received activity error from app3', flush=True) 42 | 43 | print('app2 - returning workflow result', flush=True) 44 | return 2 45 | 46 | 47 | if __name__ == '__main__': 48 | wfr.start() 49 | time.sleep(15) # wait for workflow runtime to start 50 | wfr.shutdown() 51 | -------------------------------------------------------------------------------- /dapr/actor/runtime/_method_context.py: -------------------------------------------------------------------------------- 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 | from dapr.actor.runtime._call_type import ActorCallType 17 | 18 | 19 | class ActorMethodContext: 20 | """A Actor method context that contains method information invoked 21 | by :class:`ActorRuntime`. 22 | """ 23 | 24 | def __init__(self, method_name: str, call_type: ActorCallType): 25 | self._method_name = method_name 26 | self._calltype = call_type 27 | 28 | @property 29 | def method_name(self) -> str: 30 | """Gets the method name.""" 31 | return self._method_name 32 | 33 | @property 34 | def call_type(self) -> ActorCallType: 35 | """Gets :class:`ActorCallType` for this method.""" 36 | return self._calltype 37 | 38 | @classmethod 39 | def create_for_actor(cls, method_name: str): 40 | """Creates :class:`ActorMethodContext` object for actor method.""" 41 | return ActorMethodContext(method_name, ActorCallType.actor_interface_method) 42 | 43 | @classmethod 44 | def create_for_timer(cls, method_name: str): 45 | """Creates :class:`ActorMethodContext` object for timer_method.""" 46 | return ActorMethodContext(method_name, ActorCallType.timer_method) 47 | 48 | @classmethod 49 | def create_for_reminder(cls, method_name: str): 50 | """Creates :class:`ActorMethodContext` object for reminder_method.""" 51 | return ActorMethodContext(method_name, ActorCallType.reminder_method) 52 | -------------------------------------------------------------------------------- /tests/clients/test_dapr_grpc_response_async.py: -------------------------------------------------------------------------------- 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 unittest 17 | 18 | from dapr.aio.clients.grpc._response import DecryptResponse, EncryptResponse 19 | from dapr.proto import api_v1, common_v1 20 | 21 | 22 | class CryptoResponseAsyncTests(unittest.IsolatedAsyncioTestCase): 23 | async def response_stream(self): 24 | stream1 = common_v1.StreamPayload(data=b'hello', seq=0) 25 | stream2 = common_v1.StreamPayload(data=b' dapr', seq=1) 26 | for strm in (stream1, stream2): 27 | yield api_v1.EncryptResponse(payload=strm) 28 | 29 | async def test_encrypt_response_read_bytes(self): 30 | resp = EncryptResponse(stream=self.response_stream()) 31 | self.assertEqual(await resp.read(5), b'hello') 32 | self.assertEqual(await resp.read(5), b' dapr') 33 | 34 | async def test_encrypt_response_read_all(self): 35 | resp = EncryptResponse(stream=self.response_stream()) 36 | self.assertEqual(await resp.read(), b'hello dapr') 37 | 38 | async def test_decrypt_response_read_bytes(self): 39 | resp = DecryptResponse(stream=self.response_stream()) 40 | self.assertEqual(await resp.read(5), b'hello') 41 | self.assertEqual(await resp.read(5), b' dapr') 42 | 43 | async def test_decrypt_response_read_all(self): 44 | resp = DecryptResponse(stream=self.response_stream()) 45 | self.assertEqual(await resp.read(), b'hello dapr') 46 | 47 | 48 | if __name__ == '__main__': 49 | unittest.main() 50 | -------------------------------------------------------------------------------- /examples/workflow/cross-app1.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2025 The Dapr Authors 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | 13 | import time 14 | from datetime import timedelta 15 | 16 | import dapr.ext.workflow as wf 17 | from durabletask.task import TaskFailedError 18 | 19 | wfr = wf.WorkflowRuntime() 20 | 21 | 22 | @wfr.workflow 23 | def app1_workflow(ctx: wf.DaprWorkflowContext): 24 | print('app1 - received workflow call', flush=True) 25 | print('app1 - triggering app2 workflow', flush=True) 26 | 27 | try: 28 | retry_policy = wf.RetryPolicy( 29 | max_number_of_attempts=2, 30 | first_retry_interval=timedelta(milliseconds=100), 31 | max_retry_interval=timedelta(seconds=3), 32 | ) 33 | yield ctx.call_child_workflow( 34 | workflow='app2_workflow', 35 | input=None, 36 | app_id='wfexample2', 37 | retry_policy=retry_policy, 38 | ) 39 | print('app1 - received workflow result', flush=True) 40 | except TaskFailedError: 41 | print('app1 - received workflow error from app2', flush=True) 42 | 43 | print('app1 - returning workflow result', flush=True) 44 | return 1 45 | 46 | 47 | if __name__ == '__main__': 48 | wfr.start() 49 | time.sleep(10) # wait for workflow runtime to start 50 | 51 | wf_client = wf.DaprWorkflowClient() 52 | print('app1 - triggering app1 workflow', flush=True) 53 | instance_id = wf_client.schedule_new_workflow(workflow=app1_workflow) 54 | 55 | # Wait for the workflow to complete 56 | time.sleep(7) 57 | 58 | wfr.shutdown() 59 | -------------------------------------------------------------------------------- /examples/distributed_lock/lock.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------ 2 | # Copyright 2021 The Dapr Authors 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | # ------------------------------------------------------------ 13 | 14 | import warnings 15 | 16 | from dapr.clients import DaprClient 17 | 18 | 19 | def main(): 20 | # Lock parameters 21 | store_name = 'lockstore' # as defined in components/lockstore.yaml 22 | resource_id = 'example-lock-resource' 23 | client_id = 'example-client-id' 24 | expiry_in_seconds = 60 25 | 26 | with DaprClient() as dapr: 27 | print('Will try to acquire a lock from lock store named [%s]' % store_name) 28 | print('The lock is for a resource named [%s]' % resource_id) 29 | print('The client identifier is [%s]' % client_id) 30 | print('The lock will will expire in %s seconds.' % expiry_in_seconds) 31 | 32 | with dapr.try_lock(store_name, resource_id, client_id, expiry_in_seconds) as lock_result: 33 | assert lock_result.success, 'Failed to acquire the lock. Aborting.' 34 | print('Lock acquired successfully!!!') 35 | 36 | # At this point the lock was released - by magic of the `with` clause ;) 37 | unlock_result = dapr.unlock(store_name, resource_id, client_id) 38 | print('We already released the lock so unlocking will not work.') 39 | print('We tried to unlock it anyway and got back [%s]' % unlock_result.status) 40 | 41 | 42 | if __name__ == '__main__': 43 | # Suppress "The Distributed Lock API is an Alpha" warnings 44 | warnings.simplefilter('ignore') 45 | main() 46 | -------------------------------------------------------------------------------- /tests/clients/test_client_interceptor.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Copyright 2021 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 unittest 17 | 18 | from dapr.clients.grpc.interceptors import DaprClientInterceptor, _ClientCallDetails 19 | 20 | 21 | class DaprClientInterceptorTests(unittest.TestCase): 22 | def setUp(self): 23 | self._fake_request = 'fake request' 24 | 25 | def fake_continuation(self, call_details, request): 26 | return call_details 27 | 28 | def test_intercept_unary_unary_single_header(self): 29 | interceptor = DaprClientInterceptor([('api-token', 'test-token')]) 30 | call_details = _ClientCallDetails('method1', 10, None, None, None, None) 31 | response = interceptor.intercept_unary_unary( 32 | self.fake_continuation, call_details, self._fake_request 33 | ) 34 | 35 | self.assertIsNotNone(response) 36 | self.assertEqual(1, len(response.metadata)) 37 | self.assertEqual([('api-token', 'test-token')], response.metadata) 38 | 39 | def test_intercept_unary_unary_existing_metadata(self): 40 | interceptor = DaprClientInterceptor([('api-token', 'test-token')]) 41 | call_details = _ClientCallDetails('method1', 10, [('header', 'value')], None, None, None) 42 | response = interceptor.intercept_unary_unary( 43 | self.fake_continuation, call_details, self._fake_request 44 | ) 45 | 46 | self.assertIsNotNone(response) 47 | self.assertEqual(2, len(response.metadata)) 48 | self.assertEqual([('header', 'value'), ('api-token', 'test-token')], response.metadata) 49 | -------------------------------------------------------------------------------- /examples/grpc_proxying/helloworld_service_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: helloworld_service.proto 4 | """Generated protocol buffer code.""" 5 | 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import message as _message 9 | from google.protobuf import reflection as _reflection 10 | from google.protobuf import symbol_database as _symbol_database 11 | 12 | # @@protoc_insertion_point(imports) 13 | 14 | _sym_db = _symbol_database.Default() 15 | 16 | 17 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( 18 | b'\n\x18helloworld_service.proto"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2=\n\x11HelloWorldService\x12(\n\x08SayHello\x12\r.HelloRequest\x1a\x0b.HelloReply"\x00\x62\x06proto3' 19 | ) 20 | 21 | 22 | _HELLOREQUEST = DESCRIPTOR.message_types_by_name['HelloRequest'] 23 | _HELLOREPLY = DESCRIPTOR.message_types_by_name['HelloReply'] 24 | HelloRequest = _reflection.GeneratedProtocolMessageType( 25 | 'HelloRequest', 26 | (_message.Message,), 27 | { 28 | 'DESCRIPTOR': _HELLOREQUEST, 29 | '__module__': 'helloworld_service_pb2', 30 | # @@protoc_insertion_point(class_scope:HelloRequest) 31 | }, 32 | ) 33 | _sym_db.RegisterMessage(HelloRequest) 34 | 35 | HelloReply = _reflection.GeneratedProtocolMessageType( 36 | 'HelloReply', 37 | (_message.Message,), 38 | { 39 | 'DESCRIPTOR': _HELLOREPLY, 40 | '__module__': 'helloworld_service_pb2', 41 | # @@protoc_insertion_point(class_scope:HelloReply) 42 | }, 43 | ) 44 | _sym_db.RegisterMessage(HelloReply) 45 | 46 | _HELLOWORLDSERVICE = DESCRIPTOR.services_by_name['HelloWorldService'] 47 | if _descriptor._USE_C_DESCRIPTORS == False: 48 | DESCRIPTOR._options = None 49 | _HELLOREQUEST._serialized_start = 28 50 | _HELLOREQUEST._serialized_end = 56 51 | _HELLOREPLY._serialized_start = 58 52 | _HELLOREPLY._serialized_end = 87 53 | _HELLOWORLDSERVICE._serialized_start = 89 54 | _HELLOWORLDSERVICE._serialized_end = 150 55 | # @@protoc_insertion_point(module_scope) 56 | -------------------------------------------------------------------------------- /tests/actor/test_timer_data.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Copyright 2021 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 unittest 17 | from datetime import timedelta 18 | from typing import Any 19 | 20 | from dapr.actor.runtime._timer_data import ActorTimerData 21 | 22 | 23 | class ActorTimerDataTests(unittest.TestCase): 24 | def test_timer_data(self): 25 | def my_callback(input: Any): 26 | print(input) 27 | 28 | timer = ActorTimerData( 29 | 'timer_name', 30 | my_callback, 31 | 'called', 32 | timedelta(seconds=2), 33 | timedelta(seconds=1), 34 | timedelta(seconds=3), 35 | ) 36 | self.assertEqual('timer_name', timer.timer_name) 37 | self.assertEqual('my_callback', timer.callback) 38 | self.assertEqual('called', timer.state) 39 | self.assertEqual(timedelta(seconds=2), timer.due_time) 40 | self.assertEqual(timedelta(seconds=1), timer.period) 41 | self.assertEqual(timedelta(seconds=3), timer.ttl) 42 | 43 | def test_as_dict(self): 44 | def my_callback(input: Any): 45 | print(input) 46 | 47 | timer = ActorTimerData( 48 | 'timer_name', 49 | my_callback, 50 | 'called', 51 | timedelta(seconds=1), 52 | timedelta(seconds=1), 53 | timedelta(seconds=1), 54 | ) 55 | expected = { 56 | 'callback': 'my_callback', 57 | 'data': 'called', 58 | 'dueTime': timedelta(seconds=1), 59 | 'period': timedelta(seconds=1), 60 | 'ttl': timedelta(seconds=1), 61 | } 62 | self.assertDictEqual(expected, timer.as_dict()) 63 | -------------------------------------------------------------------------------- /examples/configuration/README.md: -------------------------------------------------------------------------------- 1 | # Example - Get Configuration 2 | 3 | This example demonstrates the Configuration APIs in Dapr. 4 | It demonstrates the following APIs: 5 | - **configuration**: Get configuration from statestore 6 | 7 | > **Note:** Make sure to use the latest proto bindings 8 | 9 | ## Pre-requisites 10 | 11 | - [Dapr CLI and initialized environment](https://docs.dapr.io/getting-started) 12 | - [Install Python 3.9+](https://www.python.org/downloads/) 13 | 14 | ## Install Dapr python-SDK 15 | 16 | <!-- Our CI/CD pipeline automatically installs the correct version, so we can skip this step in the automation --> 17 | ```bash 18 | pip3 install dapr dapr-ext-grpc 19 | ``` 20 | 21 | ## Store the configuration in configurationstore 22 | <!-- STEP 23 | name: Set configuration value 24 | expected_stdout_lines: 25 | - "OK" 26 | timeout_seconds: 5 27 | sleep: 3 28 | --> 29 | 30 | ```bash 31 | docker exec dapr_redis redis-cli SET orderId1 "100||1" 32 | docker exec dapr_redis redis-cli SET orderId2 "200||1" 33 | ``` 34 | 35 | <!-- END_STEP --> 36 | 37 | ## Run configuration example 38 | 39 | Change directory to this folder: 40 | ```bash 41 | cd examples/configuration 42 | ``` 43 | 44 | To run this example, use the following command: 45 | 46 | <!-- STEP 47 | name: Run get configuration example 48 | match_order: none 49 | expected_stdout_lines: 50 | - "== APP == Got key=orderId1 value=100 version=1 metadata={}" 51 | - "== APP == Got key=orderId2 value=200 version=1 metadata={}" 52 | - "== APP == Subscribe key=orderId2 value=210 version=2 metadata={}" 53 | - "== APP == Unsubscribed successfully? True" 54 | background: true 55 | timeout_seconds: 30 56 | sleep: 3 57 | --> 58 | 59 | ```bash 60 | dapr run --app-id configexample --resources-path components/ -- python3 configuration.py 61 | ``` 62 | <!-- END_STEP --> 63 | 64 | <!-- STEP 65 | name: Set configuration value 66 | expected_stdout_lines: 67 | - "OK" 68 | timeout_seconds: 5 69 | --> 70 | 71 | ```bash 72 | docker exec dapr_redis redis-cli SET orderId2 "210||2" 73 | ``` 74 | <!-- END_STEP --> 75 | 76 | You should be able to see the following output: 77 | ``` 78 | == APP == Got key=orderId1 value=100 version=1 79 | == APP == Got key=orderId2 value=200 version=1 80 | == APP == Subscribe key=orderId2 value=210 version=2 81 | ``` 82 | -------------------------------------------------------------------------------- /examples/state_store_query/dataset.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "key": "1", 4 | "value": { 5 | "person": { 6 | "org": "Dev Ops", 7 | "id": 1036 8 | }, 9 | "city": "Seattle", 10 | "state": "WA" 11 | } 12 | }, 13 | { 14 | "key": "2", 15 | "value": { 16 | "person": { 17 | "org": "Hardware", 18 | "id": 1028 19 | }, 20 | "city": "Portland", 21 | "state": "OR" 22 | } 23 | }, 24 | { 25 | "key": "3", 26 | "value": { 27 | "person": { 28 | "org": "Finance", 29 | "id": 1071 30 | }, 31 | "city": "Sacramento", 32 | "state": "CA" 33 | } 34 | }, 35 | { 36 | "key": "4", 37 | "value": { 38 | "person": { 39 | "org": "Dev Ops", 40 | "id": 1042 41 | }, 42 | "city": "Spokane", 43 | "state": "WA" 44 | } 45 | }, 46 | { 47 | "key": "5", 48 | "value": { 49 | "person": { 50 | "org": "Hardware", 51 | "id": 1007 52 | }, 53 | "city": "Los Angeles", 54 | "state": "CA" 55 | } 56 | }, 57 | { 58 | "key": "6", 59 | "value": { 60 | "person": { 61 | "org": "Finance", 62 | "id": 1094 63 | }, 64 | "city": "Eugene", 65 | "state": "OR" 66 | } 67 | }, 68 | { 69 | "key": "7", 70 | "value": { 71 | "person": { 72 | "org": "Dev Ops", 73 | "id": 1015 74 | }, 75 | "city": "San Francisco", 76 | "state": "CA" 77 | } 78 | }, 79 | { 80 | "key": "8", 81 | "value": { 82 | "person": { 83 | "org": "Hardware", 84 | "id": 1077 85 | }, 86 | "city": "Redmond", 87 | "state": "WA" 88 | } 89 | }, 90 | { 91 | "key": "9", 92 | "value": { 93 | "person": { 94 | "org": "Finance", 95 | "id": 1002 96 | }, 97 | "city": "San Diego", 98 | "state": "CA" 99 | } 100 | }, 101 | { 102 | "key": "10", 103 | "value": { 104 | "person": { 105 | "org": "Dev Ops", 106 | "id": 1054 107 | }, 108 | "city": "New York", 109 | "state": "NY" 110 | } 111 | } 112 | ] 113 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Copyright 2021 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 os 17 | 18 | from setuptools import setup 19 | 20 | # Load version in dapr package. 21 | version_info = {} 22 | with open('dapr/version/version.py') as fp: 23 | exec(fp.read(), version_info) 24 | __version__ = version_info['__version__'] 25 | 26 | 27 | def is_release(): 28 | return '.dev' not in __version__ 29 | 30 | 31 | name = 'dapr' 32 | version = __version__ 33 | description = 'The official release of Dapr Python SDK.' 34 | long_description = """ 35 | Dapr is a portable, serverless, event-driven runtime that makes it easy for developers to 36 | build resilient, stateless and stateful microservices that run on the cloud and edge and 37 | embraces the diversity of languages and developer frameworks. 38 | 39 | Dapr codifies the best practices for building microservice applications into open, 40 | independent, building blocks that enable you to build portable applications with the language 41 | and framework of your choice. Each building block is independent and you can use one, some, 42 | or all of them in your application. 43 | """.lstrip() 44 | 45 | # Get build number from GITHUB_RUN_NUMBER environment variable 46 | build_number = os.environ.get('GITHUB_RUN_NUMBER', '0') 47 | 48 | if not is_release(): 49 | name += '-dev' 50 | version = f'{__version__}{build_number}' 51 | description = 'The developmental release for Dapr Python SDK.' 52 | long_description = 'This is the developmental release for Dapr Python SDK.' 53 | 54 | print(f'package name: {name}, version: {version}', flush=True) 55 | 56 | 57 | setup( 58 | name=name, 59 | version=version, 60 | description=description, 61 | long_description=long_description, 62 | package_data={'': ['py.typed']}, 63 | ) 64 | -------------------------------------------------------------------------------- /examples/metadata/app.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------ 2 | # Copyright 2021 The Dapr Authors 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | # ------------------------------------------------------------ 13 | 14 | from dapr.clients import DaprClient 15 | 16 | 17 | def main(): 18 | extended_attribute_name = 'is-this-our-metadata-example' 19 | 20 | with DaprClient() as dapr: 21 | print('First, we will assign a new custom label to Dapr sidecar') 22 | # We do this so example can be made deterministic across 23 | # multiple invocations. 24 | original_value = 'yes' 25 | dapr.set_metadata(extended_attribute_name, original_value) 26 | 27 | print("Now, we will fetch the sidecar's metadata") 28 | metadata = dapr.get_metadata() 29 | old_value = metadata.extended_metadata[extended_attribute_name] 30 | 31 | print('And this is what we got:') 32 | print(f' application_id: {metadata.application_id}') 33 | print(f' active_actors_count: {metadata.active_actors_count}') 34 | print(' registered_components:') 35 | for name, type, version, caps in sorted(metadata.registered_components): 36 | print(f' name={name} type={type} version={version} capabilities={sorted(caps)}') 37 | 38 | print('We will update our custom label value and check it was persisted') 39 | dapr.set_metadata(extended_attribute_name, 'You bet it is!') 40 | metadata = dapr.get_metadata() 41 | new_value = metadata.extended_metadata[extended_attribute_name] 42 | print('We added a custom label named [%s]' % extended_attribute_name) 43 | print('Its old value was [%s] but now it is [%s]' % (old_value, new_value)) 44 | 45 | print('And we are done 👋', flush=True) 46 | 47 | 48 | if __name__ == '__main__': 49 | main() 50 | -------------------------------------------------------------------------------- /ext/flask_dapr/setup.py: -------------------------------------------------------------------------------- 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 os 17 | 18 | from setuptools import setup 19 | 20 | # Load version in dapr package. 21 | version_info = {} 22 | with open('flask_dapr/version.py') as fp: 23 | exec(fp.read(), version_info) 24 | __version__ = version_info['__version__'] 25 | 26 | 27 | def is_release(): 28 | return '.dev' not in __version__ 29 | 30 | 31 | name = 'flask-dapr' 32 | version = __version__ 33 | description = 'The official release of Dapr Python SDK Flask Extension.' 34 | long_description = """ 35 | This is the Flask extension for Dapr. 36 | 37 | Dapr is a portable, serverless, event-driven runtime that makes it easy for developers to 38 | build resilient, stateless and stateful microservices that run on the cloud and edge and 39 | embraces the diversity of languages and developer frameworks. 40 | 41 | Dapr codifies the best practices for building microservice applications into open, 42 | independent, building blocks that enable you to build portable applications with the language 43 | and framework of your choice. Each building block is independent and you can use one, some, 44 | or all of them in your application. 45 | """.lstrip() 46 | 47 | # Get build number from GITHUB_RUN_NUMBER environment variable 48 | build_number = os.environ.get('GITHUB_RUN_NUMBER', '0') 49 | 50 | if not is_release(): 51 | name += '-dev' 52 | version = f'{__version__}{build_number}' 53 | description = 'The developmental release for Dapr Python SDK Flask.' 54 | long_description = 'This is the developmental release for Dapr Python SDK Flask.' 55 | 56 | print(f'package name: {name}, version: {version}', flush=True) 57 | 58 | 59 | setup( 60 | name=name, 61 | version=version, 62 | description=description, 63 | long_description=long_description, 64 | ) 65 | -------------------------------------------------------------------------------- /tests/clients/test_timeout_interceptor_async.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Copyright 2024 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 unittest 17 | from unittest.mock import Mock, patch 18 | 19 | from dapr.aio.clients.grpc.interceptors import DaprClientTimeoutInterceptorAsync 20 | from dapr.conf import settings 21 | 22 | 23 | class DaprClientTimeoutInterceptorAsyncTests(unittest.TestCase): 24 | def test_intercept_unary_unary_with_timeout(self): 25 | continuation = Mock() 26 | request = Mock() 27 | client_call_details = Mock() 28 | client_call_details.method = 'method' 29 | client_call_details.timeout = 10 30 | client_call_details.metadata = 'metadata' 31 | client_call_details.credentials = 'credentials' 32 | client_call_details.wait_for_ready = 'wait_for_ready' 33 | 34 | DaprClientTimeoutInterceptorAsync().intercept_unary_unary( 35 | continuation, client_call_details, request 36 | ) 37 | continuation.assert_called_once_with(client_call_details, request) 38 | 39 | @patch.object(settings, 'DAPR_API_TIMEOUT_SECONDS', 7) 40 | def test_intercept_unary_unary_without_timeout(self): 41 | continuation = Mock() 42 | request = Mock() 43 | client_call_details = Mock() 44 | client_call_details.method = 'method' 45 | client_call_details.timeout = None 46 | client_call_details.metadata = 'metadata' 47 | client_call_details.credentials = 'credentials' 48 | client_call_details.wait_for_ready = 'wait_for_ready' 49 | 50 | DaprClientTimeoutInterceptorAsync().intercept_unary_unary( 51 | continuation, client_call_details, request 52 | ) 53 | called_client_call_details = continuation.call_args[0][0] 54 | self.assertEqual(7, called_client_call_details.timeout) 55 | -------------------------------------------------------------------------------- /ext/dapr-ext-grpc/setup.py: -------------------------------------------------------------------------------- 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 os 17 | 18 | from setuptools import setup 19 | 20 | # Load version in dapr package. 21 | version_info = {} 22 | with open('dapr/ext/grpc/version.py') as fp: 23 | exec(fp.read(), version_info) 24 | __version__ = version_info['__version__'] 25 | 26 | 27 | def is_release(): 28 | return '.dev' not in __version__ 29 | 30 | 31 | name = 'dapr-ext-grpc' 32 | version = __version__ 33 | description = 'The official release of Dapr Python SDK gRPC Extension.' 34 | long_description = """ 35 | This is the gRPC extension for Dapr. 36 | 37 | Dapr is a portable, serverless, event-driven runtime that makes it easy for developers to 38 | build resilient, stateless and stateful microservices that run on the cloud and edge and 39 | embraces the diversity of languages and developer frameworks. 40 | 41 | Dapr codifies the best practices for building microservice applications into open, 42 | independent, building blocks that enable you to build portable applications with the language 43 | and framework of your choice. Each building block is independent and you can use one, some, 44 | or all of them in your application. 45 | """.lstrip() 46 | 47 | # Get build number from GITHUB_RUN_NUMBER environment variable 48 | build_number = os.environ.get('GITHUB_RUN_NUMBER', '0') 49 | 50 | if not is_release(): 51 | name += '-dev' 52 | version = f'{__version__}{build_number}' 53 | description = 'The developmental release for Dapr gRPC AppCallback.' 54 | long_description = 'This is the developmental release for Dapr gRPC AppCallback.' 55 | 56 | print(f'package name: {name}, version: {version}', flush=True) 57 | 58 | 59 | setup( 60 | name=name, 61 | version=version, 62 | description=description, 63 | long_description=long_description, 64 | ) 65 | -------------------------------------------------------------------------------- /ext/dapr-ext-fastapi/setup.py: -------------------------------------------------------------------------------- 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 os 17 | 18 | from setuptools import setup 19 | 20 | # Load version in dapr package. 21 | version_info = {} 22 | with open('dapr/ext/fastapi/version.py') as fp: 23 | exec(fp.read(), version_info) 24 | __version__ = version_info['__version__'] 25 | 26 | 27 | def is_release(): 28 | return '.dev' not in __version__ 29 | 30 | 31 | name = 'dapr-ext-fastapi' 32 | version = __version__ 33 | description = 'The official release of Dapr FastAPI extension.' 34 | long_description = """ 35 | This is the FastAPI extension for Dapr. 36 | 37 | Dapr is a portable, serverless, event-driven runtime that makes it easy for developers to 38 | build resilient, stateless and stateful microservices that run on the cloud and edge and 39 | embraces the diversity of languages and developer frameworks. 40 | 41 | Dapr codifies the best practices for building microservice applications into open, 42 | independent, building blocks that enable you to build portable applications with the language 43 | and framework of your choice. Each building block is independent and you can use one, some, 44 | or all of them in your application. 45 | """.lstrip() 46 | 47 | # Get build number from GITHUB_RUN_NUMBER environment variable 48 | build_number = os.environ.get('GITHUB_RUN_NUMBER', '0') 49 | 50 | if not is_release(): 51 | name += '-dev' 52 | version = f'{__version__}{build_number}' 53 | description = 'The developmental release for Dapr FastAPI extension.' 54 | long_description = 'This is the developmental release for Dapr FastAPI extension.' 55 | 56 | print(f'package name: {name}, version: {version}', flush=True) 57 | 58 | 59 | setup( 60 | name=name, 61 | version=version, 62 | description=description, 63 | long_description=long_description, 64 | ) 65 | --------------------------------------------------------------------------------