Forgotten Typos
[kamaki] / kamaki / cli / commands / pithos_cli.py
index d65187b..b6b2e25 100644 (file)
 # interpreted as representing official policies, either expressed
 # or implied, of GRNET S.A.command
 
-from kamaki.cli import command, set_api_description
-from kamaki.clients.utils import filter_in
-from kamaki.cli.errors import CLIError, raiseCLIError
-from kamaki.cli.utils import format_size, print_dict, pretty_keys, print_list
-set_api_description('store', 'Pithos+ storage commands')
+from kamaki.cli import command
+from kamaki.cli.command_tree import CommandTree
+from kamaki.cli.errors import raiseCLIError, CLISyntaxError
+from kamaki.cli.utils import format_size, print_dict, pretty_keys
+from kamaki.cli.argument import FlagArgument, ValueArgument, IntArgument
+from kamaki.cli.argument import KeyValueArgument
+from kamaki.cli.argument import ProgressBarArgument
+from kamaki.cli.commands import _command_init
 from kamaki.clients.pithos import PithosClient, ClientError
-from colors import bold
-from sys import stdout, exit
-import signal
+from kamaki.cli.utils import bold
+from sys import stdout
 from time import localtime, strftime
+from datetime import datetime as dtm
 
-from progress.bar import IncrementalBar
 
+pithos_cmds = CommandTree('store', 'Pithos+ storage commands')
+_commands = [pithos_cmds]
 
-class ProgressBar(IncrementalBar):
-    #suffix = '%(percent)d%% - %(eta)ds'
-    suffix = '%(percent)d%%'
 
-class _pithos_init(object):
+# Argument functionality
+
+
+class DelimiterArgument(ValueArgument):
+    """
+    :value type: string
+    :value returns: given string or /
+    """
+
+    def __init__(self, caller_obj, help='', parsed_name=None, default=None):
+        super(DelimiterArgument, self).__init__(help, parsed_name, default)
+        self.caller_obj = caller_obj
+
+    @property
+    def value(self):
+        if self.caller_obj.get_argument('recursive'):
+            return '/'
+        return getattr(self, '_value', self.default)
+
+    @value.setter
+    def value(self, newvalue):
+        self._value = newvalue
+
+
+class SharingArgument(ValueArgument):
+    """Set sharing (read and/or write) groups
+
+    :value type: "read=term1,term2,... write=term1,term2,..."
+
+    :value returns: {'read':['term1', 'term2', ...],
+        'write':['term1', 'term2', ...]}
+    """
+
+    @property
+    def value(self):
+        return getattr(self, '_value', self.default)
+
+    @value.setter
+    def value(self, newvalue):
+        perms = {}
+        try:
+            permlist = newvalue.split(' ')
+        except AttributeError:
+            return
+        for p in permlist:
+            try:
+                (key, val) = p.split('=')
+            except ValueError as err:
+                raiseCLIError(err, 'Error in --sharing',
+                    details='Incorrect format',
+                    importance=1)
+            if key.lower() not in ('read', 'write'):
+                raiseCLIError(err, 'Error in --sharing',
+                    details='Invalid permission key %s' % key,
+                    importance=1)
+            val_list = val.split(',')
+            if not key in perms:
+                perms[key] = []
+            for item in val_list:
+                if item not in perms[key]:
+                    perms[key].append(item)
+        self._value = perms
+
+
+class RangeArgument(ValueArgument):
+    """
+    :value type: string of the form <start>-<end>
+        where <start> and <end> are integers
+
+    :value returns: the input string, after type checking <start> and <end>
+    """
+
+    @property
+    def value(self):
+        return getattr(self, '_value', self.default)
+
+    @value.setter
+    def value(self, newvalue):
+        if newvalue is None:
+            self._value = self.default
+            return
+        (start, end) = newvalue.split('-')
+        (start, end) = (int(start), int(end))
+        self._value = '%s-%s' % (start, end)
+
+
+class DateArgument(ValueArgument):
+    """
+    :value type: a string formated in an acceptable date format
+
+    :value returns: same date in first of DATE_FORMATS
+    """
+
+    DATE_FORMATS = ["%a %b %d %H:%M:%S %Y",
+        "%A, %d-%b-%y %H:%M:%S GMT",
+        "%a, %d %b %Y %H:%M:%S GMT"]
+
+    INPUT_FORMATS = DATE_FORMATS + ["%d-%m-%Y", "%H:%M:%S %d-%m-%Y"]
+
+    @property
+    def value(self):
+        return getattr(self, '_value', self.default)
+
+    @value.setter
+    def value(self, newvalue):
+        if newvalue is None:
+            return
+        self._value = self.format_date(newvalue)
+
+    def format_date(self, datestr):
+        for format in self.INPUT_FORMATS:
+            try:
+                t = dtm.strptime(datestr, format)
+            except ValueError:
+                continue
+            self._value = t.strftime(self.DATE_FORMATS[0])
+            return
+        raiseCLIError(None,
+            'Date Argument Error',
+            details='%s not a valid date. correct formats:\n\t%s'\
+            % (datestr, self.INPUT_FORMATS))
+
+
+# Command specs
+
+
+class _pithos_init(_command_init):
+    """Initialize a pithos+ kamaki client"""
+
     def main(self):
