Fixed some pylint warnings

This commit is contained in:
Fabio Manganiello 2018-07-30 22:08:06 +02:00
parent a0ac30e9b6
commit 81803a364d
6 changed files with 113 additions and 70 deletions

View file

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2017, Fabio Manganiello Copyright (c) 2017, 2018 Fabio Manganiello
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View file

@ -1,3 +1,10 @@
"""
Platypush
.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
.. license:: MIT
"""
import argparse import argparse
import logging import logging
import sys import sys
@ -18,30 +25,29 @@ from .message.response import Response
__author__ = 'Fabio Manganiello <blacklight86@gmail.com>' __author__ = 'Fabio Manganiello <blacklight86@gmail.com>'
__version__ = '0.9' __version__ = '0.9'
#-----------# LOGGER = logging.getLogger(__name__)
logger = logging.getLogger(__name__) class Daemon:
class Daemon(object):
""" Main class for the Platypush daemon """ """ Main class for the Platypush daemon """
""" Configuration file (default: either ~/.config/platypush/config.yaml or # Configuration file (default: either ~/.config/platypush/config.yaml or
/etc/platypush/config.yaml) """ # /etc/platypush/config.yaml
config_file = None config_file = None
""" Application bus. It's an internal queue where: # Application bus. It's an internal queue where:
- backends will post the messages they receive # - backends will post the messages they receive
- plugins will post the responses they process """ # - plugins will post the responses they process
bus = None bus = None
""" backend_name => backend_obj map """ # backend_name => backend_obj map
backends = None backends = None
""" number of executions retries before a request fails """ # number of executions retries before a request fails
n_tries = 2 n_tries = 2
def __init__(self, config_file=None, requests_to_process=None): def __init__(self, config_file=None, requests_to_process=None):
""" Constructor """
Constructor
Params: Params:
config_file -- Configuration file override (default: None) config_file -- Configuration file override (default: None)
requests_to_process -- Exit after processing the specified number requests_to_process -- Exit after processing the specified number
@ -58,7 +64,8 @@ class Daemon(object):
@classmethod @classmethod
def build_from_cmdline(cls, args): def build_from_cmdline(cls, args):
""" Build the app from command line arguments. """
Build the app from command line arguments.
Params: Params:
args -- Your sys.argv[1:] [List of strings] args -- Your sys.argv[1:] [List of strings]
""" """
@ -70,30 +77,34 @@ class Daemon(object):
return cls(config_file=opts.config) return cls(config_file=opts.config)
def on_message(self): def on_message(self):
""" Default message handler """ """
Default message handler
"""
def _f(msg): def _f(msg):
""" on_message closure """
on_message closure
Params: Params:
msg -- platypush.message.Message instance """ msg -- platypush.message.Message instance
"""
if isinstance(msg, Request): if isinstance(msg, Request):
try: try:
msg.execute(n_tries=self.n_tries) msg.execute(n_tries=self.n_tries)
except PermissionError: except PermissionError:
logger.info('Dropped unauthorized request: {}'.format(msg)) LOGGER.info('Dropped unauthorized request: {}'.format(msg))
self.processed_requests += 1 self.processed_requests += 1
if self.requests_to_process \ if self.requests_to_process \
and self.processed_requests >= self.requests_to_process: and self.processed_requests >= self.requests_to_process:
self.stop_app() self.stop_app()
elif isinstance(msg, Response): elif isinstance(msg, Response):
logger.info('Received response: {}'.format(msg)) LOGGER.info('Received response: {}'.format(msg))
elif isinstance(msg, StopEvent) and msg.targets_me(): elif isinstance(msg, StopEvent) and msg.targets_me():
logger.info('Received STOP event: {}'.format(msg)) LOGGER.info('Received STOP event: {}'.format(msg))
self.stop_app() self.stop_app()
elif isinstance(msg, Event): elif isinstance(msg, Event):
logger.info('Received event: {}'.format(msg)) LOGGER.info('Received event: {}'.format(msg))
self.event_processor.process_event(msg) self.event_processor.process_event(msg)
return _f return _f
@ -124,17 +135,20 @@ class Daemon(object):
# Poll for messages on the bus # Poll for messages on the bus
try: try:
self.bus.poll() self.bus.poll()
except KeyboardInterrupt as e: except KeyboardInterrupt:
logger.info('SIGINT received, terminating application') LOGGER.info('SIGINT received, terminating application')
finally: finally:
self.stop_app() self.stop_app()
def main(): def main():
"""
Platypush daemon main
"""
print('Starting platypush v.{}'.format(__version__)) print('Starting platypush v.{}'.format(__version__))
app = Daemon.build_from_cmdline(sys.argv[1:]) app = Daemon.build_from_cmdline(sys.argv[1:])
app.start() app.start()
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et:

