Skip to content

Commit

Permalink
Merge branch 'develop': v 1.2.0. Support NLU, safe_kwargs for meta an…
Browse files Browse the repository at this point in the history
…d request (for future API updates compatability)
  • Loading branch information
mahenzon committed Oct 15, 2018
2 parents 028eae4 + 91e7425 commit 97eca68
Show file tree
Hide file tree
Showing 20 changed files with 283 additions and 13 deletions.
2 changes: 1 addition & 1 deletion aioalice/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())


__version__ = '1.1.7'
__version__ = '1.2.0'
4 changes: 4 additions & 0 deletions aioalice/types/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
from .base import AliceObject
from .meta import Meta
from .markup import Markup
from .entity_tokens import EntityTokens
from .entity_value import EntityValue
from .entity import Entity, EntityType
from .natural_language_understanding import NaturalLanguageUnderstanding
from .request import Request, RequestType
from .session import BaseSession, Session

Expand Down
2 changes: 1 addition & 1 deletion aioalice/types/alice_request.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from attr import attrs, attrib
from aioalice.utils import ensure_cls
from . import AliceObject, Meta, Session, \
Card, Request, Response, AliceResponse
from aioalice.utils import ensure_cls


@attrs
Expand Down
2 changes: 1 addition & 1 deletion aioalice/types/alice_response.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from attr import attrs, attrib
from . import AliceObject, BaseSession, Response
from aioalice.utils import ensure_cls
from . import AliceObject, BaseSession, Response


@attrs
Expand Down
2 changes: 1 addition & 1 deletion aioalice/types/card.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from attr import attrs, attrib

from . import AliceObject, MediaButton, Image, CardHeader, CardFooter
from aioalice.utils import ensure_cls
from aioalice.utils.helper import Helper, HelperMode, Item
from . import AliceObject, MediaButton, Image, CardHeader, CardFooter


@attrs
Expand Down
2 changes: 1 addition & 1 deletion aioalice/types/card_footer.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from attr import attrs, attrib

from . import AliceObject, MediaButton
from aioalice.utils import ensure_cls
from . import AliceObject, MediaButton


@attrs
Expand Down
36 changes: 36 additions & 0 deletions aioalice/types/entity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import logging
from attr import attrs, attrib

from aioalice.utils import ensure_cls
from aioalice.utils.helper import Helper, HelperMode, Item
from . import AliceObject, EntityTokens, EntityValue

log = logging.getLogger(__name__)


@attrs
class Entity(AliceObject):
"""Entity object"""
type = attrib(type=str)
tokens = attrib(convert=ensure_cls(EntityTokens))
value = attrib(factory=dict)

@type.validator
def check(self, attribute, value):
"""Report unknown type"""
if value not in EntityType.all():
log.error('Unknown Entity type! `%r`', value)

def __attrs_post_init__(self):
"""If entity type not number, convert to EntityValue"""
if self.value and self.type != EntityType.YANDEX_NUMBER:
self.value = EntityValue(**self.value)


class EntityType(Helper):
mode = HelperMode.UPPER_DOT_SEPARATED

YANDEX_GEO = Item()
YANDEX_FIO = Item()
YANDEX_NUMBER = Item()
YANDEX_DATETIME = Item()
9 changes: 9 additions & 0 deletions aioalice/types/entity_tokens.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from attr import attrs, attrib
from . import AliceObject


@attrs
class EntityTokens(AliceObject):
"""EntityTokens object"""
start = attrib(type=int)
end = attrib(type=int)
31 changes: 31 additions & 0 deletions aioalice/types/entity_value.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from attr import attrs, attrib
from . import AliceObject


@attrs
class EntityValue(AliceObject):
"""EntityValue object"""

# YANDEX.FIO
first_name = attrib(default=None, type=str)
patronymic_name = attrib(default=None, type=str)
last_name = attrib(default=None, type=str)

# YANDEX.GEO
country = attrib(default=None, type=str)
city = attrib(default=None, type=str)
street = attrib(default=None, type=str)
house_number = attrib(default=None, type=str)
airport = attrib(default=None, type=str)

# YANDEX.DATETIME
year = attrib(default=None, type=str)
year_is_relative = attrib(default=False, type=bool)
month = attrib(default=None, type=str)
month_is_relative = attrib(default=False, type=bool)
day = attrib(default=None, type=str)
day_is_relative = attrib(default=False, type=bool)
hour = attrib(default=None, type=str)
hour_is_relative = attrib(default=False, type=bool)
minute = attrib(default=None, type=str)
minute_is_relative = attrib(default=False, type=bool)
2 changes: 1 addition & 1 deletion aioalice/types/image.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from attr import attrs, attrib

from . import AliceObject, MediaButton
from aioalice.utils import ensure_cls
from . import AliceObject, MediaButton


@attrs
Expand Down
2 changes: 2 additions & 0 deletions aioalice/types/meta.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from attr import attrs, attrib
from aioalice.utils import safe_kwargs
from . import AliceObject


@safe_kwargs
@attrs
class Meta(AliceObject):
"""Meta object"""
Expand Down
11 changes: 11 additions & 0 deletions aioalice/types/natural_language_understanding.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Natural Language Understanding: https://medium.com/@lola.com/nlp-vs-nlu-whats-the-difference-d91c06780992
from attr import attrs, attrib
from aioalice.utils import ensure_cls
from . import AliceObject, Entity


@attrs
class NaturalLanguageUnderstanding(AliceObject):
"""Natural Language Understanding object"""
tokens = attrib(factory=list)
entities = attrib(factory=list, convert=ensure_cls(Entity))
5 changes: 4 additions & 1 deletion aioalice/types/request.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from attr import attrs, attrib

from aioalice.utils import safe_kwargs, ensure_cls
from aioalice.utils.helper import Helper, HelperMode, Item
from . import AliceObject, Markup
from . import AliceObject, Markup, NaturalLanguageUnderstanding


@safe_kwargs
@attrs
class Request(AliceObject):
"""Request object"""
Expand All @@ -12,6 +14,7 @@ class Request(AliceObject):
original_utterance = attrib(default='', type=str) # Can be none if payload passed
markup = attrib(default=None)
payload = attrib(default=None)
nlu = attrib(default=None, convert=ensure_cls(NaturalLanguageUnderstanding))

@type.validator
def check(self, attribute, value):
Expand Down
2 changes: 1 addition & 1 deletion aioalice/types/response.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from attr import attrs, attrib
from . import AliceObject, Card, Button
from aioalice.utils import ensure_cls
from . import AliceObject, Card, Button


@attrs
Expand Down
1 change: 1 addition & 0 deletions aioalice/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from . import exceptions
from .json import json
from .payload import generate_json_payload
from .safe_kwargs import safe_kwargs


def ensure_cls(klass):
Expand Down
9 changes: 6 additions & 3 deletions aioalice/utils/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class HelperMode(Helper):
CamelCase = 'CamelCase'
snake_case = 'snake_case'
lowercase = 'lowercase'
UPPER_DOT_SEPARATED = 'UPPER.DOT.SEPARATED'

@classmethod
def all(cls):
Expand Down Expand Up @@ -120,16 +121,18 @@ def apply(cls, text, mode):
:param mode:
:return:
"""
if mode == cls.SCREAMING_SNAKE_CASE:
if mode == cls.UPPER_DOT_SEPARATED:
return cls._screaming_snake_case(text).replace('_', '.')
elif mode == cls.SCREAMING_SNAKE_CASE:
return cls._screaming_snake_case(text)
elif mode == cls.snake_case:
return cls._snake_case(text)
elif mode == cls.lowercase:
return cls._snake_case(text).replace('_', '')
elif mode == cls.lowerCamelCase:
return cls._camel_case(text)
elif mode == cls.CamelCase:
return cls._camel_case(text, True)
elif mode == cls.lowercase:
return cls._snake_case(text).replace('_', '')
elif callable(mode):
return mode(text)
return text
Expand Down
16 changes: 16 additions & 0 deletions aioalice/utils/safe_kwargs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# https://gist.github.com/surik00/a6c2804a2d18a2ab75630bb5d93693c8

import inspect
import functools


def safe_kwargs(func_or_class):
spec = inspect.getfullargspec(func_or_class)
all_args = spec.args

@functools.wraps(func_or_class)
def wrap(*args, **kwargs):
accepted_kwargs = {k: v for k, v in kwargs.items() if k in all_args}
return func_or_class(*args, **accepted_kwargs)

return wrap
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
if sys.version_info < MINIMAL_PY_VERSION:
raise RuntimeError('aioAlice works only with Python {}+'.format('.'.join(map(str, MINIMAL_PY_VERSION))))

__version__ = '1.1.7'
__version__ = '1.2.0'


def get_description():
Expand Down
90 changes: 90 additions & 0 deletions tests/_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,93 @@
},
'version': '1.0'
}

ENTITY_TOKEN = {
"start": 2,
"end": 6
}

ENTITY_VALUE = {
"house_number": "16",
"street": "льва толстого"
}

ENTITY = {
"tokens": ENTITY_TOKEN,
"type": "YANDEX.GEO",
"value": ENTITY_VALUE
}

ENTITY_INTEGER = {
"tokens": {
"start": 5,
"end": 6
},
"type": "YANDEX.NUMBER",
"value": 16
}

NLU = {
"tokens": [
"закажи",
"пиццу",
"на",
"льва",
"толстого",
"16",
"на",
"завтра"
],
"entities": [
ENTITY,
{
"tokens": {
"start": 3,
"end": 5
},
"type": "YANDEX.FIO",
"value": {
"first_name": "лев",
"last_name": "толстой"
}
},
ENTITY_INTEGER,
{
"tokens": {
"start": 6,
"end": 8
},
"type": "YANDEX.DATETIME",
"value": {
"day": 1,
"day_is_relative": True
}
}
]
}

REQUEST_WITH_NLU = {
"meta": {
"locale": "ru-RU",
"timezone": "Europe/Moscow",
"client_id": "ru.yandex.searchplugin/5.80 (Samsung Galaxy; Android 4.4)"
},
"request": {
"command": "закажи пиццу на улицу льва толстого, 16 на завтра",
"original_utterance": "закажи пиццу на улицу льва толстого, 16 на завтра",
"type": "SimpleUtterance",
"markup": {
"dangerous_context": True
},
"payload": {},
"nlu": NLU,
},
"session": {
"new": True,
"message_id": 4,
"session_id": "2eac4854-fce721f3-b845abba-20d60",
"skill_id": "3ad36498-f5rd-4079-a14b-788652932056",
"user_id": "AC9WC3DF6FCE052E45A4566A48E6B7193774B84814CE49A922E163B8B29881DC"
},
"version": "1.0"
}
Loading

0 comments on commit 97eca68

Please sign in to comment.