-        self.token = self.config.get('store', 'token') or self.config.get('global', 'token')
-        self.base_url = self.config.get('store', 'url') or self.config.get('global', 'url')
-        self.account = self.config.get('store', 'account') or self.config.get('global', 'account')
-        self.container = self.config.get('store', 'container') or self.config.get('global', 'container')
-        self.client = PithosClient(base_url=self.base_url, token=self.token, account=self.account,
+        self.token = self.config.get('store', 'token')\
+            or self.config.get('global', 'token')
+        self.base_url = self.config.get('store', 'url')\
+            or self.config.get('global', 'url')
+        self.account = self.config.get('store', 'account')\
+            or self.config.get('global', 'account')
+        self.container = self.config.get('store', 'container')\
+            or self.config.get('global', 'container')
+        self.client = PithosClient(base_url=self.base_url,
+            token=self.token,
+            account=self.account,
             container=self.container)
 
+
 class _store_account_command(_pithos_init):
     """Base class for account level storage commands"""
 
-    def update_parser(self, parser):
-        parser.add_argument('--account', dest='account', metavar='NAME',
-                          help="Specify an account to use")
-
-    def progress(self, message):
-        """Return a generator function to be used for progress tracking"""
-
-        MESSAGE_LENGTH = 25
+    def __init__(self, arguments={}):
+        super(_store_account_command, self).__init__(arguments)
+        self.arguments['account'] =\
+            ValueArgument('Specify the account', '--account')
 
-        def progress_gen(n):
-            msg = message.ljust(MESSAGE_LENGTH)
-            for i in ProgressBar(msg).iter(range(n)):
-                yield
-            yield
-
-        return progress_gen
+    def generator(self, message):
+        return None
 
     def main(self):
         super(_store_account_command, self).main()
-        if hasattr(self.args, 'account') and self.args.account is not None:
-            self.client.account = self.args.account
+        if self.arguments['account'].value is not None:
+            self.client.account = self.arguments['account'].value
+
 
 class _store_container_command(_store_account_command):
     """Base class for container level storage commands"""
 
-    def __init__(self):
+    def __init__(self, arguments={}):
+        super(_store_container_command, self).__init__(arguments)
+        self.arguments['container'] =\
+            ValueArgument('Specify the container name', '--container')
         self.container = None
         self.path = None
 
-    def update_parser(self, parser):
-        super(_store_container_command, self).update_parser(parser)
-        parser.add_argument('--container', dest='container', metavar='NAME', default=None,
-            help="Specify a container to use")
-
-    def extract_container_and_path(self, container_with_path, path_is_optional=True):
-        assert isinstance(container_with_path, str)
-        if ':' not in container_with_path:
-            if hasattr(self.args, 'container'):
-                self.container = getattr(self.args, 'container')
-            else:
-                self.container = self.client.container
-            if self.container is None:
-                self.container = container_with_path
-            else:
-                self.path = container_with_path
-            if not path_is_optional and self.path is None:
-                raise CLIError(message="Object path is missing", status=11)
-            return
-        cnp = container_with_path.split(':')
-        self.container = cnp[0]
+    def extract_container_and_path(self,
+        container_with_path,
+        path_is_optional=True):
         try:
-            self.path = cnp[1]
-        except IndexError:
-            if path_is_optional:
+            assert isinstance(container_with_path, str)
+        except AssertionError as err:
+            raiseCLIError(err)
+
+        cont, sep, path = container_with_path.partition(':')
+
+        if sep:
+            if not cont:
+                raiseCLIError(None, 'Container is missing\n', importance=1)
+            alt_cont = self.get_argument('container')
+            if alt_cont and cont != alt_cont:
+                raiseCLIError(None,
+                    'Conflict: 2 containers (%s, %s)' % (cont, alt_cont),
+                    importance=1)
+            self.container = cont
+            if not path:
+                raiseCLIError(None,
+                    'Path is missing for object in container %s' % cont,
+                    importance=1,
+                    details='Usage: <container>:<object path>')
+            self.path = path
+        else:
+            alt_cont = self.get_argument('container') or self.client.container
+            if alt_cont:
+                self.container = alt_cont
+                self.path = cont
+            elif path_is_optional:
+                self.container = cont
                 self.path = None
             else:
-                raise CLIError(message="Object path is missing", status=11)
+                self.container = cont
+                raiseCLIError(CLISyntaxError(
+                    'Syntax error: container and path are both required',
+                    importance=1,
+                    details='Usage: <container>:<object path>'))
 
     def main(self, container_with_path=None, path_is_optional=True):
         super(_store_container_command, self).main()
         if container_with_path is not None:
-            self.extract_container_and_path(container_with_path, path_is_optional)
+            self.extract_container_and_path(container_with_path,
+                path_is_optional)
             self.client.container = self.container
-        elif hasattr(self.args, 'container'):
-            self.client.container = getattr(self.args,'container')
+        elif self.get_argument('container') is not None:
+            self.client.container = self.get_argument('container')
         self.container = self.client.container
 
-"""
-@command()
-class store_test(_store_container_command):
-    ""Test stuff""
 
-    def main(self):
-        super(self.__class__, self).main('pithos')
-        r = self.client.container_get()
-        print(unicode(r.content)+' '+unicode(r.json))
-"""
-
-@command()
+@command(pithos_cmds)
 class store_list(_store_container_command):
     """List containers, object trees or objects in a directory
     """
 
-    def update_parser(self, parser):
-        super(self.__class__, self).update_parser(parser)
-        parser.add_argument('-l', action='store_true', dest='detail', default=False,
-            help='show detailed output')
-        parser.add_argument('-N', action='store', dest='show_size', default=1000,
-            help='print output in chunks of size N')
-        parser.add_argument('-n', action='store', dest='limit', default=None,
-            help='show limited output')
-        parser.add_argument('--marker', action='store', dest='marker', default=None,
-            help='show output greater then marker')
-        parser.add_argument('--prefix', action='store', dest='prefix', default=None,
-            help='show output starting with prefix')
-        parser.add_argument('--delimiter', action='store', dest='delimiter', default=None, 
-            help='show output up to the delimiter')
-        parser.add_argument('--path', action='store', dest='path', default=None, 
-            help='show output starting with prefix up to /')
-        parser.add_argument('--meta', action='store', dest='meta', default=None, 
-            help='show output having the specified meta keys (e.g. --meta "meta1 meta2 ..."')
-        parser.add_argument('--if-modified-since', action='store', dest='if_modified_since', 
-            default=None, help='show output if modified since then')
-        parser.add_argument('--if-unmodified-since', action='store', dest='if_unmodified_since',
-            default=None, help='show output if not modified since then')
-        parser.add_argument('--until', action='store', dest='until', default=None,
-            help='show metadata until that date')
-        dateformat = '%d/%m/%Y %H:%M:%S'
-        parser.add_argument('--format', action='store', dest='format', default=dateformat,
-            help='format to parse until date (default: d/m/Y H:M:S)')
-        parser.add_argument('--shared', action='store_true', dest='shared', default=False,
-            help='show only shared')
-        parser.add_argument('--public', action='store_true', dest='public', default=False,
-            help='show only public')
+    def __init__(self, arguments={}):
+        super(store_list, self).__init__(arguments)
+        self.arguments['detail'] = FlagArgument('show detailed output', '-l')
+        self.arguments['show_size'] =\
+            ValueArgument('print output in chunks of size N', '-N')
+        self.arguments['limit'] = IntArgument('show limited output', '-n')
+        self.arguments['marker'] =\
+            ValueArgument('show output greater that marker', '--marker')
+        self.arguments['prefix'] =\
+            ValueArgument('show output staritng with prefix', '--prefix')
+        self.arguments['delimiter'] =\
+            ValueArgument('show output up to delimiter', '--delimiter')
+        self.arguments['path'] =\
+            ValueArgument('show output starting with prefix up to /', '--path')
+        self.arguments['meta'] =\
+            ValueArgument('show output haviung the specified meta keys',
+            '--meta', default=[])
+        self.arguments['if_modified_since'] =\
+            ValueArgument('show output modified since then',
+                '--if-modified-since')
+        self.arguments['if_unmodified_since'] =\
+            ValueArgument('show output not modified since then',
+            '--if-unmodified-since')
+        self.arguments['until'] =\
+            DateArgument('show metadata until then', '--until')
+        self.arguments['format'] =\
+            ValueArgument('format to parse until data (default: d/m/Y H:M:S',
+            '--format')
+        self.arguments['shared'] = FlagArgument('show only shared', '--shared')
+        self.arguments['public'] = FlagArgument('show only public', '--public')
 
     def print_objects(self, object_list):
         import sys
         try:
-            limit = getattr(self.args, 'show_size')
+            limit = self.get_argument('show_size')
             limit = int(limit)
-        except AttributeError:
-            pass
+        except (AttributeError, TypeError):
+            limit = len(object_list) + 1
         #index = 0
-        for index,obj in enumerate(object_list):
-            if not obj.has_key('content_type'):
+        for index, obj in enumerate(object_list):
+            if 'content_type' not in obj:
                 continue
             pretty_obj = obj.copy()
             index += 1
-            empty_space = ' '*(len(str(len(object_list))) - len(str(index)))
+            empty_space = ' ' * (len(str(len(object_list))) - len(str(index)))
             if obj['content_type'] == 'application/directory':
                 isDir = True
                 size = 'D'
             else:
                 isDir = False
                 size = format_size(obj['bytes'])
-                pretty_obj['bytes'] = '%s (%s)'%(obj['bytes'],size)
+                pretty_obj['bytes'] = '%s (%s)' % (obj['bytes'], size)
             oname = bold(obj['name'])
-            if getattr(self.args, 'detail'):
-                print('%s%s. %s'%(empty_space, index, oname))
+            if self.get_argument('detail'):
+                print('%s%s. %s' % (empty_space, index, oname))
                 print_dict(pretty_keys(pretty_obj), exclude=('name'))
                 print
             else:
-                oname = '%s%s. %6s %s'%(empty_space, index, size, oname)
+                oname = '%s%s. %6s %s' % (empty_space, index, size, oname)
                 oname += '/' if isDir else ''
                 print(oname)
-            if limit <= index < len(object_list) and index%limit == 0:
+            if limit <= index < len(object_list) and index % limit == 0:
                 print('(press "enter" to continue)')
                 sys.stdin.read(1)
 
     def print_containers(self, container_list):
         import sys
         try:
-            limit = getattr(self.args, 'show_size')
+            limit = self.get_argument('show_size')
             limit = int(limit)
-        except AttributeError:
-            pass
-        for index,container in enumerate(container_list):
-            if container.has_key('bytes'):
-                size = format_size(container['bytes']) 
-            cname = '%s. %s'%(index+1, bold(container['name']))
-            if getattr(self.args, 'detail'):
+        except (AttributeError, TypeError):
+            limit = len(container_list) + 1
+        for index, container in enumerate(container_list):
+            if 'bytes' in container:
+                size = format_size(container['bytes'])
+            cname = '%s. %s' % (index + 1, bold(container['name']))
+            if self.get_argument('detail'):
                 print(cname)
                 pretty_c = container.copy()
-                if container.has_key('bytes'):
-                    pretty_c['bytes'] = '%s (%s)'%(container['bytes'], size)
+                if 'bytes' in container:
+                    pretty_c['bytes'] = '%s (%s)' % (container['bytes'], size)
                 print_dict(pretty_keys(pretty_c), exclude=('name'))
                 print
             else:
-                if container.has_key('count') and container.has_key('bytes'):
-                    print('%s (%s, %s objects)' % (cname, size, container['count']))
+                if 'count' in container and 'bytes' in container:
+                    print('%s (%s, %s objects)'\
+                    % (cname, size, container['count']))
                 else:
                     print(cname)
-            if limit <= index < len(container_list) and index%limit == 0:
+            if limit <= index < len(container_list) and index % limit == 0:
                 print('(press "enter" to continue)')
                 sys.stdin.read(1)
 
-    def getuntil(self, orelse=None):
-        if hasattr(self.args, 'until'):
-            import time
-            until = getattr(self.args, 'until')
-            if until is None:
-                return None
-            format = getattr(self.args, 'format')
-            #except TypeError:
-            try:
-                t = time.strptime(until, format)
-            except ValueError as err:
-                raise CLIError(message='in --until: '+unicode(err), importance=1)
-            return int(time.mktime(t))
-        return orelse
-   
-    def getmeta(self, orelse=[]):
-        if hasattr(self.args, 'meta'):
-            meta = getattr(self.args, 'meta')
-            if meta is None:
-                return []
-            return meta.split(' ')
-        return orelse
-
-    def getpath(self, orelse=None):
-        if self.path is not None:
-            return self.path
-        if hasattr(self.args, 'path'):
-            return getattr(self.args, 'path')
-        return orelse
-
     def main(self, container____path__=None):
         super(self.__class__, self).main(container____path__)
         try:
             if self.container is None:
-                r = self.client.account_get(limit=getattr(self.args, 'limit', None),
-                    marker=getattr(self.args, 'marker', None),
-                    if_modified_since=getattr(self.args, 'if_modified_since', None),
-                    if_unmodified_since=getattr(self.args, 'if_unmodified_since', None),
-                    until=self.getuntil(),
-                    show_only_shared=getattr(self.args, 'shared', False))
+                r = self.client.account_get(limit=self.get_argument('limit'),
+                    marker=self.get_argument('marker'),
+                    if_modified_since=self.get_argument('if_modified_since'),
+                    if_unmodified_since=self.get_argument(\
+                        'if_unmodified_since'),
+                    until=self.get_argument('until'),
+                    show_only_shared=self.get_argument('shared'))
                 self.print_containers(r.json)
             else:
-                r = self.client.container_get(limit=getattr(self.args, 'limit', None),
-                    marker=getattr(self.args, 'marker', None),
-                    prefix=getattr(self.args, 'prefix', None),
-                    delimiter=getattr(self.args, 'delimiter', None), path=self.getpath(orelse=None),
-                    if_modified_since=getattr(self.args, 'if_modified_since', None),
-                    if_unmodified_since=getattr(self.args, 'if_unmodified_since', None),
-                    until=self.getuntil(),
-                    meta=self.getmeta(),
-                    show_only_shared=getattr(self.args, 'shared', False))
+                r = self.client.container_get(limit=self.get_argument('limit'),
+                    marker=self.get_argument('marker'),
+                    prefix=self.get_argument('prefix'),
+                    delimiter=self.get_argument('delimiter'),
+                    path=self.get_argument('path'),
+                    if_modified_since=self.get_argument('if_modified_since'),
+                    if_unmodified_since=self.get_argument(\
+                        'if_unmodified_since'),
+                    until=self.get_argument('until'),
+                    meta=self.get_argument('meta'),
+                    show_only_shared=self.get_argument('shared'))
                 self.print_objects(r.json)
         except ClientError as err:
             raiseCLIError(err)
 
-@command()
+
+@command(pithos_cmds)
 class store_mkdir(_store_container_command):
     """Create a directory"""
 
     def main(self, container___directory):
-        super(self.__class__, self).main(container___directory, path_is_optional=False)
+        super(self.__class__,
+            self).main(container___directory, path_is_optional=False)
         try:
             self.client.create_directory(self.path)
         except ClientError as err:
             raiseCLIError(err)
 
-@command()
+
+@command(pithos_cmds)
 class store_create(_store_container_command):
     """Create a container or a directory object"""
 
-    def update_parser(self, parser):
-        super(self.__class__, self).update_parser(parser)
-        parser.add_argument('--versioning', action='store', dest='versioning', default=None,
-            help='set container versioning (auto/none)')
-        parser.add_argument('--quota', action='store', dest='quota', default=None,
-            help='set default container quota')
-        parser.add_argument('--meta', action='store', dest='meta', default=None,
-            help='set container metadata ("key1:val1 key2:val2 ...")')
-
-    def getmeta(self, orelse=None):
-        try:
-            meta = getattr(self.args,'meta')
-            metalist = meta.split(' ')
-        except AttributeError:
-            return orelse
-        metadict = {}
-        for metastr in metalist:
-            (key,val) = metastr.split(':')
-            metadict[key] = val
-        return metadict
+    def __init__(self, arguments={}):
+        super(self.__class__, self).__init__(arguments)
+        self.arguments['versioning'] = \
+            ValueArgument('set container versioning (auto/none)',
+            '--versioning')
+        self.arguments['quota'] =\
+            IntArgument('set default container quota', '--quota')
+        self.arguments['meta'] =\
+            KeyValueArgument(
+                'set container metadata (can be repeated)', '--meta')
+            #  MetaArgument('set container metadata', '--meta')
 
     def main(self, container____directory__):
         super(self.__class__, self).main(container____directory__)
         try:
             if self.path is None:
-                self.client.container_put(quota=getattr(self.args, 'quota'),
-                    versioning=getattr(self.args, 'versioning'), metadata=self.getmeta())
+                self.client.container_put(quota=self.get_argument('quota'),
+                    versioning=self.get_argument('versioning'),
+                    metadata=self.get_argument('meta'))
             else:
                 self.client.create_directory(self.path)
         except ClientError as err:
             raiseCLIError(err)
 
-@command()
+
+@command(pithos_cmds)
 class store_copy(_store_container_command):
     """Copy an object"""
 
-    def update_parser(self, parser):
-        super(store_copy, self).update_parser(parser)
-        parser.add_argument('--source-version', action='store', dest='source_version', default=None,
-            help='copy specific version')
-        parser.add_argument('--public', action='store_true', dest='public', default=False,
-            help='make object publicly accessible')
-        parser.add_argument('--content-type', action='store', dest='content_type', default=None,
-            help='change object\'s content type')
-        parser.add_argument('--delimiter', action='store', dest='delimiter', default=None,
-            help=u'mass copy objects with path staring with src_object + delimiter')
-        parser.add_argument('-r', action='store_true', dest='recursive', default=False,
-            help='mass copy with delimiter /')
-
-    def getdelimiter(self):
-        if getattr(self.args, 'recursive'):
-            return '/'
-        return getattr(self.args, 'delimiter')
+    def __init__(self, arguments={}):
+        super(self.__class__, self).__init__(arguments)
+        self.arguments['source_version'] = ValueArgument(\
+            'copy specific version', '--source-version')
+        self.arguments['public'] = ValueArgument(\
+            'make object publicly accessible', '--public')
+        self.arguments['content_type'] = ValueArgument(\
+            'change object\'s content type', '--content-type')
+        self.arguments['delimiter'] = DelimiterArgument(self,
+            parsed_name='--delimiter',
+            help=u'copy objects prefixed as src_object + delimiter')
+        self.arguments['recursive'] = FlagArgument(
+            'mass copy with delimiter /', ('-r', '--recursive'))
 
     def main(self, source_container___path, destination_container____path__):
-        super(self.__class__, self).main(source_container___path, path_is_optional=False)
+        super(self.__class__,
+            self).main(source_container___path, path_is_optional=False)
         try:
             dst = destination_container____path__.split(':')
             dst_cont = dst[0]
             dst_path = dst[1] if len(dst) > 1 else False
-            self.client.copy_object(src_container = self.container, src_object = self.path,
-                dst_container = dst_cont, dst_object = dst_path,
-                source_version=getattr(self.args, 'source_version'),
-                public=getattr(self.args, 'public'),
-                content_type=getattr(self.args,'content_type'), delimiter=self.getdelimiter())
+            self.client.copy_object(src_container=self.container,
+                src_object=self.path,
+                dst_container=dst_cont,
+                dst_object=dst_path,
+                source_version=self.get_argument('source_version'),
+                public=self.get_argument('public'),
+                content_type=self.get_argument('content_type'),
+                delimiter=self.get_argument('delimiter'))
         except ClientError as err:
             raiseCLIError(err)
 
-@command()
+
+@command(pithos_cmds)
 class store_move(_store_container_command):
     """Copy an object"""
 
-    def update_parser(self, parser):
-        super(store_move, self).update_parser(parser)
-        parser.add_argument('--source-version', action='store', dest='source_version', default=None,
-            help='copy specific version')
-        parser.add_argument('--public', action='store_true', dest='public', default=False,
-            help='make object publicly accessible')
-        parser.add_argument('--content-type', action='store', dest='content_type', default=None,
-            help='change object\'s content type')
-        parser.add_argument('--delimiter', action='store', dest='delimiter', default=None,
-            help=u'mass copy objects with path staring with src_object + delimiter')
-        parser.add_argument('-r', action='store_true', dest='recursive', default=False,
-            help='mass copy with delimiter /')
-
-    def getdelimiter(self):
-        if getattr(self.args, 'recursive'):
-            return '/'
-        return getattr(self.args, 'delimiter')
+    def __init__(self, arguments={}):
+        super(self.__class__, self).__init__(arguments)
+
+        self.arguments['source_version'] = ValueArgument(\
+            'copy specific version', '--source-version')
+        self.arguments['public'] = FlagArgument(\
+            'make object publicly accessible', '--public')
+        self.arguments['content_type'] = ValueArgument(\
+            'change object\'s content type', '--content-type')
+        self.arguments['delimiter'] = DelimiterArgument(self,
+            parsed_name='--delimiter',
+            help='move objects prefixed as src_object + delimiter')
+        self.arguments['recursive'] = FlagArgument(\
+            'copy with delimiter /', ('-r', '--recursive'))
 
     def main(self, source_container___path, destination_container____path__):
-        super(self.__class__, self).main(source_container___path, path_is_optional=False)
+        super(self.__class__,
+            self).main(source_container___path, path_is_optional=False)
         try:
             dst = destination_container____path__.split(':')
             dst_cont = dst[0]
             dst_path = dst[1] if len(dst) > 1 else False
-            self.client.move_object(src_container = self.container, src_object = self.path,
-                dst_container = dst_cont, dst_object = dst_path,
-                source_version=getattr(self.args, 'source_version'),
-                public=getattr(self.args, 'public'),
-                content_type=getattr(self.args,'content_type'), delimiter=self.getdelimiter())
+            self.client.move_object(src_container=self.container,
+                src_object=self.path,
+                dst_container=dst_cont,
+                dst_object=dst_path,
+                source_version=self.get_argument('source_version'),
+                public=self.get_argument('public'),
+                content_type=self.get_argument('content_type'),
+                delimiter=self.get_argument('delimiter'))
         except ClientError as err:
             raiseCLIError(err)
 
-@command()
+
+@command(pithos_cmds)
 class store_append(_store_container_command):
     """Append local file to (existing) remote object"""
 
+    def __init__(self, arguments={}):
+        super(self.__class__, self).__init__(arguments)
+        self.arguments['progress_bar'] = ProgressBarArgument(\
+            'do not show progress bar', '--no-progress-bar', False)
+
     def main(self, local_path, container___path):
-        super(self.__class__, self).main(container___path, path_is_optional=False)
+        super(self.__class__,
+            self).main(container___path, path_is_optional=False)
         try:
-            f = open(local_path, 'r')
-            upload_cb = self.progress('Appending blocks')
-            self.client.append_object(object=self.path, source_file = f, upload_cb = upload_cb)
+            f = open(local_path, 'rb')
+            progress_bar = self.arguments['progress_bar']
+            try:
+                upload_cb = progress_bar.get_generator('Appending blocks')
+            except Exception:
+                upload_cb = None
+            self.client.append_object(object=self.path,
+                source_file=f,
+                upload_cb=upload_cb)
         except ClientError as err:
+            progress_bar.finish()
             raiseCLIError(err)
+        finally:
+            progress_bar.finish()
+
 
-@command()
+@command(pithos_cmds)
 class store_truncate(_store_container_command):
     """Truncate remote file up to a size"""
 
-    
     def main(self, container___path, size=0):
-        super(self.__class__, self).main(container___path, path_is_optional=False)
+        super(self.__class__,
+            self).main(container___path, path_is_optional=False)
         try:
             self.client.truncate_object(self.path, size)
         except ClientError as err:
             raiseCLIError(err)
 
-@command()
+
+@command(pithos_cmds)
 class store_overwrite(_store_container_command):
     """Overwrite part (from start to end) of a remote file"""
 
+    def __init__(self, arguments={}):
+        super(self.__class__, self).__init__(arguments)
+        self.arguments['progress_bar'] = ProgressBarArgument(\
+            'do not show progress bar', '--no-progress-bar', False)
+
     def main(self, local_path, container___path, start, end):
-        super(self.__class__, self).main(container___path, path_is_optional=False)
+        super(self.__class__,
+            self).main(container___path, path_is_optional=False)
         try:
-            f = open(local_path, 'r')
-            upload_cb = self.progress('Overwritting blocks')
-            self.client.overwrite_object(object=self.path, start=start, end=end,
-                source_file=f, upload_cb = upload_cb)
+            f = open(local_path, 'rb')
+            progress_bar = self.arguments['progress_bar']
+            try:
+                upload_cb = progress_bar.get_generator('Overwritting blocks')
+            except Exception:
+                upload_cb = None
+            self.client.overwrite_object(object=self.path,
+                start=start,
+                end=end,
+                source_file=f,
+                upload_cb=upload_cb)
         except ClientError as err:
+            progress_bar.finish()
             raiseCLIError(err)
+        finally:
+            progress_bar.finish()
+
 
-@command()
+@command(pithos_cmds)
 class store_manifest(_store_container_command):
     """Create a remote file with uploaded parts by manifestation"""
 
-    def update_parser(self, parser):
-        super(self.__class__, self).update_parser(parser)
-        parser.add_argument('--etag', action='store', dest='etag', default=None,
-            help='check written data')
-        parser.add_argument('--content-encoding', action='store', dest='content_encoding',
-            default=None, help='provide the object MIME content type')
-        parser.add_argument('--content-disposition', action='store', dest='content_disposition',
-            default=None, help='provide the presentation style of the object')
-        parser.add_argument('--content-type', action='store', dest='content_type', default=None,
-            help='create object with specific content type')
-        parser.add_argument('--sharing', action='store', dest='sharing', default=None,
-            help='define sharing object policy ( "read=user1,grp1,user2,... write=user1,grp2,...')
-        parser.add_argument('--public', action='store_true', dest='public', default=False,
-            help='make object publicly accessible')
-
-    def getsharing(self, orelse={}):
-        permstr = getattr(self.args, 'sharing')
-        if permstr is None:
-            return orelse
-        perms = {}
-        for p in permstr.split(' '):
-            (key, val) = p.split('=')
-            if key.lower() not in ('read', 'write'):
-                raise CLIError(message='in --sharing: Invalid permition key', importance=1)
-            val_list = val.split(',')
-            if not perms.has_key(key):
-                perms[key]=[]
-            for item in val_list:
-                if item not in perms[key]:
-                    perms[key].append(item)
-        return perms
-        
+    def __init__(self, arguments={}):
+        super(self.__class__, self).__init__(arguments)
+        self.arguments['etag'] = ValueArgument('check written data', '--etag')
+        self.arguments['content_encoding'] = ValueArgument(\
+            'provide the object MIME content type', '--content-encoding')
+        self.arguments['content_disposition'] = ValueArgument(\
+            'provide the presentation style of the object',
+            '--content-disposition')
+        self.arguments['content_type'] = ValueArgument(\
+            'create object with specific content type', '--content-type')
+        self.arguments['sharing'] = SharingArgument(parsed_name='--sharing',
+            help='define object sharing policy ' +\
+            '( "read=user1,grp1,user2,... write=user1,grp2,..." )')
+        self.arguments['public'] = FlagArgument(\
+            'make object publicly accessible', '--public')
+
     def main(self, container___path):
-        super(self.__class__, self).main(container___path, path_is_optional=False)
+        super(self.__class__,
+            self).main(container___path, path_is_optional=False)
         try:
             self.client.create_object_by_manifestation(self.path,
-                content_encoding=getattr(self.args, 'content_encoding'),
-                content_disposition=getattr(self.args, 'content_disposition'),
-                content_type=getattr(self.args, 'content_type'), sharing=self.getsharing(),
-                public=getattr(self.args, 'public'))
+                content_encoding=self.get_argument('content_encoding'),
+                content_disposition=self.get_argument('content_disposition'),
+                content_type=self.get_argument('content_type'),
+                sharing=self.get_argument('sharing'),
+                public=self.get_argument('public'))
         except ClientError as err:
             raiseCLIError(err)
 
-@command()
+
+@command(pithos_cmds)
 class store_upload(_store_container_command):
     """Upload a file"""
 
-    def update_parser(self, parser):
-        super(self.__class__, self).update_parser(parser)
-        parser.add_argument('--use_hashes', action='store_true', dest='use_hashes', default=False,
-            help='provide hashmap file instead of data')
-        parser.add_argument('--unchunked', action='store_true', dest='unchunked', default=False,
-            help='avoid chunked transfer mode')
-        parser.add_argument('--etag', action='store', dest='etag', default=None,
-            help='check written data')
-        parser.add_argument('--content-encoding', action='store', dest='content_encoding',
-            default=None, help='provide the object MIME content type')
-        parser.add_argument('--content-disposition', action='store', dest='content_disposition',
-            default=None, help='provide the presentation style of the object')
-        parser.add_argument('--content-type', action='store', dest='content_type', default=None,
-            help='create object with specific content type')
-        parser.add_argument('--sharing', action='store', dest='sharing', default=None,
-            help='define sharing object policy ( "read=user1,grp1,user2,... write=user1,grp2,...')
-        parser.add_argument('--public', action='store_true', dest='public', default=False,
-            help='make object publicly accessible')
-        parser.add_argument('--with-pool-size', action='store', dest='poolsize', default=None,
-            help='Set the greenlet pool size (advanced)')
-
-    def getsharing(self, orelse={}):
-        permstr = getattr(self.args, 'sharing')
-        if permstr is None:
-            return orelse
-        perms = {}
-        for p in permstr.split(' '):
-            (key, val) = p.split('=')
-            if key.lower() not in ('read', 'write'):
-                raise CLIError(message='in --sharing: Invalid permition key', importance=1)
-            val_list = val.split(',')
-            if not perms.has_key(key):
-                perms[key]=[]
-            for item in val_list:
-                if item not in perms[key]:
-                    perms[key].append(item)
-        return perms
+    def __init__(self, arguments={}):
+        super(self.__class__, self).__init__(arguments)
+        self.arguments['use_hashes'] = FlagArgument(\
+            'provide hashmap file instead of data', '--use-hashes')
+        self.arguments['etag'] = ValueArgument('check written data', '--etag')
+        self.arguments['unchunked'] = FlagArgument(\
+            'avoid chunked transfer mode', '--unchunked')
+        self.arguments['content_encoding'] = ValueArgument(\
+            'provide the object MIME content type', '--content-encoding')
+        self.arguments['content_disposition'] = ValueArgument(\
+            'provide the presentation style of the object',
+            '--content-disposition')
+        self.arguments['content_type'] = ValueArgument(\
+            'create object with specific content type', '--content-type')
+        self.arguments['sharing'] = SharingArgument(parsed_name='--sharing',
+            help='define sharing object policy ' +\
+            '( "read=user1,grp1,user2,... write=user1,grp2,...')
+        self.arguments['public'] = FlagArgument(\
+            'make object publicly accessible', '--public')
+        self.arguments['poolsize'] = IntArgument(\
+            'set pool size', '--with-pool-size')
+        self.arguments['progress_bar'] = ProgressBarArgument(\
+            'do not show progress bar', '--no-progress-bar', False)
 
     def main(self, local_path, container____path__):
         super(self.__class__, self).main(container____path__)
         remote_path = local_path if self.path is None else self.path
-        poolsize = getattr(self.args, 'poolsize')
+        poolsize = self.get_argument('poolsize')
         if poolsize is not None:
-            self.POOL_SIZE = int(poolsize)
+            self.client.POOL_SIZE = int(poolsize)
+        params = dict(content_encoding=self.get_argument('content_encoding'),
+            content_type=self.get_argument('content_type'),
+            content_disposition=self.get_argument('content_disposition'),
+            sharing=self.get_argument('sharing'),
+            public=self.get_argument('public'))
         try:
-            with open(local_path) as f:
-                if getattr(self.args, 'unchunked'):
+            progress_bar = self.arguments['progress_bar']
+            hash_bar = progress_bar.clone()
+            with open(local_path, 'rb') as f:
+                if self.get_argument('unchunked'):
                     self.client.upload_object_unchunked(remote_path, f,
-                    etag=getattr(self.args, 'etag'), withHashFile=getattr(self.args, 'use_hashes'),
-                    content_encoding=getattr(self.args, 'content_encoding'),
-                    content_disposition=getattr(self.args, 'content_disposition'),
-                    content_type=getattr(self.args, 'content_type'), sharing=self.getsharing(),
-                    public=getattr(self.args, 'public'))
+                    etag=self.get_argument('etag'),
+                    withHashFile=self.get_argument('use_hashes'),
+                    **params)
                 else:
-                    hash_cb = self.progress('Calculating block hashes')
-                    upload_cb = self.progress('Uploading blocks')
-                    self.client.upload_object(remote_path, f, hash_cb=hash_cb, upload_cb=upload_cb,
-                    content_encoding=getattr(self.args, 'content_encoding'),
-                    content_disposition=getattr(self.args, 'content_disposition'),
-                    content_type=getattr(self.args, 'content_type'), sharing=self.getsharing(),
-                    public=getattr(self.args, 'public'))
+                    hash_cb = hash_bar.get_generator(\
+                        'Calculating block hashes')
+                    upload_cb = progress_bar.get_generator('Uploading')
+                    self.client.upload_object(remote_path, f,
+                        hash_cb=hash_cb,
+                        upload_cb=upload_cb,
+                        **params)
+                    progress_bar.finish()
+                    hash_bar.finish()
         except ClientError as err:
-            raiseCLIError(err)
+            progress_bar.finish()
+            hash_bar.finish()
+            raiseCLIError(err, '"%s" not accessible' % container____path__)
+        except IOError as err:
+            progress_bar.finish()
+            hash_bar.finish()
+            raiseCLIError(err, 'Failed to read form file %s' % local_path, 2)
         print 'Upload completed'
 
-@command()
+
+@command(pithos_cmds)
+class store_cat(_store_container_command):
+    """Print a file to console"""
+
+    def __init__(self, arguments={}):
+        super(self.__class__, self).__init__(arguments)
+        self.arguments['range'] =\
+            RangeArgument('show range of data', '--range')
+        self.arguments['if_match'] =\
+            ValueArgument('show output if ETags match', '--if-match')
+        self.arguments['if_none_match'] =\
+            ValueArgument('show output if ETags match', '--if-none-match')
+        self.arguments['if_modified_since'] =\
+            DateArgument('show output modified since then',
+            '--if-modified-since')
+        self.arguments['if_unmodified_since'] =\
+            DateArgument('show output unmodified since then',
+            '--if-unmodified-since')
+        self.arguments['object_version'] =\
+            ValueArgument('get the specific version', '--object-version')
+
+    def main(self, container___path):
+        super(self.__class__,
+            self).main(container___path, path_is_optional=False)
+        try:
+            self.client.download_object(self.path, stdout,
+            range=self.get_argument('range'),
+            version=self.get_argument('object_version'),
+            if_match=self.get_argument('if_match'),
+            if_none_match=self.get_argument('if_none_match'),
+            if_modified_since=self.get_argument('if_modified_since'),
+            if_unmodified_since=self.get_argument('if_unmodified_since'))
+        except ClientError as err:
+            raiseCLIError(err)
+
+
+@command(pithos_cmds)
 class store_download(_store_container_command):
     """Download a file"""
 
-    def update_parser(self, parser):
-        super(self.__class__, self).update_parser(parser)
-        parser.add_argument('--no-progress-bar', action='store_true', dest='no_progress_bar',
-            default=False, help='Dont display progress bars')
-        parser.add_argument('--resume', action='store_true', dest='resume', default=False,
+    def __init__(self, arguments={}):
+        super(self.__class__, self).__init__(arguments)
+        self.arguments['resume'] = FlagArgument(parsed_name='--resume',
             help='Resume a previous download instead of overwritting it')
-        parser.add_argument('--range', action='store', dest='range', default=None,
-            help='show range of data')
-        parser.add_argument('--if-match', action='store', dest='if_match', default=None,
-            help='show output if ETags match')
-        parser.add_argument('--if-none-match', action='store', dest='if_none_match', default=None,
-            help='show output if ETags don\'t match')
-        parser.add_argument('--if-modified-since', action='store', dest='if_modified_since',
-            default=None, help='show output if modified since then')
-        parser.add_argument('--if-unmodified-since', action='store', dest='if_unmodified_since',
-            default=None, help='show output if not modified since then')
-        parser.add_argument('--object-version', action='store', dest='object_version', default=None,
-            help='get the specific version')
-        parser.add_argument('--with-pool-size', action='store', dest='poolsize', default=None,
-            help='Set the greenlet pool size (advanced)')
-
-    def main(self, container___path, local_path=None):
-        super(self.__class__, self).main(container___path, path_is_optional=False)
-
-        #setup output stream
-        parallel = False
+        self.arguments['range'] = RangeArgument(\
+            'show range of data', '--range')
+        self.arguments['if_match'] = ValueArgument(\
+            'show output if ETags match', '--if-match')
+        self.arguments['if_none_match'] = ValueArgument(\
+            'show output if ETags match', '--if-none-match')
+        self.arguments['if_modified_since'] = DateArgument(\
+            'show output modified since then', '--if-modified-since')
+        self.arguments['if_unmodified_since'] = DateArgument(\
+            'show output unmodified since then', '--if-unmodified-since')
+        self.arguments['object_version'] = ValueArgument(\
+            'get the specific version', '--object-version')
+        self.arguments['poolsize'] = IntArgument(\
+            'set pool size', '--with-pool-size')
+        self.arguments['progress_bar'] = ProgressBarArgument(\
+            'do not show progress bar', '--no-progress-bar', False)
+
+    def main(self, container___path, local_path):
+        super(self.__class__,
+            self).main(container___path, path_is_optional=False)
+
+        # setup output stream
         if local_path is None:
             out = stdout
         else:
             try:
-                if hasattr(self.args, 'resume') and getattr(self.args, 'resume'):
-                    out=open(local_path, 'rwb+')
+                if self.get_argument('resume'):
+                    out = open(local_path, 'rwb+')
                 else:
-                    out=open(local_path, 'wb+')
+                    out = open(local_path, 'wb+')
             except IOError as err:
-                raise CLIError(message='Cannot write to file %s - %s'%(local_path,unicode(err)),
-                    importance=1)
-        download_cb = None if getattr(self.args, 'no_progress_bar') \
-        else self.progress('Downloading')
-        poolsize = getattr(self.args, 'poolsize')
+                raiseCLIError(err, 'Cannot write to file %s' % local_path, 1)
+        poolsize = self.get_argument('poolsize')
         if poolsize is not None:
-            self.POOL_SIZE = int(poolsize)
+            self.client.POOL_SIZE = int(poolsize)
 
         try:
-            self.client.download_object(self.path, out, download_cb,
-                range=getattr(self.args, 'range'), version=getattr(self.args,'object_version'),
-                if_match=getattr(self.args, 'if_match'), resume=getattr(self.args, 'resume'),
-                if_none_match=getattr(self.args, 'if_none_match'),
-                if_modified_since=getattr(self.args, 'if_modified_since'),
-                if_unmodified_since=getattr(self.args, 'if_unmodified_since'))
+            progress_bar = self.arguments['progress_bar']
+            download_cb = progress_bar.get_generator('Downloading')
+            self.client.download_object(self.path, out,
+                download_cb=download_cb,
+                range=self.get_argument('range'),
+                version=self.get_argument('object_version'),
+                if_match=self.get_argument('if_match'),
+                resume=self.get_argument('resume'),
+                if_none_match=self.get_argument('if_none_match'),
+                if_modified_since=self.get_argument('if_modified_since'),
+                if_unmodified_since=self.get_argument('if_unmodified_since'))
+            progress_bar.finish()
         except ClientError as err:
+            progress_bar.finish()
             raiseCLIError(err)
         except KeyboardInterrupt:
+            from threading import enumerate as activethreads
+            stdout.write('\nFinishing active threads ')
+            for thread in activethreads():
+                stdout.flush()
+                try:
+                    thread.join()
+                    stdout.write('.')
+                except RuntimeError:
+                    continue
+            progress_bar.finish()
             print('\ndownload canceled by user')
             if local_path is not None:
                 print('to resume, re-run with --resume')
+        except Exception as e:
+            progress_bar.finish()
+            raiseCLIError(e)
         print
 
-@command()
+
+@command(pithos_cmds)
 class store_hashmap(_store_container_command):
     """Get the hashmap of an object"""
 
-    def update_parser(self, parser):
-        super(self.__class__, self).update_parser(parser)
-        parser.add_argument('--if-match', action='store', dest='if_match', default=None,
-            help='show output if ETags match')
-        parser.add_argument('--if-none-match', action='store', dest='if_none_match', default=None,
-            help='show output if ETags dont match')
-        parser.add_argument('--if-modified-since', action='store', dest='if_modified_since',
-            default=None, help='show output if modified since then')
-        parser.add_argument('--if-unmodified-since', action='store', dest='if_unmodified_since',
-            default=None, help='show output if not modified since then')
-        parser.add_argument('--object-version', action='store', dest='object_version', default=None,
-            help='get the specific version')
+    def __init__(self, arguments={}):
+        super(self.__class__, self).__init__(arguments)
+        self.arguments['if_match'] =\
+            ValueArgument('show output if ETags match', '--if-match')
+        self.arguments['if_none_match'] =\
+            ValueArgument('show output if ETags match', '--if-none-match')
+        self.arguments['if_modified_since'] =\
+            DateArgument('show output modified since then',
+            '--if-modified-since')
+        self.arguments['if_unmodified_since'] =\
+            DateArgument('show output unmodified since then',
+            '--if-unmodified-since')
+        self.arguments['object_version'] =\
+            ValueArgument('get the specific version', '--object-version')
 
     def main(self, container___path):
-        super(self.__class__, self).main(container___path, path_is_optional=False)
+        super(self.__class__,
+            self).main(container___path, path_is_optional=False)
         try:
             data = self.client.get_object_hashmap(self.path,
-                version=getattr(self.args, 'object_version'),
-                if_match=getattr(self.args, 'if_match'),
-                if_none_match=getattr(self.args, 'if_none_match'),
-                if_modified_since=getattr(self.args, 'if_modified_since'),
-                if_unmodified_since=getattr(self.args, 'if_unmodified_since'))
+                version=self.get_argument('object_version'),
+                if_match=self.get_argument('if_match'),
+                if_none_match=self.get_argument('if_none_match'),
+                if_modified_since=self.get_argument('if_modified_since'),
+                if_unmodified_since=self.get_argument('if_unmodified_since'))
         except ClientError as err:
             raiseCLIError(err)
         print_dict(data)
 
-@command()
+
+@command(pithos_cmds)
 class store_delete(_store_container_command):
     """Delete a container [or an object]"""
 