View file

@ -1,3 +1,8 @@
"""
.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
.. license:: MIT
"""
import importlib import importlib
import logging import logging
import sys import sys

View file

@ -1,3 +1,8 @@
"""
.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
.. license:: MIT
"""
import json import json
import os import os
import subprocess import subprocess
@ -36,10 +41,11 @@ class AssistantGoogleBackend(Backend):
* **google-assistant-sdk[samples]** (``pip install google-assistant-sdk[samples]``) * **google-assistant-sdk[samples]** (``pip install google-assistant-sdk[samples]``)
""" """
def __init__(self, credentials_file=os.path.join( def __init__(self,
os.path.expanduser('~/.config'), credentials_file=os.path.join(
'google-oauthlib-tool', 'credentials.json'), os.path.expanduser('~/.config'),
device_model_id='Platypush', **kwargs): 'google-oauthlib-tool', 'credentials.json'),
device_model_id='Platypush', **kwargs):
""" """
:param credentials_file: Path to the Google OAuth credentials file (default: ~/.config/google-oauthlib-tool/credentials.json). See https://developers.google.com/assistant/sdk/guides/library/python/embed/install-sample#generate_credentials for how to get your own credentials file. :param credentials_file: Path to the Google OAuth credentials file (default: ~/.config/google-oauthlib-tool/credentials.json). See https://developers.google.com/assistant/sdk/guides/library/python/embed/install-sample#generate_credentials for how to get your own credentials file.
:type credentials_file: str :type credentials_file: str
@ -80,12 +86,14 @@ class AssistantGoogleBackend(Backend):
def start_conversation(self): def start_conversation(self):
""" Starts an assistant conversation """ """ Starts an assistant conversation """
if self.assistant: self.assistant.start_conversation() if self.assistant:
self.assistant.start_conversation()
def stop_conversation(self): def stop_conversation(self):
""" Stops an assistant conversation """ """ Stops an assistant conversation """
if self.assistant: self.assistant.stop_conversation() if self.assistant:
self.assistant.stop_conversation()
def run(self): def run(self):
@ -98,4 +106,3 @@ class AssistantGoogleBackend(Backend):
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et:

View file

