summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugins/alias.py16
-rw-r--r--src/common.py105
-rw-r--r--src/plugin.py46
-rw-r--r--src/timed_events.py43
4 files changed, 150 insertions, 60 deletions
diff --git a/plugins/alias.py b/plugins/alias.py
index 163e4c26..4d4a3bf4 100644
--- a/plugins/alias.py
+++ b/plugins/alias.py
@@ -6,7 +6,7 @@ Allows the creation and the removal of personal aliases.
from plugin import BasePlugin
import common
-from common import parse_command_args_to_alias as parse
+from common import shell_split
class Plugin(BasePlugin):
def init(self):
@@ -27,18 +27,18 @@ class Plugin(BasePlugin):
"""
arg = common.shell_split(line)
if len(arg) < 2:
- self.core.information('Alias: Not enough parameters', 'Error')
+ self.api.information('Alias: Not enough parameters', 'Error')
return
alias = arg[0]
command = arg[1]
tmp_args = arg[2] if len(arg) > 2 else ''
if alias in self.core.commands or alias in self.commands:
- self.core.information('Alias: command already exists', 'Error')
+ self.api.information('Alias: command already exists', 'Error')
return
- self.commands[alias] = lambda arg: self.get_command(command)(parse(arg, tmp_args))
+ self.commands[alias] = lambda arg: self.get_command(command)(tmp_args.format(*shell_split(arg)))
self.add_command(alias, self.commands[alias], 'This command is an alias for /%s %s' %( command, tmp_args))
- self.core.information('Alias /%s successfuly created' % alias, 'Info')
+ self.api.information('Alias /%s successfuly created' % alias, 'Info')
def command_unalias(self, alias):
"""
@@ -47,7 +47,7 @@ class Plugin(BasePlugin):
if alias in self.commands:
del self.commands[alias]
self.del_command(alias)
- self.core.information('Alias /%s successfuly deleted' % alias, 'Info')
+ self.api.information('Alias /%s successfuly deleted' % alias, 'Info')
def completion_unalias(self, the_input):
aliases = [alias for alias in self.commands]
@@ -61,6 +61,6 @@ class Plugin(BasePlugin):
pass
if name in self.core.commands:
return self.core.commands[name][0]
- elif name in self.core.current_tab().commands:
- return self.core.current_tab().commands[name][0]
+ elif name in self.api.current_tab().commands:
+ return self.api.current_tab().commands[name][0]
return dummy
diff --git a/src/common.py b/src/common.py
index e4e3a52d..1a3027e7 100644
--- a/src/common.py
+++ b/src/common.py
@@ -6,7 +6,7 @@
# it under the terms of the zlib license. See the COPYING file.
"""
-various useful functions
+Various useful functions.
"""
from datetime import datetime, timedelta
@@ -29,6 +29,13 @@ ROOM_STATE_HL = 13
def get_base64_from_file(path):
"""
Convert the content of a file to base64
+
+ :param str path: The path of the file to convert.
+ :return: A tuple of (encoded data, mime type, sha1 hash) if
+ the file exists and does not exceeds the upper size limit of 16384.
+ :return: (None, None, error message) if it fails
+ :rtype: :py:class:`tuple`
+
"""
if not os.path.isfile(path):
return (None, None, "File does not exist")
@@ -44,7 +51,11 @@ def get_base64_from_file(path):
def get_output_of_command(command):
"""
- Runs a command and returns its output
+ Runs a command and returns its output.
+
+ :param str command: The command to run.
+ :return: The output or None
+ :rtype: :py:class:`str`
"""
try:
return subprocess.check_output(command.split()).decode('utf-8').split('\n')
@@ -53,9 +64,14 @@ def get_output_of_command(command):
def is_in_path(command, return_abs_path=False):
"""
- Return True if 'command' is found in one of the directories in the user's
- path. If 'return_abs_path' is True, return the absolute path of the first
- found command instead. Return False otherwise and on errors
+ Check if *command* is in the $PATH or not.
+
+ :param str command: The command to be checked.
+ :param bool return_abs_path: Return the absolute path of the command instead
+ of True if the command is found.
+ :return: True if the command is found, the command path if the command is found
+ and *return_abs_path* is True, otherwise False.
+
"""
for directory in os.getenv('PATH').split(os.pathsep):
try:
@@ -95,6 +111,8 @@ def get_os_info():
"""
Returns a detailed and well formated string containing
informations about the operating system
+
+ :rtype: str
"""
if os.name == 'posix':
executable = 'lsb_release'
@@ -151,14 +169,21 @@ def get_os_info():
def datetime_tuple(timestamp):
"""
- Convert timestamp using strptime and the format: %Y%m%dT%H:%M:%S
+ Convert a timestamp using strptime and the format: %Y%m%dT%H:%M:%S.
- Because of various datetime formats are used the following exceptions
+ Because various datetime formats are used, the following exceptions
are handled:
- - Optional milliseconds appened to the string are removed
- - Optional Z (that means UTC) appened to the string are removed
- - XEP-082 datetime strings have all '-' cahrs removed to meet
- the above format.
+
+ * Optional milliseconds appened to the string are removed
+ * Optional Z (that means UTC) appened to the string are removed
+ * XEP-082 datetime strings have all '-' chars removed to meet the above format.
+
+ :param str timestamp: The string containing the formatted date.
+ :return: The date.
+ :rtype: :py:class:`datetime.datetime`
+
+ >>> common.datetime_tuple('20130226T06:23:12')
+ datetime.datetime(2013, 2, 26, 8, 23, 12)
"""
timestamp = timestamp.split('.')[0]
timestamp = timestamp.replace('-', '')
@@ -172,6 +197,17 @@ def datetime_tuple(timestamp):
return ret
def shell_split(st):
+ """
+ Split a string correctly according to the quotes
+ around the elements.
+
+ :param str st: The string to split.
+ :return: A list of the different of the string.
+ :rtype: :py:class:`list`
+
+ >>> shell_split('"sdf 1" "toto 2"')
+ ['sdf 1', 'toto 2']
+ """
sh = shlex.shlex(st, posix=True)
sh.commenters = ''
sh.whitespace_split = True
@@ -188,7 +224,12 @@ def shell_split(st):
def parse_str_to_secs(duration=''):
"""
- Parse a string of with a number of d, h, m, s
+ Parse a string of with a number of d, h, m, s.
+
+ :param str duration: The formatted string.
+ :return: The number of seconds represented by the string
+ :rtype: :py:class:`int`
+
>>> parse_str_to_secs("1d3m1h")
90180
"""
@@ -210,8 +251,15 @@ def parse_str_to_secs(duration=''):
def parse_secs_to_str(duration=0):
"""
+ Do the reverse operation of :py:func:`parse_str_to_secs`.
+
Parse a number of seconds to a human-readable string.
The string has the form XdXhXmXs. 0 units are removed.
+
+ :param int duration: The duration, in seconds.
+ :return: A formatted string containing the duration.
+ :rtype: :py:class:`str`
+
>>> parse_secs_to_str(3601)
1h1s
"""
@@ -230,36 +278,13 @@ def parse_secs_to_str(duration=0):
result = '0s'
return result
-def parse_command_args_to_alias(arg, strto):
- """
- Parse command parameters.
- Numbers can be from 0 to 9.
- >>> parse_command_args_to_alias('sdf koin', '%1 %0')
- "koin sdf"
+def safeJID(*args, **kwargs):
"""
- if '%' not in strto:
- return strto + arg
- args = shell_split(arg)
- l = len(args)
- dest = ''
- var_num = False
- for i in strto:
- if i != '%':
- if not var_num:
- dest += i
- elif i in string.digits:
- if 0 <= int(i) < l:
- dest += args[int(i)]
- var_num = False
- elif i == '%':
- if var_num:
- dest += '%'
- var_num = False
- else:
- var_num = True
- return dest
+ Construct a :py:class:`sleekxmpp.JID` object from a string.
-def safeJID(*args, **kwargs):
+ Used to avoid tracebacks during is stringprep fails
+ (fall back to a JID with an empty string).
+ """
try:
return JID(*args, **kwargs)
except InvalidJID:
diff --git a/src/plugin.py b/src/plugin.py
index 602d0326..2ef83510 100644
--- a/src/plugin.py
+++ b/src/plugin.py
@@ -6,6 +6,7 @@ These are used in the plugin system added in poezio 0.7.5
import os
from functools import partial
from configparser import RawConfigParser
+from timed_events import TimedEvent, DelayedEvent
import config
import inspect
import traceback
@@ -120,12 +121,49 @@ class PluginAPI(object):
def add_timed_event(self, _, *args, **kwargs):
"""
- Add a timed event.
+ Schedule a timed event.
- :param event: The timed event to add.
+ :param timed_events.TimedEvent event: The timed event to schedule.
"""
return self.core.add_timed_event(*args, **kwargs)
+ def remove_timed_event(self, _, *args, **kwargs):
+ """
+ Unschedule a timed event.
+
+ :param timed_events.TimedEvent event: The event to unschedule.
+ """
+ return self.core.remove_timed_event(*args, **kwargs)
+
+ def create_timed_event(self, _, *args, **kwargs):
+ """
+ Create a timed event, but do not schedule it;
+ :py:func:`~PluginAPI.add_timed_event` must be used for that.
+
+ :param datetime.datetime date: The time at which the handler must be executed
+ :param function callback: The handler that will be executed
+ :param \*args: Optional arguments passed to the handler.
+ :return: The created event.
+ :rtype: :py:class:`timed_events.TimedEvent`
+ """
+ return TimedEvent(*args, **kwargs)
+
+ def create_delayed_event(self, _, *args, **kwargs):
+ """
+ Create a delayed event, but do not schedule it;
+ :py:func:`~PluginAPI.add_timed_event` must be used for that.
+
+ A delayed event is a timed event with a delay from the time
+ this function is called (instead of a datetime).
+
+ :param int delay: The number of seconds to schedule the execution
+ :param function callback: The handler that will be executed
+ :param \*args: Optional arguments passed to the handler.
+ :return: The created event.
+ :rtype: :py:class:`timed_events.DelayedEvent`
+ """
+ return DelayedEvent(*args, **kwargs)
+
def information(self, _, *args, **kwargs):
"""
Display a new message in the information buffer.
@@ -139,7 +177,7 @@ class PluginAPI(object):
"""
Get the current Tab.
- :returns: tabs.Tab The current tab.
+ :returns: The current tab.
"""
return self.core.current_tab()
@@ -176,7 +214,7 @@ class PluginAPI(object):
Example string: "<server> [port]"
- :raises: Exception If the command already exists.
+ :raises Exception: If the command already exists.
"""
return self.plugin_manager.add_command(module, *args, **kwargs)
diff --git a/src/timed_events.py b/src/timed_events.py
index 5be2aba2..a922ee03 100644
--- a/src/timed_events.py
+++ b/src/timed_events.py
@@ -6,8 +6,11 @@
# it under the terms of the zlib license. See the COPYING file.
"""
-To use these, just use core.add_timed_event(event)
-where event is an instance of one of these classes
+Timed events are the standard way to schedule events for later in poezio.
+
+Once created, they must be added to the list of checked events with
+:py:func:`Core.add_timed_event` (within poezio) or with
+:py:func:`.PluginAPI.add_timed_event` (within a plugin).
"""
import logging
@@ -18,13 +21,22 @@ import datetime
class TimedEvent(object):
"""
- An event with a callback that is called when the specified time is passed
+ An event with a callback that is called when the specified time is passed.
+
Note that these events can NOT be used for very small delay or a very
precise date, since the check for events is done once per second, as
a maximum.
+
The callback and its arguments should be passed as the lasts arguments.
"""
def __init__(self, date, callback, *args):
+ """
+ Create a new timed event.
+
+ :param datetime.datetime date: Time at which the callback must be run.
+ :param function callback: The handler that will be executed.
+ :param \*args: Optional arguments passed to the handler.
+ """
self._callback = callback
self.args = args
self.repetive = False
@@ -42,7 +54,11 @@ class TimedEvent(object):
def has_timed_out(self, current_date):
"""
- returns True if the callback should be called
+ Check if the event has timed out.
+
+ :param datetime.datetime current_date: The current date.
+ :returns: True if the callback should be called
+ :rtype: bool
"""
if self.next_call_date < current_date:
return True
@@ -51,22 +67,33 @@ class TimedEvent(object):
def change_date(self, date):
"""
- Simply change the date of the event
+ Simply change the date of the event.
+
+ :param datetime.datetime date: Next date.
"""
self.next_call_date = date
def add_delay(self, delay):
"""
- Add a delay (in seconds) to the date
+ Add a delay (in seconds) to the date.
+
+ :param int delay: The delay to add.
"""
self.next_call_date += datetime.timedelta(seconds=delay)
class DelayedEvent(TimedEvent):
"""
- The date is calculated from now + a delay in seconds
- Use it if you want an event to happen in, e.g. 6 seconds
+ A TimedEvent, but with the date calculated from now + a delay in seconds.
+ Use it if you want an event to happen in, e.g. 6 seconds.
"""
def __init__(self, delay, callback, *args):
+ """
+ Create a new DelayedEvent.
+
+ :param int delay: The number of seconds.
+ :param function callback: The handler that will be executed.
+ :param \*args: Optional arguments passed to the handler.
+ """
date = datetime.datetime.now() + datetime.timedelta(seconds=delay)
TimedEvent.__init__(self, date, callback, *args)