-    def update_parser(self, parser):
-        super(self.__class__, self).update_parser(parser)
-        parser.add_argument('--until', action='store', dest='until', default=None,
-            help='remove history until that date')
-        parser.add_argument('--format', action='store', dest='format', default='%d/%m/%Y %H:%M:%S',
-            help='format to parse until date (default: d/m/Y H:M:S)')
-        parser.add_argument('--delimiter', action='store', dest='delimiter',
-            default=None, 
-            help='mass delete objects with path staring with <object><delimiter>')
-        parser.add_argument('-r', action='store_true', dest='recursive', default=False,
-            help='empty dir or container and delete (if dir)')
-    
-    def getuntil(self, orelse=None):
-        if hasattr(self.args, 'until'):
-            import time
-            until = getattr(self.args, 'until')
-            if until is None:
-                return None
-            format = getattr(self.args, 'format')
-            try:
-                t = time.strptime(until, format)
-            except ValueError as err:
-                raise CLIError(message='in --until: '+unicode(err), importance=1)
-            return int(time.mktime(t))
-        return orelse
-
-    def getdelimiter(self, orelse=None):
-        try:
-            dlm = getattr(self.args, 'delimiter')
-            if dlm is None:
-                return '/' if getattr(self.args, 'recursive') else orelse
-        except AttributeError:
-            return orelse
-        return dlm
+    def __init__(self, arguments={}):
+        super(self.__class__, self).__init__(arguments)
+        self.arguments['until'] = DateArgument(\
+            'remove history until that date', '--until')
+        self.arguments['recursive'] = FlagArgument(\
+            'empty dir or container and delete (if dir)',
+            ('-r', '--recursive'))
+        self.arguments['delimiter'] = DelimiterArgument(self,
+            parsed_name='--delimiter',
+            help='delete objects prefixed with <object><delimiter>')
 
     def main(self, container____path__):
         super(self.__class__, self).main(container____path__)
         try:
             if self.path is None:
-                self.client.del_container(until=self.getuntil(), delimiter=self.getdelimiter())
+                self.client.del_container(until=self.get_argument('until'),
+                    delimiter=self.get_argument('delimiter'))
             else:
-                #self.client.delete_object(self.path)
-                self.client.del_object(self.path, until=self.getuntil(),
-                    delimiter=self.getdelimiter())
+                # self.client.delete_object(self.path)
+                self.client.del_object(self.path,
+                    until=self.get_argument('until'),
+                    delimiter=self.get_argument('delimiter'))
         except ClientError as err:
             raiseCLIError(err)
 
-@command()
+
+@command(pithos_cmds)
 class store_purge(_store_container_command):
     """Purge a container"""
-    
+
     def main(self, container):
         super(self.__class__, self).main(container)
         try:
@@ -720,48 +883,56 @@ class store_purge(_store_container_command):
         except ClientError as err:
             raiseCLIError(err)
 
-@command()
+
+@command(pithos_cmds)
 class store_publish(_store_container_command):
     """Publish an object"""
 
     def main(self, container___path):
-        super(self.__class__, self).main(container___path, path_is_optional=False)
+        super(self.__class__,
+            self).main(container___path, path_is_optional=False)
         try:
-            self.client.publish_object(self.path)
+            url = self.client.publish_object(self.path)
         except ClientError as err:
             raiseCLIError(err)
+        print(url)
 
-@command()
+
+@command(pithos_cmds)
 class store_unpublish(_store_container_command):
     """Unpublish an object"""
 
     def main(self, container___path):
-        super(self.__class__, self).main(container___path, path_is_optional=False)
+        super(self.__class__,
+            self).main(container___path, path_is_optional=False)
         try:
             self.client.unpublish_object(self.path)
         except ClientError as err:
             raiseCLIError(err)
 
-@command()
-class store_permitions(_store_container_command):
-    """Get object read/write permitions"""
+
+@command(pithos_cmds)
+class store_permissions(_store_container_command):
+    """Get object read / write permissions """
 
     def main(self, container___path):
-        super(self.__class__, self).main(container___path, path_is_optional=False)
+        super(self.__class__,
+            self).main(container___path, path_is_optional=False)
         try:
             reply = self.client.get_object_sharing(self.path)
             print_dict(reply)
         except ClientError as err:
             raiseCLIError(err)
 
-@command()
-class store_setpermitions(_store_container_command):
-    """Set sharing permitions"""
 
-    def format_permition_dict(self,permitions):
+@command(pithos_cmds)
+class store_setpermissions(_store_container_command):
+    """Set sharing permissions """
+
+    def format_permition_dict(self, permissions):
         read = False
         write = False
-        for perms in permitions:
+        for perms in permissions:
             splstr = perms.split('=')
             if 'read' == splstr[0]:
                 read = [user_or_group.strip() \
@@ -773,35 +944,44 @@ class store_setpermitions(_store_container_command):
                 read = False
                 write = False
         if not read and not write:
-            raise CLIError(message='Usage:\tread=<groups,users> write=<groups,users>',
-                importance=0)
-        return (read,write)
-
-    def main(self, container___path, *permitions):
-        super(self.__class__, self).main(container___path, path_is_optional=False)
-        (read, write) = self.format_permition_dict(permitions)
+            raiseCLIError(None,
+            'Usage:\tread=<groups,users> write=<groups,users>')
+        return (read, write)
+
+    def main(self, container___path, *permissions):
+        super(self.__class__,
+            self).main(container___path, path_is_optional=False)
+        (read, write) = self.format_permition_dict(permissions)
         try:
             self.client.set_object_sharing(self.path,
                 read_permition=read, write_permition=write)
         except ClientError as err:
             raiseCLIError(err)
 
-@command()
-class store_delpermitions(_store_container_command):
-    """Delete all sharing permitions"""
+
+@command(pithos_cmds)
+class store_delpermissions(_store_container_command):
+    """Delete all sharing permissions"""
 
     def main(self, container___path):
-        super(self.__class__, self).main(container___path, path_is_optional=False)
+        super(self.__class__,
+            self).main(container___path, path_is_optional=False)
         try:
             self.client.del_object_sharing(self.path)
         except ClientError as err:
             raiseCLIError(err)
 
-@command()
+
+@command(pithos_cmds)
 class store_info(_store_container_command):
     """Get information for account [, container [or object]]"""
 
-    
+    def __init__(self, arguments={}):
+        super(self.__class__, self).__init__(arguments)
+        self.arguments['object_version'] =\
+            ValueArgument(parsed_name='--object-version',
+            help='show specific version \ (applies only for objects)')
+
     def main(self, container____path__=None):
         super(self.__class__, self).main(container____path__)
         try:
@@ -810,76 +990,66 @@ class store_info(_store_container_command):
             elif self.path is None:
                 reply = self.client.get_container_info(self.container)
             else:
-                reply = self.client.get_object_info(self.path)
+                reply = self.client.get_object_info(self.path,
+                    version=self.get_argument('object_version'))
         except ClientError as err:
             raiseCLIError(err)
         print_dict(reply)
 
-@command()
+
+@command(pithos_cmds)
 class store_meta(_store_container_command):
     """Get custom meta-content for account [, container [or object]]"""
 
-    def update_parser(self, parser):
-        super(self.__class__, self).update_parser(parser)
-        parser.add_argument('-l', action='store_true', dest='detail', default=False,
-            help='show detailed output')
-        parser.add_argument('--until', action='store', dest='until', default=None,
-            help='show metadata until that date')
-        dateformat='%d/%m/%Y %H:%M:%S'
-        parser.add_argument('--format', action='store', dest='format', default=dateformat,
-            help='format to parse until date (default: "d/m/Y H:M:S")')
-        parser.add_argument('--object_version', action='store', dest='object_version', default=None,
+    def __init__(self, arguments={}):
+        super(self.__class__, self).__init__(arguments)
+        self.arguments['detail'] =\
+            FlagArgument('show detailed output', '-l')
+        self.arguments['until'] =\
+            DateArgument('show metadata until then', '--until')
+        self.arguments['object_version'] =\
+            ValueArgument(parsed_name='--object-version',
             help='show specific version \ (applies only for objects)')
 
-    def getuntil(self, orelse=None):
-        if hasattr(self.args, 'until'):
-            import time
-            until = getattr(self.args, 'until')
-            if until is None:
-                return None
-            format = getattr(self.args, 'format')
-            #except TypeError:
-            try:
-                t = time.strptime(until, format)
-            except ValueError as err:
-                raise CLIError(message='in --until: '+unicode(err), importance=1)
-            return int(time.mktime(t))
-        return orelse
-
-    def main(self, container____path__ = None):
+    def main(self, container____path__=None):
         super(self.__class__, self).main(container____path__)
 
-        detail = getattr(self.args, 'detail')
+        detail = self.get_argument('detail')
         try:
+            until = self.get_argument('until')
             if self.container is None:
                 print(bold(self.client.account))
                 if detail:
-                    reply = self.client.get_account_info(until=self.getuntil())
+                    reply = self.client.get_account_info(until=until)
                 else:
-                    reply = self.client.get_account_meta(until=self.getuntil())
+                    reply = self.client.get_account_meta(until=until)
                     reply = pretty_keys(reply, '-')
             elif self.path is None:
-                print(bold(self.client.account+': '+self.container))
+                print(bold('%s: %s' % (self.client.account, self.container)))
                 if detail:
-                    reply = self.client.get_container_info(until = self.getuntil())
+                    reply = self.client.get_container_info(until=until)
                 else:
-                    cmeta = self.client.get_container_meta(until=self.getuntil())
-                    ometa = self.client.get_container_object_meta(until=self.getuntil())
-                    reply = {'container-meta':pretty_keys(cmeta, '-'),
-                        'object-meta':pretty_keys(ometa, '-')}
+                    cmeta = self.client.get_container_meta(until=until)
+                    ometa = self.client.get_container_object_meta(until=until)
+                    reply = {'container-meta': pretty_keys(cmeta, '-'),
+                        'object-meta': pretty_keys(ometa, '-')}
             else:
-                print(bold(self.client.account+': '+self.container+':'+self.path))
-                version=getattr(self.args, 'object_version')
+                print(bold('%s: %s:%s'\
+                    % (self.client.account, self.container, self.path)))
+                version = self.get_argument('object_version')
                 if detail:
-                    reply = self.client.get_object_info(self.path, version = version)
+                    reply = self.client.get_object_info(self.path,
+                        version=version)
                 else:
-                    reply = self.client.get_object_meta(self.path, version=version)
+                    reply = self.client.get_object_meta(self.path,
+                        version=version)
                     reply = pretty_keys(pretty_keys(reply, '-'))
         except ClientError as err:
             raiseCLIError(err)
         print_dict(reply)
 
-@command()
+
+@command(pithos_cmds)
 class store_setmeta(_store_container_command):
     """Set a new metadatum for account [, container [or object]]"""
 
@@ -887,20 +1057,20 @@ class store_setmeta(_store_container_command):
         super(self.__class__, self).main(container____path__)
         try:
             metakey, metavalue = metakey___metaval.split(':')
-        except ValueError:
-            raise CLIError(message='Meta variables should be formated as metakey:metavalue',
-                importance=1)
+        except ValueError as err:
+            raiseCLIError(err, 'Usage:  metakey:metavalue', importance=1)
         try:
             if self.container is None:
-                self.client.set_account_meta({metakey:metavalue})
+                self.client.set_account_meta({metakey: metavalue})
             elif self.path is None:
-                self.client.set_container_meta({metakey:metavalue})
+                self.client.set_container_meta({metakey: metavalue})
             else:
-                self.client.set_object_meta(self.path, {metakey:metavalue})
+                self.client.set_object_meta(self.path, {metakey: metavalue})
         except ClientError as err:
             raiseCLIError(err)
 
-@command()
+
+@command(pithos_cmds)
 class store_delmeta(_store_container_command):
     """Delete an existing metadatum of account [, container [or object]]"""
 
@@ -912,15 +1082,16 @@ class store_delmeta(_store_container_command):
             elif self.path is None:
                 self.client.del_container_meta(metakey)
             else:
-                self.client.del_object_meta(metakey, self.path)
+                self.client.del_object_meta(self.path, metakey)
         except ClientError as err:
             raiseCLIError(err)
 
-@command()
+
+@command(pithos_cmds)
 class store_quota(_store_account_command):
     """Get  quota for account [or container]"""
 
-    def main(self, container = None):
+    def main(self, container=None):
         super(self.__class__, self).main()
         try:
             if container is None:
@@ -931,11 +1102,12 @@ class store_quota(_store_account_command):
             raiseCLIError(err)
         print_dict(reply)
 
-@command()
+
+@command(pithos_cmds)
 class store_setquota(_store_account_command):
     """Set new quota (in KB) for account [or container]"""
 
-    def main(self, quota, container = None):
+    def main(self, quota, container=None):
         super(self.__class__, self).main()
         try:
             if container is None:
@@ -946,11 +1118,12 @@ class store_setquota(_store_account_command):
         except ClientError as err:
             raiseCLIError(err)
 
-@command()
+
+@command(pithos_cmds)
 class store_versioning(_store_account_command):
     """Get  versioning for account [or container ]"""
 
-    def main(self, container = None):
+    def main(self, container=None):
         super(self.__class__, self).main()
         try:
             if container is None:
@@ -961,11 +1134,12 @@ class store_versioning(_store_account_command):
             raiseCLIError(err)
         print_dict(reply)
 
-@command()
+
+@command(pithos_cmds)
 class store_setversioning(_store_account_command):
     """Set new versioning (auto, none) for account [or container]"""
 
-    def main(self, versioning, container = None):
+    def main(self, versioning, container=None):
         super(self.__class__, self).main()
         try:
             if container is None:
@@ -976,7 +1150,8 @@ class store_setversioning(_store_account_command):
         except ClientError as err:
             raiseCLIError(err)
 
-@command()
+
+@command(pithos_cmds)
 class store_group(_store_account_command):
     """Get user groups details for account"""
 
@@ -988,7 +1163,8 @@ class store_group(_store_account_command):
             raiseCLIError(err)
         print_dict(reply)
 
-@command()
+
+@command(pithos_cmds)
 class store_setgroup(_store_account_command):
     """Create/update a new user group on account"""
 
@@ -999,7 +1175,8 @@ class store_setgroup(_store_account_command):
         except ClientError as err:
             raiseCLIError(err)
 
-@command()
+
+@command(pithos_cmds)
 class store_delgroup(_store_account_command):
     """Delete a user group on an account"""
 
@@ -1010,34 +1187,37 @@ class store_delgroup(_store_account_command):
         except ClientError as err:
             raiseCLIError(err)
 
-@command()
+
+@command(pithos_cmds)
 class store_sharers(_store_account_command):
     """List the accounts that share objects with default account"""
 
-    def update_parser(self, parser):
-        super(store_sharers, self).update_parser(parser)
-        parser.add_argument('-l', action='store_true', dest='detail', default=False,
-            help='show detailed output')
-        parser.add_argument('-n', action='store',  dest='limit', default=10000,
-            help='show limited output')
-        parser.add_argument('--marker', action='store', dest='marker', default=None,
-            help='show output greater then marker')
+    def __init__(self, arguments={}):
+        super(self.__class__, self).__init__(arguments)
+        self.arguments['detail'] =\
+            FlagArgument('show detailed output', '-l')
+        self.arguments['limit'] =\
+            IntArgument('show limited output', '--n', default=1000)
+        self.arguments['marker'] =\
+            ValueArgument('show output greater then marker', '--marker')
 
     def main(self):
         super(self.__class__, self).main()
         try:
-            accounts = self.client.get_sharing_accounts(marker=getattr(self.args, 'marker'))
+            marker = self.get_argument('marker')
+            accounts = self.client.get_sharing_accounts(marker=marker)
         except ClientError as err:
             raiseCLIError(err)
 
         for acc in accounts:
-            stdout.write(bold(acc['name'])+' ')
-            if getattr(self.args, 'detail'):
-                print_dict(acc, exclude='name', ident=18)
-        if not getattr(self.args, 'detail'):
+            stdout.write(bold(acc['name']) + ' ')
+            if self.get_argument('detail'):
+                print_dict(acc, exclude='name', ident=4)
+        if not self.get_argument('detail'):
             print
 
-@command()
+
+@command(pithos_cmds)
 class store_versions(_store_container_command):
     """Get the version list of an object"""
 
@@ -1046,10 +1226,10 @@ class store_versions(_store_container_command):
         try:
             versions = self.client.get_object_versionlist(self.path)
         except ClientError as err:
-            raise CLIError(err)
+            raiseCLIError(err)
 
-        print('%s:%s versions'%(self.container,self.path))
+        print('%s:%s versions' % (self.container, self.path))
         for vitem in versions:
             t = localtime(float(vitem[1]))
             vid = bold(unicode(vitem[0]))
-            print('\t%s \t(%s)'%(vid, strftime('%d-%m-%Y %H:%M:%S', t)))
\ No newline at end of file
+            print('\t%s \t(%s)' % (vid, strftime('%d-%m-%Y %H:%M:%S', t)))