@ -1,22 +1,24 @@
"""
.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
.. license:: MIT
"""
import concurrent
import json import json
import logging import logging
import os import os
import threading
import time
import grpc import grpc
import google.auth.transport.grpc import google.auth.transport.grpc
import google.auth.transport.requests import google.auth.transport.requests
import google.oauth2.credentials import google.oauth2.credentials
from google.assistant.embedded.v1alpha2 import embedded_assistant_pb2, embedded_assistant_pb2_grpc
import googlesamples.assistant.grpc.audio_helpers as audio_helpers import googlesamples.assistant.grpc.audio_helpers as audio_helpers
import googlesamples.assistant.grpc.device_helpers as device_helpers import googlesamples.assistant.grpc.device_helpers as device_helpers
import googlesamples.assistant.grpc.assistant_helpers as assistant_helpers import googlesamples.assistant.grpc.assistant_helpers as assistant_helpers
from tenacity import retry, stop_after_attempt, retry_if_exception from tenacity import retry, stop_after_attempt, retry_if_exception
from google.assistant.embedded.v1alpha2 import (
embedded_assistant_pb2,
embedded_assistant_pb2_grpc
)
from platypush.backend import Backend from platypush.backend import Backend
@ -53,15 +55,16 @@ class AssistantGooglePushtotalkBackend(Backend):
audio_flush_size = audio_helpers.DEFAULT_AUDIO_DEVICE_FLUSH_SIZE audio_flush_size = audio_helpers.DEFAULT_AUDIO_DEVICE_FLUSH_SIZE
grpc_deadline = 60 * 3 + 5 grpc_deadline = 60 * 3 + 5
def __init__(self, credentials_file=os.path.join( def __init__(self, *args,
os.path.expanduser('~'), '.config', credentials_file=os.path.join(
'google-oauthlib-tool', 'credentials.json'), os.path.expanduser('~'), '.config',
device_config=os.path.join( 'google-oauthlib-tool', 'credentials.json'),
os.path.expanduser('~'), '.config', 'googlesamples-assistant', device_config=os.path.join(
'device_config.json'), os.path.expanduser('~'), '.config', 'googlesamples-assistant',
lang='en-US', 'device_config.json'),
conversation_start_fifo = os.path.join(os.path.sep, 'tmp', 'pushtotalk.fifo'), lang='en-US',
*args, **kwargs): conversation_start_fifo=os.path.join(os.path.sep, 'tmp', 'pushtotalk.fifo'),
**kwargs):
""" """
:param credentials_file: Path to the Google OAuth credentials file (default: ~/.config/google-oauthlib-tool/credentials.json). See https://developers.google.com/assistant/sdk/guides/library/python/embed/install-sample#generate_credentials for how to get your own credentials file. :param credentials_file: Path to the Google OAuth credentials file (default: ~/.config/google-oauthlib-tool/credentials.json). See https://developers.google.com/assistant/sdk/guides/library/python/embed/install-sample#generate_credentials for how to get your own credentials file.
:type credentials_file: str :type credentials_file: str
@ -98,10 +101,10 @@ class AssistantGooglePushtotalkBackend(Backend):
**json.load(f)) **json.load(f))
http_request = google.auth.transport.requests.Request() http_request = google.auth.transport.requests.Request()
credentials.refresh(http_request) credentials.refresh(http_request)
except: except Exception as ex:
self.logger.error('Error loading credentials: %s', e) self.logger.error('Error loading credentials: %s', str(ex))
self.logger.error('Run google-oauthlib-tool to initialize ' self.logger.error('Run google-oauthlib-tool to initialize '
'new OAuth 2.0 credentials.') 'new OAuth 2.0 credentials.')
raise raise
# Create an authorized gRPC channel. # Create an authorized gRPC channel.
@ -151,43 +154,44 @@ class AssistantGooglePushtotalkBackend(Backend):
self.conversation_stream.stop_playback() self.conversation_stream.stop_playback()
self.bus.post(ConversationEndEvent()) self.bus.post(ConversationEndEvent())
def send_message(self, msg):
pass
def on_conversation_start(self): def on_conversation_start(self):
""" Conversation start handler """
self.bus.post(ConversationStartEvent()) self.bus.post(ConversationStartEvent())
def on_conversation_end(self): def on_conversation_end(self):
""" Conversation end handler """
self.bus.post(ConversationEndEvent()) self.bus.post(ConversationEndEvent())
def on_speech_recognized(self, speech): def on_speech_recognized(self, speech):
""" Speech recognized handler """
self.bus.post(SpeechRecognizedEvent(phrase=speech)) self.bus.post(SpeechRecognizedEvent(phrase=speech))
def run(self): def run(self):
""" Backend executor """
super().run() super().run()
with SampleAssistant(self.lang, self.device_model_id, self.device_id, with SampleAssistant(self.lang, self.device_model_id, self.device_id,
self.conversation_stream, self.conversation_stream,
self.grpc_channel, self.grpc_deadline, self.grpc_channel, self.grpc_deadline,
self.device_handler, self.device_handler,
on_conversation_start=self.on_conversation_start, on_conversation_start=self.on_conversation_start,
on_conversation_end=self.on_conversation_end, on_conversation_end=self.on_conversation_end,
on_speech_recognized=self.on_speech_recognized) as self.assistant: on_speech_recognized=self.on_speech_recognized) as self.assistant:
while not self.should_stop(): while not self.should_stop():
with open(self.conversation_start_fifo, 'r') as f: with open(self.conversation_start_fifo, 'r') as f:
for line in f: pass f.read()
self.logger.info('Received conversation start event') self.logger.info('Received conversation start event')
continue_conversation = True continue_conversation = True
user_request = None
while continue_conversation: while continue_conversation:
(user_request, continue_conversation) = self.assistant.assist() (user_request, continue_conversation) = self.assistant.assist()
self.logger('User request: {}'.format(user_request))
self.on_conversation_end() self.on_conversation_end()
class SampleAssistant(object): class SampleAssistant:
"""Sample Assistant that supports conversations and device actions. """Sample Assistant that supports conversations and device actions.
Args: Args:
@ -242,11 +246,14 @@ class SampleAssistant(object):
if e: if e:
return False return False
self.conversation_stream.close() self.conversation_stream.close()
return True
@staticmethod
def is_grpc_error_unavailable(e): def is_grpc_error_unavailable(e):
""" Returns True if the gRPC is not available """
is_grpc_error = isinstance(e, grpc.RpcError) is_grpc_error = isinstance(e, grpc.RpcError)
if is_grpc_error and (e.code() == grpc.StatusCode.UNAVAILABLE): if is_grpc_error and (e.code() == grpc.StatusCode.UNAVAILABLE):
self.logger.error('grpc unavailable error: %s', e) print('grpc unavailable error: {}'.format(e))
return True return True
return False return False
@ -288,7 +295,7 @@ class SampleAssistant(object):
self.logger.info('Transcript of user request: "%s".', user_request) self.logger.info('Transcript of user request: "%s".', user_request)
self.logger.info('Playing assistant response.') self.logger.info('Playing assistant response.')
if len(resp.audio_out.audio_data) > 0: if resp.audio_out.audio_data:
self.conversation_stream.write(resp.audio_out.audio_data) self.conversation_stream.write(resp.audio_out.audio_data)
if resp.dialog_state_out.conversation_state: if resp.dialog_state_out.conversation_state:
conversation_state = resp.dialog_state_out.conversation_state conversation_state = resp.dialog_state_out.conversation_state
@ -311,7 +318,7 @@ class SampleAssistant(object):
if fs: if fs:
device_actions_futures.extend(fs) device_actions_futures.extend(fs)
if len(device_actions_futures): if device_actions_futures:
self.logger.info('Waiting for device executions to complete.') self.logger.info('Waiting for device executions to complete.')
concurrent.futures.wait(device_actions_futures) concurrent.futures.wait(device_actions_futures)
@ -319,7 +326,7 @@ class SampleAssistant(object):
try: try:
self.conversation_stream.stop_playback() self.conversation_stream.stop_playback()
except: except Exception:
pass pass
if user_request and self.on_speech_recognized: if user_request and self.on_speech_recognized:
@ -331,12 +338,14 @@ class SampleAssistant(object):
"""Yields: AssistRequest messages to send to the API.""" """Yields: AssistRequest messages to send to the API."""
dialog_state_in = embedded_assistant_pb2.DialogStateIn( dialog_state_in = embedded_assistant_pb2.DialogStateIn(
language_code=self.language_code, language_code=self.language_code,
conversation_state=b'' conversation_state=b''
) )
if self.conversation_state: if self.conversation_state:
self.logger.debug('Sending conversation state.') self.logger.debug('Sending conversation state.')
dialog_state_in.conversation_state = self.conversation_state dialog_state_in.conversation_state = self.conversation_state
config = embedded_assistant_pb2.AssistConfig( config = embedded_assistant_pb2.AssistConfig(
audio_in_config=embedded_assistant_pb2.AudioInConfig( audio_in_config=embedded_assistant_pb2.AudioInConfig(
encoding='LINEAR16', encoding='LINEAR16',
@ -353,6 +362,7 @@ class SampleAssistant(object):
device_model_id=self.device_model_id, device_model_id=self.device_model_id,
) )
) )
# The first AssistRequest must contain the AssistConfig # The first AssistRequest must contain the AssistConfig
# and no audio data. # and no audio data.
yield embedded_assistant_pb2.AssistRequest(config=config) yield embedded_assistant_pb2.AssistRequest(config=config)
@ -362,4 +372,3 @@ class SampleAssistant(object):
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et:

View file

@ -1,3 +1,8 @@
"""
.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
.. license:: MIT
"""
import json import json
import os import os
import subprocess import subprocess
@ -57,6 +62,10 @@ class AssistantSnowboyBackend(Backend):
self.logger.info('Initialized Snowboy hotword detection') self.logger.info('Initialized Snowboy hotword detection')
def hotword_detected(self): def hotword_detected(self):
"""
Callback called on hotword detection
"""
def callback(): def callback():
self.bus.post(HotwordDetectedEvent(hotword=self.hotword)) self.bus.post(HotwordDetectedEvent(hotword=self.hotword))
return callback return callback
@ -67,4 +76,3 @@ class AssistantSnowboyBackend(Backend):
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et: