Document with sphinx timed_events, common, and add methods to PluginAPI
- add methods related to timed events to the PluginAPI - remove parse_command_args_to_alias because str.format does that, and better → update the alias plugin
This commit is contained in:
parent
0a2bd90c6d
commit
dbde08a526
4 changed files with 151 additions and 61 deletions
|
@ -6,7 +6,7 @@ Allows the creation and the removal of personal aliases.
|
||||||
|
|
||||||
from plugin import BasePlugin
|
from plugin import BasePlugin
|
||||||
import common
|
import common
|
||||||
from common import parse_command_args_to_alias as parse
|
from common import shell_split
|
||||||
|
|
||||||
class Plugin(BasePlugin):
|
class Plugin(BasePlugin):
|
||||||
def init(self):
|
def init(self):
|
||||||
|
@ -27,18 +27,18 @@ class Plugin(BasePlugin):
|
||||||
"""
|
"""
|
||||||
arg = common.shell_split(line)
|
arg = common.shell_split(line)
|
||||||
if len(arg) < 2:
|
if len(arg) < 2:
|
||||||
self.core.information('Alias: Not enough parameters', 'Error')
|
self.api.information('Alias: Not enough parameters', 'Error')
|
||||||
return
|
return
|
||||||
alias = arg[0]
|
alias = arg[0]
|
||||||
command = arg[1]
|
command = arg[1]
|
||||||
tmp_args = arg[2] if len(arg) > 2 else ''
|
tmp_args = arg[2] if len(arg) > 2 else ''
|
||||||
|
|
||||||
if alias in self.core.commands or alias in self.commands:
|
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
|
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.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):
|
def command_unalias(self, alias):
|
||||||
"""
|
"""
|
||||||
|
@ -47,7 +47,7 @@ class Plugin(BasePlugin):
|
||||||
if alias in self.commands:
|
if alias in self.commands:
|
||||||
del self.commands[alias]
|
del self.commands[alias]
|
||||||
self.del_command(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):
|
def completion_unalias(self, the_input):
|
||||||
aliases = [alias for alias in self.commands]
|
aliases = [alias for alias in self.commands]
|
||||||
|
@ -61,6 +61,6 @@ class Plugin(BasePlugin):
|
||||||
pass
|
pass
|
||||||
if name in self.core.commands:
|
if name in self.core.commands:
|
||||||
return self.core.commands[name][0]
|
return self.core.commands[name][0]
|
||||||
elif name in self.core.current_tab().commands:
|
elif name in self.api.current_tab().commands:
|
||||||
return self.core.current_tab().commands[name][0]
|
return self.api.current_tab().commands[name][0]
|
||||||
return dummy
|
return dummy
|
||||||
|
|
107
src/common.py
107
src/common.py
|
@ -6,7 +6,7 @@
|
||||||
# it under the terms of the zlib license. See the COPYING file.
|
# it under the terms of the zlib license. See the COPYING file.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
various useful functions
|
Various useful functions.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
@ -29,6 +29,13 @@ ROOM_STATE_HL = 13
|
||||||
def get_base64_from_file(path):
|
def get_base64_from_file(path):
|
||||||
"""
|
"""
|
||||||
Convert the content of a file to base64
|
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):
|
if not os.path.isfile(path):
|
||||||
return (None, None, "File does not exist")
|
return (None, None, "File does not exist")
|
||||||
|
@ -44,7 +51,11 @@ def get_base64_from_file(path):
|
||||||
|
|
||||||
def get_output_of_command(command):
|
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:
|
try:
|
||||||
return subprocess.check_output(command.split()).decode('utf-8').split('\n')
|
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):
|
def is_in_path(command, return_abs_path=False):
|
||||||
"""
|
"""
|
||||||
Return True if 'command' is found in one of the directories in the user's
|
Check if *command* is in the $PATH or not.
|
||||||
path. If 'return_abs_path' is True, return the absolute path of the first
|
|
||||||
found command instead. Return False otherwise and on errors
|
: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):
|
for directory in os.getenv('PATH').split(os.pathsep):
|
||||||
try:
|
try:
|
||||||
|
@ -95,6 +111,8 @@ def get_os_info():
|
||||||
"""
|
"""
|
||||||
Returns a detailed and well formated string containing
|
Returns a detailed and well formated string containing
|
||||||
informations about the operating system
|
informations about the operating system
|
||||||
|
|
||||||
|
:rtype: str
|
||||||
"""
|
"""
|
||||||
if os.name == 'posix':
|
if os.name == 'posix':
|
||||||
executable = 'lsb_release'
|
executable = 'lsb_release'
|
||||||
|
@ -151,14 +169,21 @@ def get_os_info():
|
||||||
|
|
||||||
def datetime_tuple(timestamp):
|
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:
|
are handled:
|
||||||
- Optional milliseconds appened to the string are removed
|
|
||||||
- Optional Z (that means UTC) appened to the string are removed
|
* Optional milliseconds appened to the string are removed
|
||||||
- XEP-082 datetime strings have all '-' cahrs removed to meet
|
* Optional Z (that means UTC) appened to the string are removed
|
||||||
the above format.
|
* 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.split('.')[0]
|
||||||
timestamp = timestamp.replace('-', '')
|
timestamp = timestamp.replace('-', '')
|
||||||
|
@ -172,6 +197,17 @@ def datetime_tuple(timestamp):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def shell_split(st):
|
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 = shlex.shlex(st, posix=True)
|
||||||
sh.commenters = ''
|
sh.commenters = ''
|
||||||
sh.whitespace_split = True
|
sh.whitespace_split = True
|
||||||
|
@ -188,7 +224,12 @@ def shell_split(st):
|
||||||
|
|
||||||
def parse_str_to_secs(duration=''):
|
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")
|
>>> parse_str_to_secs("1d3m1h")
|
||||||
90180
|
90180
|
||||||
"""
|
"""
|
||||||
|
@ -210,8 +251,15 @@ def parse_str_to_secs(duration=''):
|
||||||
|
|
||||||
def parse_secs_to_str(duration=0):
|
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.
|
Parse a number of seconds to a human-readable string.
|
||||||
The string has the form XdXhXmXs. 0 units are removed.
|
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)
|
>>> parse_secs_to_str(3601)
|
||||||
1h1s
|
1h1s
|
||||||
"""
|
"""
|
||||||
|
@ -230,36 +278,13 @@ def parse_secs_to_str(duration=0):
|
||||||
result = '0s'
|
result = '0s'
|
||||||
return result
|
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"
|
|
||||||
"""
|
|
||||||
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
|
|
||||||
|
|
||||||
def safeJID(*args, **kwargs):
|
def safeJID(*args, **kwargs):
|
||||||
|
"""
|
||||||
|
Construct a :py:class:`sleekxmpp.JID` object from a string.
|
||||||
|
|
||||||
|
Used to avoid tracebacks during is stringprep fails
|
||||||
|
(fall back to a JID with an empty string).
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
return JID(*args, **kwargs)
|
return JID(*args, **kwargs)
|
||||||
except InvalidJID:
|
except InvalidJID:
|
||||||
|
|
|
@ -6,6 +6,7 @@ These are used in the plugin system added in poezio 0.7.5
|
||||||
import os
|
import os
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from configparser import RawConfigParser
|
from configparser import RawConfigParser
|
||||||
|
from timed_events import TimedEvent, DelayedEvent
|
||||||
import config
|
import config
|
||||||
import inspect
|
import inspect
|
||||||
import traceback
|
import traceback
|
||||||
|
@ -120,12 +121,49 @@ class PluginAPI(object):
|
||||||
|
|
||||||
def add_timed_event(self, _, *args, **kwargs):
|
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)
|
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):
|
def information(self, _, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Display a new message in the information buffer.
|
Display a new message in the information buffer.
|
||||||
|
@ -139,7 +177,7 @@ class PluginAPI(object):
|
||||||
"""
|
"""
|
||||||
Get the current Tab.
|
Get the current Tab.
|
||||||
|
|
||||||
:returns: tabs.Tab The current tab.
|
:returns: The current tab.
|
||||||
"""
|
"""
|
||||||
return self.core.current_tab()
|
return self.core.current_tab()
|
||||||
|
|
||||||
|
@ -176,7 +214,7 @@ class PluginAPI(object):
|
||||||
|
|
||||||
Example string: "<server> [port]"
|
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)
|
return self.plugin_manager.add_command(module, *args, **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,11 @@
|
||||||
# it under the terms of the zlib license. See the COPYING file.
|
# it under the terms of the zlib license. See the COPYING file.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
To use these, just use core.add_timed_event(event)
|
Timed events are the standard way to schedule events for later in poezio.
|
||||||
where event is an instance of one of these classes
|
|
||||||
|
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
|
import logging
|
||||||
|
@ -18,13 +21,22 @@ import datetime
|
||||||
|
|
||||||
class TimedEvent(object):
|
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
|
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
|
precise date, since the check for events is done once per second, as
|
||||||
a maximum.
|
a maximum.
|
||||||
|
|
||||||
The callback and its arguments should be passed as the lasts arguments.
|
The callback and its arguments should be passed as the lasts arguments.
|
||||||
"""
|
"""
|
||||||
def __init__(self, date, callback, *args):
|
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._callback = callback
|
||||||
self.args = args
|
self.args = args
|
||||||
self.repetive = False
|
self.repetive = False
|
||||||
|
@ -42,7 +54,11 @@ class TimedEvent(object):
|
||||||
|
|
||||||
def has_timed_out(self, current_date):
|
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:
|
if self.next_call_date < current_date:
|
||||||
return True
|
return True
|
||||||
|
@ -51,22 +67,33 @@ class TimedEvent(object):
|
||||||
|
|
||||||
def change_date(self, date):
|
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
|
self.next_call_date = date
|
||||||
|
|
||||||
def add_delay(self, delay):
|
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)
|
self.next_call_date += datetime.timedelta(seconds=delay)
|
||||||
|
|
||||||
class DelayedEvent(TimedEvent):
|
class DelayedEvent(TimedEvent):
|
||||||
"""
|
"""
|
||||||
The date is calculated from now + a delay in 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
|
Use it if you want an event to happen in, e.g. 6 seconds.
|
||||||
"""
|
"""
|
||||||
def __init__(self, delay, callback, *args):
|
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)
|
date = datetime.datetime.now() + datetime.timedelta(seconds=delay)
|
||||||
TimedEvent.__init__(self, date, callback, *args)
|
TimedEvent.__init__(self, date, callback, *args)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue