Skip to content

Commit

Permalink
Тутор по флагам и возможность авторизации в навыках (#15)
Browse files Browse the repository at this point in the history
* Актуализация документации и обновление версий линтеров

* Убрал лишний __init__ в тайп-чекинг блоке

* Туториал на флаги

* Заготовка под авторизацию в навыках

* Работоспособная авторизация через навык

* Пример работы с встроенными интентами и обновлённые ссылки на официальную документацию

* Проверка полей в TYPE_CHECKING'ах(ВСЁ ХОРОШО), поправка полей "session: Session..." для красоты

* Pydantic v2.8

---------

Co-authored-by: Erkut <[email protected]>
  • Loading branch information
K1rL3s and ZloyKobra committed Jul 21, 2024
1 parent ab3d313 commit b6e7dfd
Show file tree
Hide file tree
Showing 90 changed files with 471 additions and 145 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ jobs:
- name: Lint code
run: |
ruff --output-format=github aliceio examples
ruff check --output-format=github aliceio examples
mypy aliceio
black --check --diff aliceio tests
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
rev: v4.6.0
hooks:
- id: trailing-whitespace
- id: check-case-conflict
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
</div>
<p align="center">
<b>
Асинхронный фреймворк, упрощающий разработку
Асинхронный фреймворк для разработки
<a target="_blank" href="https://dialogs.yandex.ru/store">навыков Алисы</a>
из
<a target="_blank" href="https://dialogs.yandex.ru/development">Яндекс.Диалогов</a>
Expand Down
13 changes: 0 additions & 13 deletions aliceio/client/context_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,6 @@
class SkillContextController(BaseModel):
_skill: Optional["Skill"] = PrivateAttr()

if TYPE_CHECKING:

def __init__(
__pydantic_self__,
*,
_skill: Optional["Skill"],
**__pydantic_kwargs: Any,
) -> None:
super().__init__(
_skill=_skill,
**__pydantic_kwargs,
)

def model_post_init(self, __context: Any) -> None:
self._skill = __context.get("skill") if __context else None

Expand Down
2 changes: 0 additions & 2 deletions aliceio/client/session/middlewares/manager.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from __future__ import annotations

from functools import partial
from typing import Any, Callable, List, Optional, Sequence, Union, cast, overload

Expand Down
4 changes: 1 addition & 3 deletions aliceio/dispatcher/event/alice.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from __future__ import annotations

from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional

from aliceio.dispatcher.event.bases import UNHANDLED, MiddlewareType, SkipHandler
Expand All @@ -20,7 +18,7 @@ class AliceEventObserver:
Он остановит распространение события, когда пройдут фильтры любого обработчика.
"""

def __init__(self, router: Router, event_name: str) -> None:
def __init__(self, router: "Router", event_name: str) -> None:
self.router = router
self.event_name = event_name

Expand Down
2 changes: 0 additions & 2 deletions aliceio/dispatcher/event/bases.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from __future__ import annotations

from typing import Any, Awaitable, Callable, Dict, NoReturn, Optional, TypeVar, Union
from unittest.mock import sentinel

Expand Down
2 changes: 0 additions & 2 deletions aliceio/dispatcher/event/event.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from __future__ import annotations

from typing import Any, Callable, List

from .handler import CallbackType, HandlerObject
Expand Down
4 changes: 1 addition & 3 deletions aliceio/dispatcher/middlewares/error.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from __future__ import annotations

from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict

from aliceio.dispatcher.event.bases import UNHANDLED, CancelHandler, SkipHandler
Expand All @@ -12,7 +10,7 @@


class ErrorsMiddleware(BaseMiddleware[Update]):
def __init__(self, router: Router) -> None:
def __init__(self, router: "Router") -> None:
self.router = router

async def __call__(
Expand Down
9 changes: 7 additions & 2 deletions aliceio/dispatcher/router.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from __future__ import annotations

from typing import Any, Dict, Final, Generator, List, Optional
from typing import Any, Dict, Final, FrozenSet, Generator, List, Optional

from ..enums import EventType
from ..types.base import AliceObject
from .event.alice import AliceEventObserver
from .event.bases import REJECTED, UNHANDLED
from .event.event import EventObserver

INTERNAL_UPDATE_TYPES: Final[frozenset[str]] = frozenset({"update", "error", "timeout"})
INTERNAL_UPDATE_TYPES: Final[FrozenSet[str]] = frozenset({"update", "error", "timeout"})


class Router:
Expand Down Expand Up @@ -43,6 +43,10 @@ def __init__(self, *, name: Optional[str] = None) -> None:
router=self,
event_name=EventType.AUDIO_PLAYER,
)
self.account_linking_complete = AliceEventObserver(
router=self,
event_name=EventType.ACCOUNT_LINKING_COMPLETE,
)
self.errors = self.error = AliceEventObserver(
router=self,
event_name=EventType.ERROR,
Expand All @@ -58,6 +62,7 @@ def __init__(self, *, name: Optional[str] = None) -> None:
EventType.PURCHASE: self.purchase,
EventType.SHOW_PULL: self.show_pull,
EventType.AUDIO_PLAYER: self.audio_player,
EventType.ACCOUNT_LINKING_COMPLETE: self.account_linking_complete,
EventType.ERROR: self.errors,
EventType.TIMEOUT: self.timeout,
}
Expand Down
2 changes: 2 additions & 0 deletions aliceio/enums/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class EventType(StrEnum, ValuesEnum):
MESSAGE = "message"
SHOW_PULL = "show_pull"
PURCHASE = "purchase"
ACCOUNT_LINKING_COMPLETE = "account_linking_complete_event"
UPDATE = "update"
TIMEOUT = "timeout"

Expand All @@ -22,6 +23,7 @@ class RequestType(StrEnum, ValuesEnum):
PURCHASE_CONFIRMATION = "Purchase.Confirmation"
SHOW_PULL = "Show.Pull"
SIMPLE_UTTERANCE = "SimpleUtterance"
ACCOUNT_LINKING_COMPLETE = "AccountLinkigCompleteEvent" # Нужен ли?


class ShowType(StrEnum, ValuesEnum):
Expand Down
2 changes: 1 addition & 1 deletion aliceio/fsm/middlewares/api_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class FSMApiStorageMiddleware(BaseMiddleware[Update]):
Регистрируется только тогда, когда установлен флаг при создании диспетчера.
https://yandex.ru/dev/dialogs/alice/doc/session-persistence.html
https://yandex.ru/dev/dialogs/alice/doc/ru/session-persistence
"""

def __init__(self, strategy: FSMStrategy = FSMStrategy.USER) -> None:
Expand Down
2 changes: 2 additions & 0 deletions aliceio/handlers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .account_linking_complete import AccountLinkingCompleteHandler
from .audio_player import AudioPlayerHandler
from .base import BaseHandler, BaseHandlerMixin
from .button_pressed import ButtonPressedHandler
Expand All @@ -8,6 +9,7 @@
from .timeout import TimeoutHandler

__all__ = (
"AccountLinkingCompleteHandler",
"AudioPlayerHandler",
"BaseHandler",
"BaseHandlerMixin",
Expand Down
9 changes: 9 additions & 0 deletions aliceio/handlers/account_linking_complete.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from abc import ABC

from aliceio.handlers.base import BaseHandler
from aliceio.types import AccountLinkingComplete


# TODO: узнать, передаётся ли поле request (и с чем) при подтверждении авторизации
class AccountLinkingCompleteHandler(BaseHandler[AccountLinkingComplete], ABC):
"""Базовый класс для обработчиков успешной авторизации пользоватя."""
6 changes: 2 additions & 4 deletions aliceio/handlers/base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from __future__ import annotations

from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any, Dict, Generic, TypeVar, cast

Expand All @@ -21,11 +19,11 @@ class BaseHandler(BaseHandlerMixin[T], ABC):
"""Базовый класс для всех class-based обработчиков."""

def __init__(self, event: T, **kwargs: Any) -> None:
self.event: T = event
self.event = event
self.data: Dict[str, Any] = kwargs

@property
def skill(self) -> Skill:
def skill(self) -> "Skill":
from aliceio import Skill

if "skill" in self.data:
Expand Down
4 changes: 1 addition & 3 deletions aliceio/methods/base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from __future__ import annotations

from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any, ClassVar, Generator, Generic, Optional, TypeVar

Expand Down Expand Up @@ -48,7 +46,7 @@ def __http_method__(self) -> str:
def api_url(self, api_server: AliceAPIServer) -> str:
pass

async def emit(self, skill: Skill) -> AliceType:
async def emit(self, skill: "Skill") -> AliceType:
if not self._skill:
self._skill = self.skill
return await skill(self)
Expand Down
2 changes: 1 addition & 1 deletion aliceio/methods/images/delete_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def __init__(
)

def api_url(self, api_server: AliceAPIServer) -> str:
skill: "Skill" = cast("Skill", self.skill)
skill: Skill = cast("Skill", self.skill)
return api_server.delete_file_url(
skill_id=skill.id,
file_type=FileType.IMAGES,
Expand Down
2 changes: 1 addition & 1 deletion aliceio/methods/images/get_images.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class GetImages(AliceMethod[UploadedImagesList]):
__http_method__ = HttpMethod.GET

def api_url(self, api_server: AliceAPIServer) -> str:
skill: "Skill" = cast("Skill", self.skill)
skill: Skill = cast("Skill", self.skill)
return api_server.get_all_files_url(
skill_id=skill.id,
file_type=FileType.IMAGES,
Expand Down
2 changes: 1 addition & 1 deletion aliceio/methods/images/upload_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def model_post_init(self, __context: Any) -> None:
raise AliceWrongFieldError('"file" and "url" cannot be specified together')

def api_url(self, api_server: AliceAPIServer) -> str:
skill: "Skill" = cast("Skill", self.skill)
skill: Skill = cast("Skill", self.skill)
return api_server.upload_file_url(
skill_id=skill.id,
file_type=FileType.IMAGES,
Expand Down
2 changes: 1 addition & 1 deletion aliceio/methods/sounds/delete_sound.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def __init__(
)

def api_url(self, api_server: AliceAPIServer) -> str:
skill: "Skill" = cast("Skill", self.skill)
skill: Skill = cast("Skill", self.skill)
return api_server.delete_file_url(
skill_id=skill.id,
file_type=FileType.SOUNDS,
Expand Down
2 changes: 1 addition & 1 deletion aliceio/methods/sounds/get_sounds.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class GetSounds(AliceMethod[UploadedSoundsList]):
__http_method__ = HttpMethod.GET

def api_url(self, api_server: AliceAPIServer) -> str:
skill: "Skill" = cast("Skill", self.skill)
skill: Skill = cast("Skill", self.skill)
return api_server.get_all_files_url(
skill_id=skill.id,
file_type=FileType.SOUNDS,
Expand Down
2 changes: 1 addition & 1 deletion aliceio/methods/sounds/upload_sound.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def __init__(
)

def api_url(self, api_server: AliceAPIServer) -> str:
skill: "Skill" = cast("Skill", self.skill)
skill: Skill = cast("Skill", self.skill)
return api_server.upload_file_url(
skill_id=skill.id,
file_type=FileType.SOUNDS,
Expand Down
2 changes: 2 additions & 0 deletions aliceio/types/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .account_linking_complete import AccountLinkingComplete
from .alice_request import AliceRequest
from .alice_response import AliceResponse
from .analytic_event import AnalyticEvent
Expand Down Expand Up @@ -54,6 +55,7 @@
from .user import User

__all__ = (
"AccountLinkingComplete",
"AliceRequest",
"AliceResponse",
"AnalyticEvent",
Expand Down
21 changes: 21 additions & 0 deletions aliceio/types/account_linking_complete.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from typing import TYPE_CHECKING, Any

from .base import MutableAliceObject


class AccountLinkingComplete(MutableAliceObject):
"""
Успешная авторизация пользователя в навыке.
[Source](https://yandex.ru/dev/dialogs/alice/doc/ru/auth/make-skill#authorization-complete)
"""

if TYPE_CHECKING:

def __init__(
__pydantic_self__,
**__pydantic_kwargs: Any,
) -> None:
super().__init__(
**__pydantic_kwargs,
)
8 changes: 4 additions & 4 deletions aliceio/types/alice_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class AliceRequest(AliceObject):
"""
Запрос с информацией от пользователя от API Алисы.
[Source](https://yandex.ru/dev/dialogs/alice/doc/request.html#request__request-desc)
[Source](https://yandex.ru/dev/dialogs/alice/doc/ru/request#request-desc)
"""

type: str
Expand All @@ -22,11 +22,11 @@ class AliceRequest(AliceObject):
nlu: Optional[NLU] = None

# Ошибка в аудиоплеере
# https://yandex.ru/dev/dialogs/alice/doc/request-audioplayer.html
# https://yandex.ru/dev/dialogs/alice/doc/ru/request-audioplayer
error: Optional[AudioPlayerError] = None

# not null при type == RequestType.PURCHASE_CONFIRMATION
# https://yandex.ru/dev/dialogs/alice/doc/request-purchase-confirmation.html
# https://yandex.ru/dev/dialogs/alice/doc/ru/request-purchase-confirmation
purchase_request_id: Optional[str] = None
purchase_token: Optional[str] = None
order_id: Optional[str] = None
Expand All @@ -36,7 +36,7 @@ class AliceRequest(AliceObject):
signature: Optional[str] = None

# not null при запуске утреннего шоу Алисы
# https://yandex.ru/dev/dialogs/alice/doc/request-show-pull.html
# https://yandex.ru/dev/dialogs/alice/doc/ru/request-show-pull
show_type: Optional[str] = None

if TYPE_CHECKING:
Expand Down
2 changes: 1 addition & 1 deletion aliceio/types/alice_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class AliceResponse(MutableAliceObject):
"""
Ответ на запрос API Алисы.
[Source](https://yandex.ru/dev/dialogs/alice/doc/response.html)
[Source](https://yandex.ru/dev/dialogs/alice/doc/ru/response)
"""

response: Response
Expand Down
2 changes: 1 addition & 1 deletion aliceio/types/analytic_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class AnalyticEvent(MutableAliceObject):
"""
Событие для аналитики.
[Source](https://yandex.ru/dev/dialogs/alice/doc/response.html#response__events-desc)
[Source](https://yandex.ru/dev/dialogs/alice/doc/ru/response#events-desc)
"""

name: str
Expand Down
2 changes: 1 addition & 1 deletion aliceio/types/analytics.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class Analytics(MutableAliceObject):
"""
Данные для аналитики AppMetrica.
[Source](https://yandex.ru/dev/dialogs/alice/doc/response.html#response__analytics-desc)
[Source](https://yandex.ru/dev/dialogs/alice/doc/ru/response#analytics-desc)
"""

events: List[AnalyticEvent]
Expand Down
4 changes: 2 additions & 2 deletions aliceio/types/api_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
SessionState = StateDict
UserState = StateDict
ApplicationState = StateDict
# https://yandex.ru/dev/dialogs/alice/doc/session-persistence.html
# https://yandex.ru/dev/dialogs/alice/doc/ru/session-persistence


class ApiState(AliceObject):
"""
Данные о сохранённом состоянии на стороне API Алисы.
[Source](https://yandex.ru/dev/dialogs/alice/doc/request.html#request__state-desc)
[Source](https://yandex.ru/dev/dialogs/alice/doc/ru/request#state-desc)
"""

user: Optional[UserState] = None
Expand Down
2 changes: 1 addition & 1 deletion aliceio/types/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class Application(MutableAliceObject):
"""
Приложение из :class:`Session`.
[Source](https://yandex.ru/dev/dialogs/alice/doc/request.html#request__application-desc)
[Source](https://yandex.ru/dev/dialogs/alice/doc/ru/request#application-desc)
"""

application_id: str
Expand Down
Loading

0 comments on commit b6e7dfd

Please sign in to comment.