def test_transaction_then_get_states(self): dapr = DaprClient(f'localhost:{self.server_port}') key = str(uuid.uuid4()) value = str(uuid.uuid4()) another_key = str(uuid.uuid4()) another_value = str(uuid.uuid4()) dapr.execute_transaction( store_name="statestore", operations=[ TransactionalStateOperation(key=key, data=value), TransactionalStateOperation(key=another_key, data=another_value), ], transactional_metadata={"metakey": "metavalue"}) resp = dapr.get_states(store_name="statestore", keys=[key, another_key]) self.assertEqual(resp.items[0].key, key) self.assertEqual(resp.items[0].data, to_bytes(value)) self.assertEqual(resp.items[1].key, another_key) self.assertEqual(resp.items[1].data, to_bytes(another_value)) resp = dapr.get_states(store_name="statestore", keys=[key, another_key], states_metadata={"upper": "1"}) self.assertEqual(resp.items[0].key, key) self.assertEqual(resp.items[0].data, to_bytes(value.upper())) self.assertEqual(resp.items[1].key, another_key) self.assertEqual(resp.items[1].data, to_bytes(another_value.upper()))
def test_get_save_delete_state(self): dapr = DaprClient(f'localhost:{self.server_port}') key = "key_1" value = "value_1" options = StateOptions( consistency=Consistency.eventual, concurrency=Concurrency.first_write, ) dapr.save_state(store_name="statestore", key=key, value=value, options=options, state_metadata={"capitalize": "1"}) resp = dapr.get_state(store_name="statestore", key=key) self.assertEqual(resp.data, to_bytes(value.capitalize())) resp = dapr.get_state(store_name="statestore", key=key, state_metadata={"upper": "1"}) self.assertEqual(resp.data, to_bytes(value.upper())) resp = dapr.get_state(store_name="statestore", key="NotValidKey") self.assertEqual(resp.data, b'') dapr.delete_state(store_name="statestore", key=key) resp = dapr.get_state(store_name="statestore", key=key) self.assertEqual(resp.data, b'') with self.assertRaises(Exception) as context: dapr.delete_state(store_name="statestore", key=key, state_metadata={"must_delete": "1"}) print(context.exception) self.assertTrue('delete failed' in str(context.exception))
def test_save_then_get_states(self): dapr = DaprClient(f'localhost:{self.server_port}') key = str(uuid.uuid4()) value = str(uuid.uuid4()) another_key = str(uuid.uuid4()) another_value = str(uuid.uuid4()) dapr.save_states(store_name="statestore", states=[ StateItem(key=key, value=value, metadata={"capitalize": "1"}), StateItem(key=another_key, value=another_value, etag="1"), ], metadata=(("metakey", "metavalue"), )) resp = dapr.get_states(store_name="statestore", keys=[key, another_key]) self.assertEqual(resp.items[0].key, key) self.assertEqual(resp.items[0].data, to_bytes(value.capitalize())) self.assertEqual(resp.items[1].key, another_key) self.assertEqual(resp.items[1].data, to_bytes(another_value)) resp = dapr.get_states(store_name="statestore", keys=[key, another_key], states_metadata={"upper": "1"}) self.assertEqual(resp.items[0].key, key) self.assertEqual(resp.items[0].etag, "fake_etag") self.assertEqual(resp.items[0].data, to_bytes(value.upper())) self.assertEqual(resp.items[1].key, another_key) self.assertEqual(resp.items[1].etag, "fake_etag") self.assertEqual(resp.items[1].data, to_bytes(another_value.upper()))
def save_state( self, store_name: str, key: str, value: Union[bytes, str], etag: Optional[str] = None, options: Optional[StateOptions] = None, metadata: Optional[MetadataTuple] = () ) -> DaprResponse: """Saves key-value pairs to a statestore This saves a value to the statestore with a given key and state store name. Options for request can be passed with the options field and custom metadata can be passed with metadata field. The example saves states to a statestore: from dapr import DaprClient with DaprClient() as d: resp = d.save_state( store_name='state_store' states=[{'key': 'key1', 'value': 'value1'}], etag='etag', metadata=( ('header1', 'value1') ), ) Args: store_name (str): the state store name to save to key (str): the key to be saved value (bytes or str): the value to be saved etag (str, optional): the etag to save with options (StateOptions, optional): custom options for concurrency and consistency metadata (tuple, optional): custom metadata Returns: :class:`DaprResponse` gRPC metadata returned from callee """ if not isinstance(value, (bytes, str)): raise ValueError(f'invalid type for data {type(value)}') req_value = value if len(store_name) == 0 or len(store_name.strip()) == 0: raise ValueError("State store name cannot be empty") if options is None: state_options = None else: state_options = options.get_proto() state = common_v1.StateItem(key=key, value=to_bytes(req_value), etag=etag, options=state_options) req = api_v1.SaveStateRequest(store_name=store_name, states=[state]) response, call = self._stub.SaveState.with_call(req, metadata=metadata) return DaprResponse(headers=call.initial_metadata())
def execute_state_transaction( self, store_name: str, operations: Sequence[TransactionalStateOperation], transactional_metadata: Optional[Dict[str, str]] = dict(), metadata: Optional[MetadataTuple] = () ) -> DaprResponse: """Saves or deletes key-value pairs to a statestore as a transaction This saves or deletes key-values to the statestore as part of a single transaction, transaction_metadata is used for the transaction operation, while metadata is used for the GRPC call. The example saves states to a statestore: from dapr import DaprClient with DaprClient() as d: resp = d.execute_state_transaction( store_name='state_store', operations=[ TransactionalStateOperation(key=key, data=value), TransactionalStateOperation(key=another_key, data=another_value), TransactionalStateOperation( operation_type=TransactionOperationType.delete, key=key_to_delete), ], transactional_metadata={"header1": "value1"}, metadata=( ('header1', 'value1') ), ) Args: store_name (str): the state store name to save to operations (Sequence[TransactionalStateOperation]): the transaction operations transactional_metadata (Dict[str, str], optional): custom metadata for transaction metadata (tuple, optional): custom grpc metadata Returns: :class:`DaprResponse` gRPC metadata returned from callee """ if not store_name or len(store_name) == 0 or len( store_name.strip()) == 0: raise ValueError("State store name cannot be empty") req_ops = [ api_v1.TransactionalStateOperation( operationType=o.operation_type.value, request=common_v1.StateItem(key=o.key, value=to_bytes(o.data), etag=o.etag)) for o in operations ] req = api_v1.ExecuteStateTransactionRequest( storeName=store_name, operations=req_ops, metadata=transactional_metadata) _, call = self._stub.ExecuteStateTransaction.with_call( req, metadata=metadata) return DaprResponse(headers=call.initial_metadata())
def save_bulk_state( self, store_name: str, states: List[StateItem], metadata: Optional[MetadataTuple] = () ) -> DaprResponse: """Saves state items to a statestore This saves a given state item into the statestore specified by store_name. The example saves states to a statestore: from dapr import DaprClient with DaprClient() as d: resp = d.save_bulk_state( store_name='state_store', states=[StateItem(key='key1', value='value1'), StateItem(key='key2', value='value2', etag='etag'),], ) Args: store_name (str): the state store name to save to states (List[StateItem]): list of states to save metadata (tuple, optional): gRPC custom metadata Returns: :class:`DaprResponse` gRPC metadata returned from callee Raises: ValueError: states is empty ValueError: store_name is empty """ if metadata is not None: warn( 'metadata argument is deprecated. Dapr already intercepts API token headers ' 'and this is not needed.', DeprecationWarning, stacklevel=2) if not states or len(states) == 0: raise ValueError("States to be saved cannot be empty") if not store_name or len(store_name) == 0 or len( store_name.strip()) == 0: raise ValueError("State store name cannot be empty") req_states = [ common_v1.StateItem( key=i.key, value=to_bytes(i.value), etag=common_v1.Etag( value=i.etag) if i.etag is not None else None, options=i.options, metadata=i.metadata) for i in states ] req = api_v1.SaveStateRequest(store_name=store_name, states=req_states) _, call = self._stub.SaveState.with_call(req, metadata=metadata) return DaprResponse(headers=call.initial_metadata())
def execute_state_transaction( self, store_name: str, operations: Sequence[TransactionalStateOperation], transactional_metadata: Optional[Dict[str, str]] = dict(), metadata: Optional[MetadataTuple] = None) -> DaprResponse: """Saves or deletes key-value pairs to a statestore as a transaction This saves or deletes key-values to the statestore as part of a single transaction, transaction_metadata is used for the transaction operation, while metadata is used for the GRPC call. The example saves states to a statestore: from dapr import DaprClient with DaprClient() as d: resp = d.execute_state_transaction( store_name='state_store', operations=[ TransactionalStateOperation(key=key, data=value), TransactionalStateOperation(key=another_key, data=another_value), TransactionalStateOperation( operation_type=TransactionOperationType.delete, key=key_to_delete), ], transactional_metadata={"header1": "value1"}, ) Args: store_name (str): the state store name to save to operations (Sequence[TransactionalStateOperation]): the transaction operations transactional_metadata (Dict[str, str], optional): Dapr metadata for transaction metadata (tuple, optional, DEPRECATED): gRPC custom metadata Returns: :class:`DaprResponse` gRPC metadata returned from callee """ if metadata is not None: warn('metadata argument is deprecated. Dapr already intercepts API token headers ' 'and this is not needed.', DeprecationWarning, stacklevel=2) if not store_name or len(store_name) == 0 or len(store_name.strip()) == 0: raise ValueError("State store name cannot be empty") req_ops = [api_v1.TransactionalStateOperation( operationType=o.operation_type.value, request=common_v1.StateItem( key=o.key, value=to_bytes(o.data), etag=common_v1.Etag(value=o.etag) if o.etag is not None else None)) for o in operations] req = api_v1.ExecuteStateTransactionRequest( storeName=store_name, operations=req_ops, metadata=transactional_metadata) _, call = self._stub.ExecuteStateTransaction.with_call(req, metadata=metadata) return DaprResponse( headers=call.initial_metadata())
def GetState(self, request, context): key = request.key if key not in self.store: return empty_pb2.Empty() else: data, etag = self.store[key] if request.metadata["upper"]: data = to_bytes(data.decode("utf-8").upper()) return api_v1.GetStateResponse(data=data, etag=etag)
def set_data(self, val: Union[str, bytes, GrpcAny, GrpcMessage, None]) -> None: """Sets data to request data.""" if val is None: self._data = GrpcAny() elif isinstance(val, (bytes, str)): self._data = GrpcAny(value=to_bytes(val)) elif isinstance(val, (GrpcAny, GrpcMessage)): self.pack(val) else: raise ValueError(f'invalid data type {type(val)}')
def GetBulkState(self, request, context): items = [] for key in request.keys: req = api_v1.GetStateRequest(store_name=request.store_name, key=key) res = self.GetState(req, context) data = res.data etag = res.etag if request.metadata["upper"]: data = to_bytes(data.decode("utf-8").upper()) items.append(api_v1.BulkStateItem(key=key, etag=etag, data=data)) return api_v1.GetBulkStateResponse(items=items)
def SaveState(self, request, context): headers = () trailers = () for state in request.states: data = state.value if state.metadata["capitalize"]: data = to_bytes(data.decode("utf-8").capitalize()) self.store[state.key] = data context.send_initial_metadata(headers) context.set_trailing_metadata(trailers) return empty_pb2.Empty()
def save_bulk_state( self, store_name: str, states: List[StateItem], metadata: Optional[MetadataTuple] = () ) -> DaprResponse: """Saves state items to a statestore This saves a given state item into the statestore specified by store_name. The example saves states to a statestore: from dapr import DaprClient with DaprClient() as d: resp = d.save_bulk_state( store_name='state_store' states=[StateItem(key='key1', value='value1'), StateItem(key='key2', value='value2', etag='etag'),], metadata=( ('header1', 'value1') ), ) Args: store_name (str): the state store name to save to states (List[StateItem]): list of states to save metadata (tuple, optional): custom metadata Returns: :class:`DaprResponse` gRPC metadata returned from callee Raises: ValueError: states is empty ValueError: store_name is empty """ if not states or len(states) == 0: raise ValueError("States to be saved cannot be empty") if not store_name or len(store_name) == 0 or len( store_name.strip()) == 0: raise ValueError("State store name cannot be empty") req_states = [ common_v1.StateItem(key=i.key, value=to_bytes(i.value), etag=i.etag, options=i.options, metadata=i.metadata) for i in states ] req = api_v1.SaveStateRequest(store_name=store_name, states=req_states) _, call = self._stub.SaveState.with_call(req, metadata=metadata) return DaprResponse(headers=call.initial_metadata())
def test_get_save_state_etag_none(self): dapr = DaprGrpcClient(f'localhost:{self.server_port}') value = 'test' no_etag_key = 'no_etag' empty_etag_key = 'empty_etag' dapr.save_state( store_name="statestore", key=no_etag_key, value=value, ) dapr.save_state(store_name="statestore", key=empty_etag_key, value=value, etag="") resp = dapr.get_state(store_name="statestore", key=no_etag_key) self.assertEqual(resp.data, to_bytes(value)) self.assertEqual(resp.etag, "ETAG_WAS_NONE") resp = dapr.get_state(store_name="statestore", key=empty_etag_key) self.assertEqual(resp.data, to_bytes(value)) self.assertEqual(resp.etag, "")
def SaveState(self, request, context): headers = () trailers = () for state in request.states: data = state.value if state.metadata["capitalize"]: data = to_bytes(data.decode("utf-8").capitalize()) if state.HasField('etag'): self.store[state.key] = (data, state.etag.value) else: self.store[state.key] = (data, 'ETAG_WAS_NONE') context.send_initial_metadata(headers) context.set_trailing_metadata(trailers) return empty_pb2.Empty()
def test_get_save_delete_state(self): dapr = DaprClient(f'localhost:{self.server_port}') key = "key_1" value = "value_1" options = StateOptions( consistency=Consistency.eventual, concurrency=Concurrency.first_write, ) dapr.save_state(store_name="statestore", key=key, value=value, options=options) resp = dapr.get_state(store_name="statestore", key=key) self.assertEqual(resp.data, to_bytes(value)) resp = dapr.get_state(store_name="statestore", key="NotValidKey") self.assertEqual(resp.data, b'') dapr.delete_state(store_name="statestore", key=key) resp = dapr.get_state(store_name="statestore", key=key) self.assertEqual(resp.data, b'')
def save_state( self, store_name: str, key: str, value: Union[bytes, str], etag: Optional[str] = None, options: Optional[StateOptions] = None, state_metadata: Optional[Dict[str, str]] = dict(), metadata: Optional[MetadataTuple] = () ) -> DaprResponse: """Saves key-value pairs to a statestore This saves a value to the statestore with a given key and state store name. Options for request can be passed with the options field and custom metadata can be passed with metadata field. The example saves states to a statestore: from dapr import DaprClient with DaprClient() as d: resp = d.save_state( store_name='state_store', key='key1', value='value1', etag='etag', state_metadata={"metakey": "metavalue"}, ) Args: store_name (str): the state store name to save to key (str): the key to be saved value (bytes or str): the value to be saved etag (str, optional): the etag to save with options (StateOptions, optional): custom options for concurrency and consistency state_metadata (Dict[str, str], optional): Dapr metadata for state request metadata (tuple, optional, DEPRECATED): gRPC custom metadata Returns: :class:`DaprResponse` gRPC metadata returned from callee Raises: ValueError: value is not bytes or str ValueError: store_name is empty """ if metadata is not None: warn( 'metadata argument is deprecated. Dapr already intercepts API token headers ' 'and this is not needed.', DeprecationWarning, stacklevel=2) if not isinstance(value, (bytes, str)): raise ValueError(f'invalid type for data {type(value)}') req_value = value if not store_name or len(store_name) == 0 or len( store_name.strip()) == 0: raise ValueError("State store name cannot be empty") if options is None: state_options = None else: state_options = options.get_proto() state = common_v1.StateItem( key=key, value=to_bytes(req_value), etag=common_v1.Etag(value=etag) if etag is not None else None, options=state_options, metadata=state_metadata) req = api_v1.SaveStateRequest(store_name=store_name, states=[state]) _, call = self._stub.SaveState.with_call(req, metadata=metadata) return DaprResponse(headers=call.initial_metadata())
def data(self, val: Union[str, bytes]) -> None: """Sets str or bytes type data to request data.""" self._data = to_bytes(val)