Skip to content

Commit

Permalink
Merge branch 'dev' into feat/actor_revalidation
Browse files Browse the repository at this point in the history
  • Loading branch information
pseusys committed Mar 18, 2024
2 parents 913887e + cda7984 commit cdf5348
Show file tree
Hide file tree
Showing 97 changed files with 2,106 additions and 2,339 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,13 @@ import dff.script.conditions.std_conditions as cnd
script = {
GLOBAL: {
TRANSITIONS: {
("flow", "node_hi"): cnd.exact_match(Message(text="Hi")),
("flow", "node_hi"): cnd.exact_match(Message("Hi")),
("flow", "node_ok"): cnd.true()
}
},
"flow": {
"node_hi": {RESPONSE: Message(text="Hi!")},
"node_ok": {RESPONSE: Message(text="OK")},
"node_hi": {RESPONSE: Message("Hi!")},
"node_ok": {RESPONSE: Message("OK")},
},
}

Expand All @@ -112,7 +112,7 @@ def turn_handler(in_request: Message, pipeline: Pipeline) -> Message:

while True:
in_request = input("Your message: ")
out_response = turn_handler(Message(text=in_request), pipeline)
out_response = turn_handler(Message(in_request), pipeline)
print("Response: ", out_response.text)
```

Expand Down
1 change: 1 addition & 0 deletions dff/context_storages/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
that developers can inherit from in order to create their own context storage solutions.
This class implements the basic functionality and can be extended to add additional features as needed.
"""

import asyncio
import importlib
import threading
Expand Down
1 change: 1 addition & 0 deletions dff/context_storages/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
This class is used to store and retrieve context data in a JSON. It allows the DFF to easily
store and retrieve context data.
"""

import asyncio
from typing import Hashable

Expand Down
1 change: 1 addition & 0 deletions dff/context_storages/mongo.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
and environments. Additionally, MongoDB is highly scalable and can handle large amounts of data
and high levels of read and write traffic.
"""

from typing import Hashable, Dict, Any

try:
Expand Down
1 change: 1 addition & 0 deletions dff/context_storages/pickle.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
It is efficient and fast, but it is not recommended to use it to transfer data across
different languages or platforms because it's not cross-language compatible.
"""

import asyncio
import pickle
from typing import Hashable
Expand Down
1 change: 1 addition & 0 deletions dff/context_storages/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
The DFF supports a variety of communication protocols,
which allows it to communicate with different types of databases.
"""

import json
import pathlib

Expand Down
1 change: 1 addition & 0 deletions dff/context_storages/redis.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
Additionally, Redis can be used as a cache, message broker, and database, making it a versatile
and powerful choice for data storage and management.
"""

import json
from typing import Hashable

Expand Down
1 change: 1 addition & 0 deletions dff/context_storages/shelve.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
It stores data in a dbm-style format in the file system, which is not as fast as the other serialization
libraries like pickle or JSON.
"""

import pickle
from shelve import DbfilenameShelf
from typing import Hashable
Expand Down
1 change: 1 addition & 0 deletions dff/context_storages/sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
reliability and scalability. SQLite is a self-contained, high-reliability, embedded, full-featured,
public-domain, SQL database engine.
"""

import asyncio
import importlib
import json
Expand Down
1 change: 1 addition & 0 deletions dff/context_storages/ydb.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
with Yandex Cloud services using python. This allows the DFF to easily integrate with the Yandex DataBase and
take advantage of the scalability and high-availability features provided by the service.
"""

import asyncio
import os
from typing import Hashable
Expand Down
5 changes: 3 additions & 2 deletions dff/messengers/common/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
The Message Interfaces module contains several basic classes that define the message interfaces.
These classes provide a way to define the structure of the messengers that are used to communicate with the DFF.
"""

from __future__ import annotations
import abc
import asyncio
Expand Down Expand Up @@ -70,7 +71,7 @@ def _on_exception(self, e: BaseException):
:param e: The exception.
"""
if isinstance(e, Exception):
logger.error(f"Exception in {type(self).__name__} loop!\n{str(e)}")
logger.error(f"Exception in {type(self).__name__} loop!", exc_info=e)
else:
logger.info(f"{type(self).__name__} has stopped polling.")

Expand Down Expand Up @@ -164,7 +165,7 @@ def __init__(
self._descriptor: Optional[TextIO] = out_descriptor

def _request(self) -> List[Tuple[Message, Any]]:
return [(Message(text=input(self._prompt_request)), self._ctx_id)]
return [(Message(input(self._prompt_request)), self._ctx_id)]

def _respond(self, responses: List[Context]):
print(f"{self._prompt_response}{responses[0].last_response.text}", file=self._descriptor)
Expand Down
1 change: 1 addition & 0 deletions dff/messengers/common/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
-----
The Types module contains special types that are used throughout the `DFF Messengers`.
"""

from typing import Callable
from typing_extensions import TypeAlias

Expand Down
1 change: 1 addition & 0 deletions dff/messengers/telegram/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
This module implements various interfaces for :py:class:`~dff.messengers.telegram.messenger.TelegramMessenger`
that can be used to interact with the Telegram API.
"""

import asyncio
from typing import Any, Optional, List, Tuple, Callable

Expand Down
7 changes: 4 additions & 3 deletions dff/messengers/telegram/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
----------------
This module implements inherited classes :py:mod:`dff.script.core.message` modified for usage with Telegram.
"""

from typing import Optional, Union
from enum import Enum

Expand Down Expand Up @@ -67,9 +68,9 @@ class ParseMode(Enum):


class TelegramMessage(Message):
ui: Optional[
Union[TelegramUI, RemoveKeyboard, ReplyKeyboardRemove, ReplyKeyboardMarkup, InlineKeyboardMarkup]
] = None
ui: Optional[Union[TelegramUI, RemoveKeyboard, ReplyKeyboardRemove, ReplyKeyboardMarkup, InlineKeyboardMarkup]] = (
None
)
location: Optional[Location] = None
callback_query: Optional[Union[str, _ClickButton]] = None
update: Optional[
Expand Down
1 change: 1 addition & 0 deletions dff/messengers/telegram/messenger.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
Using it, you can put Telegram update handlers inside your script and condition your transitions accordingly.
"""

from pathlib import Path
from typing import Union, List, Optional, Callable
from enum import Enum
Expand Down
1 change: 1 addition & 0 deletions dff/messengers/telegram/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
------
This module contains utilities for connecting to Telegram.
"""

from typing import Union, Iterable
from contextlib import contextmanager
from pathlib import Path
Expand Down
1 change: 1 addition & 0 deletions dff/pipeline/conditions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
are attached should be executed or not.
The standard set of them allows user to setup dependencies between pipeline components.
"""

from __future__ import annotations
from typing import Optional, TYPE_CHECKING

Expand Down
1 change: 1 addition & 0 deletions dff/pipeline/pipeline/actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
.. figure:: /_static/drawio/dfe/user_actor.png
"""

from __future__ import annotations
import inspect
import logging
Expand Down
1 change: 1 addition & 0 deletions dff/pipeline/pipeline/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
The PipelineComponent class can be a group or a service. It is designed to be reusable and composable,
allowing developers to create complex processing pipelines by combining multiple components.
"""

from __future__ import annotations
import logging
import abc
Expand Down
1 change: 1 addition & 0 deletions dff/pipeline/pipeline/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
class, which is defined in the Component module. Together, these classes provide a powerful and flexible way
to structure and manage the messages processing flow.
"""

import asyncio
import logging
from typing import Union, List, Dict, Optional, Hashable, Callable
Expand Down
1 change: 1 addition & 0 deletions dff/pipeline/pipeline/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
The Utils module contains several service functions that are commonly used throughout the framework.
These functions provide a variety of utility functionality.
"""

import collections
from typing import Union, List
from inspect import isfunction
Expand Down
1 change: 1 addition & 0 deletions dff/pipeline/service/extra.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
beyond the core functionality. Extra handlers is an input converting addition to :py:class:`.PipelineComponent`.
For example, it is used to grep statistics from components, timing, logging, etc.
"""

from __future__ import annotations
import asyncio
import logging
Expand Down
5 changes: 3 additions & 2 deletions dff/pipeline/service/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
allowing for easier management and organization of the services within the pipeline.
The :py:class:`~.ServiceGroup` serves the important function of grouping services to work together in parallel.
"""

from __future__ import annotations
import asyncio
import logging
Expand Down Expand Up @@ -149,9 +150,9 @@ async def _run(
else:
self._set_state(ctx, ComponentExecutionState.NOT_RUN)

except Exception as e:
except Exception as exc:
self._set_state(ctx, ComponentExecutionState.FAILED)
logger.error(f"ServiceGroup '{self.name}' execution failed!\n{e}")
logger.error(f"ServiceGroup '{self.name}' execution failed!", exc_info=exc)

await self.run_extra_handler(ExtraHandlerType.AFTER, ctx, pipeline)

Expand Down
7 changes: 4 additions & 3 deletions dff/pipeline/service/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
Service can be asynchronous only if its handler is a coroutine.
Actor wrapping service is asynchronous.
"""

from __future__ import annotations
import logging
import inspect
Expand Down Expand Up @@ -134,7 +135,7 @@ async def _run_as_actor(self, ctx: Context, pipeline: Pipeline) -> None:
self._set_state(ctx, ComponentExecutionState.FINISHED)
except Exception as exc:
self._set_state(ctx, ComponentExecutionState.FAILED)
logger.error(f"Actor '{self.name}' execution failed!\n{exc}")
logger.error(f"Actor '{self.name}' execution failed!", exc_info=exc)

async def _run_as_service(self, ctx: Context, pipeline: Pipeline) -> None:
"""
Expand All @@ -151,9 +152,9 @@ async def _run_as_service(self, ctx: Context, pipeline: Pipeline) -> None:
self._set_state(ctx, ComponentExecutionState.FINISHED)
else:
self._set_state(ctx, ComponentExecutionState.NOT_RUN)
except Exception as e:
except Exception as exc:
self._set_state(ctx, ComponentExecutionState.FAILED)
logger.error(f"Service '{self.name}' execution failed!\n{e}")
logger.error(f"Service '{self.name}' execution failed!", exc_info=exc)

async def _run(self, ctx: Context, pipeline: Pipeline) -> None:
"""
Expand Down
1 change: 1 addition & 0 deletions dff/pipeline/service/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
The Utility Functions module contains several utility functions that are commonly used throughout the DFF.
These functions provide a variety of utility functionality.
"""

import asyncio
from typing import Callable, Any, Optional, Tuple, Mapping

Expand Down
1 change: 1 addition & 0 deletions dff/pipeline/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
The classes and special types in this module can include data models,
data structures, and other types that are defined for type hinting.
"""

from __future__ import annotations
from enum import unique, Enum
from typing import Callable, Union, Awaitable, Dict, List, Optional, Iterable, Any, Protocol, Hashable, TYPE_CHECKING
Expand Down
2 changes: 1 addition & 1 deletion dff/script/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@
ModuleName,
ActorStage,
)
from .core.message import Message, MultiMessage
from .core.message import Message
1 change: 1 addition & 0 deletions dff/script/conditions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from .std_conditions import (
exact_match,
has_text,
regexp,
check_cond_seq,
aggregate,
Expand Down
29 changes: 23 additions & 6 deletions dff/script/conditions/std_conditions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
These conditions can be used to check the current context, the user's input,
or other factors that may affect the conversation flow.
"""

from typing import Callable, Pattern, Union, List, Optional
import logging
import re
Expand All @@ -24,8 +25,8 @@
def exact_match(match: Message, skip_none: bool = True) -> Callable[[Context, Pipeline], bool]:
"""
Return function handler. This handler returns `True` only if the last user phrase
is the same Message as the :py:const:`match`.
If :py:const:`skip_none` the handler will not compare `None` fields of :py:const:`match`.
is the same Message as the `match`.
If `skip_none` the handler will not compare `None` fields of `match`.
:param match: A Message variable to compare user request with.
:param skip_none: Whether fields should be compared if they are `None` in :py:const:`match`.
Expand All @@ -49,11 +50,27 @@ def exact_match_condition_handler(ctx: Context, pipeline: Pipeline) -> bool:
return exact_match_condition_handler


@validate_call
def has_text(text: str) -> Callable[[Context, Pipeline], bool]:
"""
Return function handler. This handler returns `True` only if the last user phrase
contains the phrase specified in `text`.
:param text: A `str` variable to look for within the user request.
"""

def has_text_condition_handler(ctx: Context, pipeline: Pipeline) -> bool:
request = ctx.last_request
return text in request.text

return has_text_condition_handler


@validate_call
def regexp(pattern: Union[str, Pattern], flags: Union[int, re.RegexFlag] = 0) -> Callable[[Context, Pipeline], bool]:
"""
Return function handler. This handler returns `True` only if the last user phrase contains
:py:const:`pattern <Union[str, Pattern]>` with :py:const:`flags <Union[int, re.RegexFlag]>`.
`pattern` with `flags`.
:param pattern: The `RegExp` pattern.
:param flags: Flags for this pattern. Defaults to 0.
Expand Down Expand Up @@ -170,9 +187,9 @@ def has_last_labels(
) -> Callable[[Context, Pipeline], bool]:
"""
Return condition handler. This handler returns `True` if any label from
last :py:const:`last_n_indices` context labels is in
the :py:const:`flow_labels` list or in
the :py:const:`~dff.script.NodeLabel2Type` list.
last `last_n_indices` context labels is in
the `flow_labels` list or in
the `~dff.script.NodeLabel2Type` list.
:param flow_labels: List of labels to check. Every label has type `str`. Empty if not set.
:param labels: List of labels corresponding to the nodes. Empty if not set.
Expand Down
1 change: 1 addition & 0 deletions dff/script/core/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
The context can be easily serialized to a format that can be stored or transmitted, such as JSON.
This allows developers to save the context data and resume the conversation later.
"""

from __future__ import annotations
import logging
from uuid import UUID, uuid4
Expand Down
1 change: 1 addition & 0 deletions dff/script/core/keywords.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
They are used to determine all nodes in the script and to assign python objects and python functions for nodes.
"""

from enum import Enum


Expand Down
Loading

0 comments on commit cdf5348

Please sign in to comment.