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
|
||||
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
|
||||
|
|
107
src/common.py
107
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"
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
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:
|
||||
return JID(*args, **kwargs)
|
||||
except InvalidJID:
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in a new issue