This file is indexed.

/usr/lib/python3/dist-packages/cement/core/controller.py is in python3-cement 2.10.0-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
"""Cement core controller module."""

import re
import textwrap
import argparse
from ..core import exc, interface, handler
from ..utils.misc import minimal_logger

LOG = minimal_logger(__name__)


def controller_validator(klass, obj):
    """
    Validates a handler implementation against the IController interface.

    """
    members = [
        '_setup',
        '_dispatch',
    ]
    meta = [
        'label',
        'interface',
        'config_section',
        'config_defaults',
        'stacked_on',
        'stacked_type',
    ]
    interface.validate(IController, obj, members, meta=meta)

    # also check _meta.arguments values
    errmsg = "Controller arguments must be a list of tuples.  I.e. " + \
             "[ (['-f', '--foo'], dict(action='store')), ]"

    if obj._meta.arguments is not None:
        if type(obj._meta.arguments) is not list:
            raise exc.InterfaceError(errmsg)
        for item in obj._meta.arguments:
            if type(item) is not tuple:
                raise exc.InterfaceError(errmsg)
            if type(item[0]) is not list:
                raise exc.InterfaceError(errmsg)
            if type(item[1]) is not dict:
                raise exc.InterfaceError(errmsg)

    if not obj._meta.label == 'base' and obj._meta.stacked_on is None:
        errmsg = "Controller `%s` is not stacked anywhere!" % \
                 obj.__class__.__name__
        raise exc.InterfaceError(errmsg)
    if not obj._meta.label == 'base' and \
            obj._meta.stacked_type not in ['nested', 'embedded']:
        raise exc.InterfaceError(
            "Controller '%s' " % obj._meta.label +
            "has an unknown stacked type of '%s'." %
            obj._meta.stacked_type
        )


class IController(interface.Interface):

    """
    This class defines the Controller Handler Interface.  Classes that
    implement this handler must provide the methods and attributes defined
    below.

    Implementations do *not* subclass from interfaces.

    Usage:

    .. code-block:: python

        from cement.core import controller

        class MyBaseController(controller.CementBaseController):
            class Meta:
                interface = controller.IController
                ...
    """
    # pylint: disable=W0232, C0111, R0903
    class IMeta:

        """Interface meta-data."""

        #: The string identifier of the interface.
        label = 'controller'

        #: The interface validator function.
        validator = controller_validator

    # Must be provided by the implementation
    Meta = interface.Attribute('Handler meta-data')

    def _setup(app_obj):
        """
        The _setup function is after application initialization and after it
        is determined that this controller was requested via command line
        arguments.  Meaning, a controllers _setup() function is only called
        right before it's _dispatch() function is called to execute a command.
        Must 'setup' the handler object making it ready for the framework
        or the application to make further calls to it.

        :param app_obj: The application object.
        :returns: ``None``

        """

    def _dispatch(self):
        """
        Reads the application object's data to dispatch a command from this
        controller.  For example, reading self.app.pargs to determine what
        command was passed, and then executing that command function.

        Note that Cement does *not* parse arguments when calling _dispatch()
        on a controller, as it expects the controller to handle parsing
        arguments (I.e. self.app.args.parse()).

        :returns: Returns the result of the executed controller function,
          or ``None`` if no controller function is called.

        """


class expose(object):

    """
    Used to expose controller functions to be listed as commands, and to
    decorate the function with Meta data for the argument parser.

    :param help: Help text to display for that command.
    :type help: str
    :param hide: Whether the command should be visible.
    :type hide: boolean
    :param aliases: Aliases to this command.
    :param aliases_only: Whether to only display the aliases (not the label).
     This is useful for situations where you have obscure function names
     which you do not want displayed.  Effecively, if there are aliases and
     `aliases_only` is True, then aliases[0] will appear as the actual
     command/function label.
    :type aliases: ``list``

    Usage:

    .. code-block:: python

        from cement.core.controller import CementBaseController, expose

        class MyAppBaseController(CementBaseController):
            class Meta:
                label = 'base'

            @expose(hide=True, aliases=['run'])
            def default(self):
                print("In MyAppBaseController.default()")

            @expose()
            def my_command(self):
                print("In MyAppBaseController.my_command()")

    """
    # pylint: disable=W0622

    def __init__(self, help='', hide=False, aliases=[], aliases_only=False):
        self.hide = hide
        self.help = help
        self.aliases = aliases
        self.aliases_only = aliases_only

    def __call__(self, func):
        metadict = {}
        metadict['label'] = re.sub('_', '-', func.__name__)
        metadict['func_name'] = func.__name__
        metadict['exposed'] = True
        metadict['hide'] = self.hide
        metadict['help'] = self.help or func.__doc__
        metadict['aliases'] = self.aliases
        metadict['aliases_only'] = self.aliases_only
        metadict['controller'] = None  # added by the controller
        func.__cement_meta__ = metadict
        return func


# pylint: disable=R0921
class CementBaseController(handler.CementBaseHandler):

    """
    This is an implementation of the
    `IControllerHandler <#cement.core.controller.IController>`_ interface, but
    as a base class that application controllers `should` subclass from.
    Registering it directly as a handler is useless.

    NOTE: This handler **requires** that the applications 'arg_handler' be
    argparse.  If using an alternative argument handler you will need to
    write your own controller base class.

    NOTE: This the initial default implementation of CementBaseController.  In
    the future it will be replaced by CementBaseController2, therefore using
    CementBaseController2 is recommended for new development.

    Usage:

    .. code-block:: python

        from cement.core.controller import CementBaseController

        class MyAppBaseController(CementBaseController):
            class Meta:
                label = 'base'
                description = 'MyApp is awesome'
                config_defaults = dict()
                arguments = []
                epilog = "This is the text at the bottom of --help."
                # ...

        class MyStackedController(CementBaseController):
            class Meta:
                label = 'second_controller'
                aliases = ['sec', 'secondary']
                stacked_on = 'base'
                stacked_type = 'embedded'
                # ...

    """
    class Meta:

        """
        Controller meta-data (can be passed as keyword arguments to the parent
        class).

        """

        interface = IController
        """The interface this class implements."""

        label = None
        """The string identifier for the controller."""

        aliases = []
        """
        A list of aliases for the controller.  Will be treated like
        command/function aliases for non-stacked controllers.  For example:
        ``myapp <controller_label> --help`` is the same as
        ``myapp <controller_alias> --help``.
        """

        aliases_only = False
        """
        When set to True, the controller label will not be displayed at
        command line, only the aliases will.  Effectively, aliases[0] will
        appear as the label.  This feature is useful for the situation Where
        you might want two controllers to have the same label when stacked
        on top of separate controllers.  For example, 'myapp users list' and
        'myapp servers list' where 'list' is a stacked controller, not a
        function.
        """

        description = None
        """The description shown at the top of '--help'.  Default: None"""

        config_section = None
        """
        A config [section] to merge config_defaults into.  Cement will default
        to controller.<label> if None is set.
        """

        config_defaults = {}
        """
        Configuration defaults (type: dict) that are merged into the
        applications config object for the config_section mentioned above.
        """

        arguments = []
        """
        Arguments to pass to the argument_handler.  The format is a list
        of tuples whos items are a ( list, dict ).  Meaning:

        ``[ ( ['-f', '--foo'], dict(dest='foo', help='foo option') ), ]``

        This is equivelant to manually adding each argument to the argument
        parser as in the following example:

        ``parser.add_argument(['-f', '--foo'], help='foo option', dest='foo')``

        """

        stacked_on = 'base'
        """
        A label of another controller to 'stack' commands/arguments on top of.
        """

        stacked_type = 'embedded'
        """
        Whether to `embed` commands and arguments within the parent controller
        or to simply `nest` the controller under the parent controller (making
        it a sub-sub-command).  Must be one of `['embedded', 'nested']` only
        if `stacked_on` is not `None`.
        """

        hide = False
        """Whether or not to hide the controller entirely."""

        epilog = None
        """
        The text that is displayed at the bottom when '--help' is passed.
        """

        usage = None
        """
        The text that is displayed at the top when '--help' is passed.
        Although the default is `None`, Cement will set this to a generic
        usage based on the `prog`, `controller` name, etc if nothing else is
        passed.
        """

        argument_formatter = argparse.RawDescriptionHelpFormatter
        """
        The argument formatter class to use to display --help output.
        """

        default_func = 'default'
        """
        Function to call if no sub-command is passed.  Note that this can
        **not** start with an ``_`` due to backward compatibility restraints
        in how Cement discovers and maps commands.
        """

    def __init__(self, *args, **kw):
        super(CementBaseController, self).__init__(*args, **kw)

        self.app = None
        self._commands = {}  # used to store collected commands
        self._visible_commands = []  # used to sort visible command labels
        self._arguments = []  # used to store collected arguments
        self._dispatch_map = {}  # used to map commands/aliases to controller
        self._dispatch_command = None  # set during _parse_args()

    def _setup(self, app_obj):
        """
        See `IController._setup() <#cement.core.cache.IController._setup>`_.
        """
        super(CementBaseController, self)._setup(app_obj)

        if getattr(self._meta, 'description', None) is None:
            self._meta.description = "%s Controller" % \
                self._meta.label.capitalize()

        self.app = app_obj

    def _collect(self):
        LOG.debug("collecting arguments/commands for %s" % self)
        arguments = []
        commands = []

        # process my arguments and commands first
        arguments = list(self._meta.arguments)

        for member in dir(self.__class__):
            if member.startswith('_'):
                continue
            try:
                func = getattr(self.__class__, member).__cement_meta__
            except AttributeError:
                continue
            else:
                func['controller'] = self
                commands.append(func)

        # process stacked controllers second for commands and args
        for contr in self.app.handler.list('controller'):
            # don't include self here
            if contr == self.__class__:
                continue

            contr = contr()
            contr._setup(self.app)
            if contr._meta.stacked_on == self._meta.label:
                if contr._meta.stacked_type == 'embedded':
                    contr_arguments, contr_commands = contr._collect()
                    for arg in contr_arguments:
                        arguments.append(arg)
                    for func in contr_commands:
                        commands.append(func)
                elif contr._meta.stacked_type == 'nested':
                    metadict = {}
                    metadict['label'] = re.sub('_', '-', contr._meta.label)
                    metadict['func_name'] = '_dispatch'
                    metadict['exposed'] = True
                    metadict['hide'] = contr._meta.hide
                    metadict['help'] = contr._meta.description
                    metadict['aliases'] = contr._meta.aliases
                    metadict['aliases_only'] = contr._meta.aliases_only
                    metadict['controller'] = contr
                    commands.append(metadict)

        return (arguments, commands)

    def _process_arguments(self):
        for _arg, _kw in self._arguments:
            try:
                self.app.args.add_argument(*_arg, **_kw)
            except argparse.ArgumentError as e:
                raise exc.FrameworkError(e.__str__())

    def _process_commands(self):
        self._dispatch_map = {}
        self._visible_commands = []

        for cmd in self._commands:
            # process command labels
            if cmd['label'] in self._dispatch_map.keys():
                raise exc.FrameworkError(
                    "Duplicate command named '%s' " % cmd['label'] +
                    "found in controller '%s'" % cmd['controller']
                )
            self._dispatch_map[cmd['label']] = cmd

            if not cmd['hide']:
                self._visible_commands.append(cmd['label'])

            # process command aliases
            for alias in cmd['aliases']:
                if alias in self._dispatch_map.keys():
                    raise exc.FrameworkError(
                        "The alias '%s' of the " % alias +
                        "'%s' controller collides " % cmd['controller'] +
                        "with a command or alias of the same name."
                    )
                self._dispatch_map[alias] = cmd
        self._visible_commands.sort()

    def _get_dispatch_command(self):
        default_func_key = re.sub('_', '-', self._meta.default_func)

        if (len(self.app.argv) <= 0) or (self.app.argv[0].startswith('-')):
            # if no command is passed, then use default
            if default_func_key in self._dispatch_map.keys():
                self._dispatch_command = self._dispatch_map[default_func_key]

        elif self.app.argv[0] in self._dispatch_map.keys():
            self._dispatch_command = self._dispatch_map[self.app.argv[0]]
            self.app.argv.pop(0)
        else:
            # check for default again (will get here if command line has
            # positional arguments that don't start with a -)
            if default_func_key in self._dispatch_map.keys():
                self._dispatch_command = self._dispatch_map[default_func_key]

    def _parse_args(self):
        self.app.args.description = self._help_text
        self.app.args.usage = self._usage_text
        self.app.args.formatter_class = self._meta.argument_formatter
        self.app._parse_args()

    def _dispatch(self):
        """
        Takes the remaining arguments from self.app.argv and parses for a
        command to dispatch, and if so... dispatches it.

        """
        if hasattr(self._meta, 'epilog'):
            if self._meta.epilog is not None:
                self.app.args.epilog = self._meta.epilog

        self._arguments, self._commands = self._collect()
        self._process_commands()
        self._get_dispatch_command()

        if self._dispatch_command:
            if self._dispatch_command['func_name'] == '_dispatch':
                func = getattr(self._dispatch_command['controller'],
                               '_dispatch')
                return func()
            else:
                self._process_arguments()
                self._parse_args()
                func = getattr(self._dispatch_command['controller'],
                               self._dispatch_command['func_name'])
                return func()
        else:
            self._process_arguments()
            self._parse_args()

    @property
    def _usage_text(self):
        """Returns the usage text displayed when ``--help`` is passed."""

        if self._meta.usage is not None:
            return self._meta.usage

        txt = "%s (sub-commands ...) [options ...] {arguments ...}" % \
              self.app.args.prog
        return txt

    @property
    def _help_text(self):
        """Returns the help text displayed when '--help' is passed."""

        cmd_txt = ''
        for label in self._visible_commands:
            cmd = self._dispatch_map[label]
            if len(cmd['aliases']) > 0 and cmd['aliases_only']:
                if len(cmd['aliases']) > 1:
                    first = cmd['aliases'].pop(0)
                    cmd_txt = cmd_txt + "  %s (aliases: %s)\n" % \
                        (first, ', '.join(cmd['aliases']))
                else:
                    cmd_txt = cmd_txt + "  %s\n" % cmd['aliases'][0]
            elif len(cmd['aliases']) > 0:
                cmd_txt = cmd_txt + "  %s (aliases: %s)\n" % \
                    (label, ', '.join(cmd['aliases']))
            else:
                cmd_txt = cmd_txt + "  %s\n" % label

            if cmd['help']:
                cmd_txt = cmd_txt + "    %s\n\n" % cmd['help']
            else:
                cmd_txt = cmd_txt + "\n"

        if len(cmd_txt) > 0:
            txt = '''%s

commands:

%s


        ''' % (self._meta.description, cmd_txt)
        else:
            txt = self._meta.description

        return textwrap.dedent(txt)