Skip to content

Commit

Permalink
Fixed comments
Browse files Browse the repository at this point in the history
  • Loading branch information
gornostal committed Apr 23, 2017
1 parent 670c2f2 commit 8693973
Show file tree
Hide file tree
Showing 59 changed files with 407 additions and 150 deletions.
8 changes: 8 additions & 0 deletions build-utils/builddoc.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash

set -ex

cd `dirname $0`/../docs

sphinx-apidoc -d 5 -o source ../ulauncher
make html
9 changes: 9 additions & 0 deletions build-utils/watchdoc.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash

cd `dirname $0`/..

watchmedo shell-command \
--patterns="*.py" \
--recursive \
--command='./build-utils/builddoc.sh' \
ulauncher
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.autodoc',
'sphinx.ext.viewcode',
# 'sphinx.ext.viewcode',
'sphinx.ext.githubpages']

# Add any paths that contain templates here, relative to this directory.
Expand Down
8 changes: 0 additions & 8 deletions docs/source/ulauncher.api.shared.action.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,6 @@ ulauncher\.api\.shared\.action\.ExtensionCustomAction module
:undoc-members:
:show-inheritance:

ulauncher\.api\.shared\.action\.KeepAppOpenAction module
--------------------------------------------------------

.. automodule:: ulauncher.api.shared.action.KeepAppOpenAction
:members:
:undoc-members:
:show-inheritance:

ulauncher\.api\.shared\.action\.LaunchAppAction module
------------------------------------------------------

Expand Down
27 changes: 27 additions & 0 deletions ulauncher/api/client/Client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@


class Client(object):
"""
Instantiated in extension code and manages data transfer from/to Ulauncher app
:param ~ulauncher.api.client.Extension extension:
:param str ws_api_url: uses env. var `ULAUNCHER_WS_API` by default
"""

def __init__(self, extension, ws_api_url=os.environ.get('ULAUNCHER_WS_API')):
self.ws_api_url = ws_api_url
Expand All @@ -22,6 +28,9 @@ def __init__(self, extension, ws_api_url=os.environ.get('ULAUNCHER_WS_API')):
self.ws = None

def connect(self):
"""
Connects to WS server and blocks thread
"""
websocket.enableTrace(False)
self.ws = websocket.WebSocketApp(self.ws_api_url,
on_message=self.on_message,
Expand All @@ -31,6 +40,12 @@ def connect(self):
self.ws.run_forever()

def on_message(self, ws, message):
"""
Parses message from Ulauncher and triggers extension event
:param websocket.WebSocketApp ws:
:param str message:
"""
event = pickle.loads(message)
logger.debug('Incoming event %s' % type(event).__name__)
try:
Expand All @@ -42,6 +57,13 @@ def on_error(self, ws, error):
logger.error('WS Client error %s' % error)

def on_close(self, ws):
"""
Terminates extension process on WS disconnect.
Triggers :class:`~ulauncher.api.shared.event.SystemExitEvent` for graceful shutdown
:param websocket.WebSocketApp ws:
"""
logger.warning("Connection closed. Exiting")
self.extension.trigger_event(SystemExitEvent())
# extension has 0.5 sec to save it's state, after that it will be terminated
Expand All @@ -51,5 +73,10 @@ def on_open(self, ws):
self.ws = ws

def send(self, response):
"""
Sends response to Ulauncher
:param ~ulauncher.api.shared.Response.Response response:
"""
logger.debug('Send message')
self.ws.send(pickle.dumps(response))
10 changes: 10 additions & 0 deletions ulauncher/api/client/EventListener.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@

class EventListener(object):
"""
Base event listener class
"""

def on_event(self, event, extension):
"""
:param ~ulauncher.api.shared.event.BaseEvent event:
:param ~ulauncher.api.client.Extension.Extension extension:
:rtype: ~ulauncher.api.shared.action.BaseAction.BaseAction or None
:return: Instance of `BaseAction` if needed
"""
pass
21 changes: 21 additions & 0 deletions ulauncher/api/client/Extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@


class Extension(object):
"""
Manages extension runtime
"""

def __init__(self):
self._listeners = defaultdict(list)
Expand All @@ -19,12 +22,27 @@ def __init__(self):
setup_logging()

def subscribe(self, event_type, event_listener):
"""
Example:
extension.subscribe(PreferencesEvent, PreferencesEventListener())
:param type event_type:
:param ~ulauncher.api.client.EventListener.EventListener event_listener:
"""
self._listeners[event_type].append(event_listener)

def get_listeners_for_event(self, event):
"""
:param ~ulauncher.api.shared.event.BaseEvent event:
:rtype: ~ulauncher.api.client.EventListener.EventListener
"""
return self._listeners[type(event)]

def trigger_event(self, event):
"""
:param ~ulauncher.api.shared.event.BaseEvent event:
"""
listeners = self.get_listeners_for_event(event)
if not listeners:
self.logger.debug('No listeners for event %s' % type(event).__name__)
Expand All @@ -37,6 +55,9 @@ def trigger_event(self, event):
self._client.send(Response(event, action))

def run(self):
"""
Subscribes to events and connects to Ulauncher WS server
"""
self.subscribe(PreferencesEvent, PreferencesEventListener())
self.subscribe(PreferencesUpdateEvent, PreferencesUpdateEventListener())
self._client.connect()
Expand Down
5 changes: 0 additions & 5 deletions ulauncher/api/client/setup_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@
BOLD_SEQ = "\033[1m"


class NullHandler(logging.Handler):
def emit(self, record):
pass


def setup_logging():
root = logging.getLogger()

Expand Down
15 changes: 15 additions & 0 deletions ulauncher/api/server/DeferredResultRenderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,18 @@


class DeferredResultRenderer(object):
"""
Handles asynchronous render for extensions
"""

LOADING_DELAY = 0.5 # delay in sec before Loading... is rendered

@classmethod
@singleton
def get_instance(cls):
"""
Returns singleton instance
"""
return cls()

def __init__(self):
Expand All @@ -28,6 +34,9 @@ def get_active_controller(self):
return self.active_controller

def handle_event(self, event, controller):
"""
Schedules "Loading..." message and returns :class:`~ulauncher.api.shared.action.DoNothingAction.DoNothingAction`
"""
self._cancel_loading()
self.loading = Timer(self.LOADING_DELAY,
partial(self._render_loading,
Expand All @@ -39,13 +48,19 @@ def handle_event(self, event, controller):
return DoNothingAction()

def handle_response(self, response, controller):
"""
Calls `response.action.run()`
"""
if self.active_controller != controller or self.active_event != response.event:
return

self._cancel_loading()
response.action.run()

def on_query_change(self):
"""
Cancels "Loading..."
"""
self._cancel_loading()
self.active_event = None
self.active_controller = None
Expand Down
16 changes: 15 additions & 1 deletion ulauncher/api/server/ExtensionController.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@


class ExtensionController(WebSocket):
"""
Handles messages from Ulauncher app.
Implements `send_event()` to send events back to Ulauncher
:param list controllers: list of :class:`~ulauncher.api.server.ExtensionController`
"""

extension_id = None
manifest = None
Expand Down Expand Up @@ -48,7 +55,9 @@ def get_extension_id(self):

def handleMessage(self):
"""
Inbound response
Handles incoming message stored in `self.data` by invoking
:meth:`~ulauncher.api.server.DeferredResultRenderer.DeferredResultRenderer.handle_response`
of `DeferredResultRenderer`
"""
response = pickle.loads(self.data)

Expand All @@ -59,6 +68,11 @@ def handleMessage(self):
self.resultRenderer.handle_response(response, self)

def handleConnected(self):
"""
* Appends `self` to `self.controllers`
* Validates manifest file.
* Sends :class:`PreferencesEvent` to extension
"""
self.extension_id = self.request.path[1:]
if not self.extension_id:
raise Exception('Incorrect path %s' % self.request.path)
Expand Down
3 changes: 3 additions & 0 deletions ulauncher/api/server/ExtensionManifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@


class ExtensionManifest(object):
"""
Reads `manifest.json`
"""

@classmethod
def open(cls, extension_id, extensions_dir=EXTENSIONS_DIR):
Expand Down
18 changes: 16 additions & 2 deletions ulauncher/api/server/ExtensionPreferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@


class ExtensionPreferences(object):
"""
Manages extension preferences. Stores them in pickled file in cache directory
"""

def __init__(self, extension_id, manifest, ext_preferences_dir=EXT_PREFERENCES_DIR):
self.db_path = os.path.join(ext_preferences_dir, '%s.db' % extension_id)
Expand All @@ -16,7 +19,8 @@ def __init__(self, extension_id, manifest, ext_preferences_dir=EXT_PREFERENCES_D

def get_items(self, type=None):
"""
Returns list of dicts: [{id: .., type: .., defalut_value: .., user_value: ..., value: ..., description}]
:param str type:
:rtype: list of dicts: [{id: .., type: .., defalut_value: .., user_value: ..., value: ..., description}, ...]
"""
self._open_db()

Expand All @@ -40,7 +44,7 @@ def get_items(self, type=None):

def get_dict(self):
"""
Returns dict(id=value, id2=value2, ...)
:rtype: dict(id=value, id2=value2, ...)
"""
items = {}
for i in self.get_items():
Expand All @@ -51,15 +55,25 @@ def get_dict(self):
def get(self, id):
"""
Returns one item
:rtype: dict
"""
for i in self.get_items():
if i['id'] == id:
return i

def get_active_keywords(self):
"""
Filters items by type "keyword"
"""
return [p['value'] for p in self.get_items(type='keyword') if p['value']]

def set(self, id, value):
"""
Updates preference
:param str id: id as defined in manifest
:param str value:
"""
self.db.put(id, value)
self.db.commit()

Expand Down
13 changes: 11 additions & 2 deletions ulauncher/api/server/ExtensionRunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ def __init__(self):
self.verbose = get_options().verbose

def run_all(self):
"""
Finds all extensions in `EXTENSIONS_DIR` and runs them
"""
for id, _ in find_extensions(self.extensions_dir):
try:
self.run(id)
Expand All @@ -37,7 +40,10 @@ def run_all(self):

def run(self, extension_id):
"""
Returns a thread object
* Validates manifest
* Runs extension in a new process
:rtype: :class:`threading.Thread`
"""
if self.is_running(extension_id):
raise ExtensionIsRunningError('Extension ID: %s' % extension_id)
Expand All @@ -51,7 +57,7 @@ def run(self, extension_id):

def _run_process(self, extension_id):
"""
(Blocks execution)
Blocking function
"""
cmd = [sys.executable, os.path.join(self.extensions_dir, extension_id, 'main.py')]
env = os.environ.copy()
Expand Down Expand Up @@ -95,6 +101,9 @@ def _run_process(self, extension_id):
logger.error('Extension "%s" exited with code %s. Restarting...' % (extension_id, code))

def stop(self, extension_id):
"""
Terminates extension
"""
if not self.is_running(extension_id):
raise ExtensionIsNotRunningError('Extension ID: %s' % extension_id)

Expand Down

0 comments on commit 8693973

Please sign in to comment.