summaryrefslogtreecommitdiff
path: root/src/decorators.py
diff options
context:
space:
mode:
authorFlorent Le Coz <louiz@louiz.org>2014-11-25 16:58:26 +0100
committerFlorent Le Coz <louiz@louiz.org>2014-11-25 17:07:45 +0100
commite1808a8455aadc9fac300c68e397b712a030ae29 (patch)
treedf5ad7cf84a8e9faa4cd018189bf585ee9d7bdeb /src/decorators.py
parent61b5c6a91e58b81811bcbf8e789b0bf112d3a416 (diff)
downloadpoezio-e1808a8455aadc9fac300c68e397b712a030ae29.tar.gz
poezio-e1808a8455aadc9fac300c68e397b712a030ae29.tar.bz2
poezio-e1808a8455aadc9fac300c68e397b712a030ae29.tar.xz
poezio-e1808a8455aadc9fac300c68e397b712a030ae29.zip
Parse command arguments using a decorator and make things more consistent
Avoid surprises with some commands accepting quoted arguments and some other not. fix #2555
Diffstat (limited to 'src/decorators.py')
-rw-r--r--src/decorators.py92
1 files changed, 92 insertions, 0 deletions
diff --git a/src/decorators.py b/src/decorators.py
index 251d8749..627d8f59 100644
--- a/src/decorators.py
+++ b/src/decorators.py
@@ -2,6 +2,8 @@
Module containing various decorators
"""
+import common
+
class RefreshWrapper(object):
def __init__(self):
self.core = None
@@ -41,3 +43,93 @@ class RefreshWrapper(object):
return wrap
refresh_wrapper = RefreshWrapper()
+
+class CommandArgParser(object):
+ """Modify the string argument of the function into a list of strings
+ containing the right number of extracted arguments, or None if we don’t
+ have enough.
+ """
+ @staticmethod
+ def raw(func):
+ """Just call the function with a single string, which is the original string
+ untouched
+ """
+ def wrap(self, args, *a, **kw):
+ return func(self, args, *a, **kw)
+ return wrap
+
+ @staticmethod
+ def ignored(func):
+ """
+ Call the function without any argument
+ """
+ def wrap(self, args, *a, **kw):
+ return func(self, *a, **kw)
+ return wrap
+
+ @staticmethod
+ def quoted(mandatory, optional=0, defaults=[],
+ ignore_trailing_arguments=False):
+
+ """The function receives a list with a number of arguments that is between
+ the numbers `mandatory` and `optional`.
+
+ If the string doesn’t contain at least `mandatory` arguments, we return
+ None because the given arguments are invalid.
+
+ If there are any remaining arguments after `mandatory` and `optional`
+ arguments have been found (and “ignore_trailing_arguments" is not True),
+ we happen them to the last argument of the list.
+
+ An argument is a string (with or without whitespaces) between to quotes
+ ("), or a whitespace separated word (if not inside quotes).
+
+ The argument `defaults` is a list of strings that are used when an
+ optional argument is missing. For example if we accept one optional
+ argument, zero is available but we have one value in the `defaults`
+ list, we use that string inplace. The `defaults` list can only
+ replace missing optional arguments, not mandatory ones. And it
+ should not contain more than `mandatory` values. Also you cannot
+
+ Example:
+ This method needs at least one argument, and accepts up to 3
+ arguments
+
+ >> @command_args_parser.quoted(1, 2, ['default for first arg'], False)
+ >> def f(args):
+ >> print(args)
+
+ >> f('coucou les amis') # We have one mandatory and two optional
+ ['coucou', 'les', 'amis']
+ >> f('"coucou les amis" "PROUT PROUT"') # One mandator and only one optional,
+ # no default for the second
+ ['coucou les amis', 'PROUT PROUT']
+ >> f('') # Not enough args for mandatory number
+ None
+ >> f('"coucou les potes"') # One mandatory, and use the default value
+ # for the first optional
+ ['coucou les potes, 'default for first arg']
+ >> f('"un et demi" deux trois quatre cinq six') # We have three trailing arguments
+ ['un et demi', 'deux', 'trois quatre cinq six']
+
+ """
+ def first(func):
+ def second(self, args, *a, **kw):
+ default_args = defaults
+ args = common.shell_split(args)
+ if len(args) < mandatory:
+ return func(self, None, *a, **kw)
+ res, args = args[:mandatory], args[mandatory:]
+ opt_args = args[:optional]
+ if opt_args:
+ res += opt_args
+ args = args[len(opt_args):]
+ default_args = default_args[len(opt_args):]
+ res += default_args
+ if args and res and not ignore_trailing_arguments:
+ res[-1] += " " + " ".join(args)
+ return func(self, res, *a, **kw)
+ return second
+ return first
+
+command_args_parser = CommandArgParser()