nodes: 0, module; 1, function_definition; 2, function_name:plugins; 3, parameters; 4, comment:# TODO: share this documentation with `../doc/plugin.rst`...; 5, block; 6, identifier:group; 7, default_parameter; 8, expression_statement; 9, expression_statement; 10, expression_statement; 11, expression_statement; 12, return_statement; 13, identifier:spec; 14, None; 15, string:'''
    Returns a `PluginSet` object for the specified setuptools-style
    entrypoint `group`. This is just a wrapper around
    `pkg_resources.iter_entry_points` that allows the plugins to sort
    and override themselves.
  
    The optional `spec` parameter controls how and what plugins are
    loaded. If it is ``None`` or the special value ``'*'``, then the
    normal plugin loading will occur, i.e. all registered plugins will
    be loaded and their self-declared ordering and dependencies will be
    applied.
  
    Otherwise, the `spec` is taken as a comma- or whitespace-separated
    list of plugins to load. In this mode, the `spec` can either specify
    an exact list of plugins to load, in the specified order, referred
    to as an "absolute" spec. Otherwise, it is a "relative" spec, which
    indicates that it only adjusts the standard registered plugin
    loading. A spec is a list of either absolute or relative
    instructions, and they cannot be mixed.
  
    In either mode, a plugin is identified either by name for registered
    plugins (e.g. ``foo``), or by fully-qualified Python module and
    symbol name for unregistered plugins
    (e.g. ``package.module.symbol``).
  
    Plugins in an absolute spec are loaded in the order specified and
    can be optionally prefixed with the following special characters:
  
    * ``'?'`` : the specified plugin should be loaded if available.  If
      it is not registered, cannot be found, or cannot be loaded, then
      it is ignored (a DEBUG log message will be emitted, however).
  
    Plugins in a relative spec are always prefixed with at least one of
    the following special characters:
  
    * ``'-'`` : removes the specified plugin; this does not affect
      plugin ordering, it only removes the plugin from the loaded
      list. If the plugin does not exist, no error is thrown.
  
    * ``'+'`` : adds or requires the specified plugin to the loaded
      set. If the plugin is not a named/registered plugin, then it will
      be loaded as an asset-symbol, i.e. a Python-dotted module and
      symbol name. If the plugin does not exist or cannot be loaded,
      this will throw an error. It does not affect the plugin ordering
      of registered plugins.
  
    * ``'/'`` : the plugin name is taken as a regular expression that
      will be used to match plugin names and it must terminate in a
      slash. Note that this must be the **last** element in the spec
      list.
  
    Examples:
  
    * ``'*'`` : load all registered plugins.
  
    * ``'foo,bar'`` : load the "foo" plugin, then the "bar" plugin.
  
    * ``'foo,?bar'`` : load the "foo" plugin and if the "bar" plugin
      exists, load it too.
  
    * ``'-zig'`` : load all registered plugins except the "zig" plugin.
  
    * ``'+pkg.foo.bar'`` : load all registered plugins and then load
      the "pkg.foo.bar" Python symbol.
  
    * ``'pkg.foo.bar'`` : load only the "pkg.foo.bar" Python symbol.
    '''; 16, assignment; 17, assignment; 18, augmented_assignment; 19, call; 20, identifier:pspec; 21, call; 22, identifier:plugs; 23, call; 24, identifier:plugs; 25, call; 26, identifier:PluginSet; 27, argument_list; 28, identifier:_parse_spec; 29, argument_list; 30, identifier:list; 31, argument_list; 32, identifier:list; 33, argument_list; 34, identifier:group; 35, identifier:spec; 36, call; 37, identifier:spec; 38, call; 39, call; 40, identifier:list; 41, argument_list; 42, identifier:_get_registered_plugins; 43, argument_list; 44, identifier:_get_unregistered_plugins; 45, argument_list; 46, call; 47, identifier:group; 48, identifier:pspec; 49, identifier:group; 50, identifier:plugs; 51, identifier:pspec; 52, identifier:_sort_plugins; 53, argument_list; 54, identifier:group; 55, identifier:plugs; 56, identifier:pspec; 57, identifier:spec
code: def plugins(group, spec=None):
    # TODO: share this documentation with `../doc/plugin.rst`...
    '''
    Returns a `PluginSet` object for the specified setuptools-style
    entrypoint `group`. This is just a wrapper around
    `pkg_resources.iter_entry_points` that allows the plugins to sort
    and override themselves.
  
    The optional `spec` parameter controls how and what plugins are
    loaded. If it is ``None`` or the special value ``'*'``, then the
    normal plugin loading will occur, i.e. all registered plugins will
    be loaded and their self-declared ordering and dependencies will be
    applied.
  
    Otherwise, the `spec` is taken as a comma- or whitespace-separated
    list of plugins to load. In this mode, the `spec` can either specify
    an exact list of plugins to load, in the specified order, referred
    to as an "absolute" spec. Otherwise, it is a "relative" spec, which
    indicates that it only adjusts the standard registered plugin
    loading. A spec is a list of either absolute or relative
    instructions, and they cannot be mixed.
  
    In either mode, a plugin is identified either by name for registered
    plugins (e.g. ``foo``), or by fully-qualified Python module and
    symbol name for unregistered plugins
    (e.g. ``package.module.symbol``).
  
    Plugins in an absolute spec are loaded in the order specified and
    can be optionally prefixed with the following special characters:
  
    * ``'?'`` : the specified plugin should be loaded if available.  If
      it is not registered, cannot be found, or cannot be loaded, then
      it is ignored (a DEBUG log message will be emitted, however).
  
    Plugins in a relative spec are always prefixed with at least one of
    the following special characters:
  
    * ``'-'`` : removes the specified plugin; this does not affect
      plugin ordering, it only removes the plugin from the loaded
      list. If the plugin does not exist, no error is thrown.
  
    * ``'+'`` : adds or requires the specified plugin to the loaded
      set. If the plugin is not a named/registered plugin, then it will
      be loaded as an asset-symbol, i.e. a Python-dotted module and
      symbol name. If the plugin does not exist or cannot be loaded,
      this will throw an error. It does not affect the plugin ordering
      of registered plugins.
  
    * ``'/'`` : the plugin name is taken as a regular expression that
      will be used to match plugin names and it must terminate in a
      slash. Note that this must be the **last** element in the spec
      list.
  
    Examples:
  
    * ``'*'`` : load all registered plugins.
  
    * ``'foo,bar'`` : load the "foo" plugin, then the "bar" plugin.
  
    * ``'foo,?bar'`` : load the "foo" plugin and if the "bar" plugin
      exists, load it too.
  
    * ``'-zig'`` : load all registered plugins except the "zig" plugin.
  
    * ``'+pkg.foo.bar'`` : load all registered plugins and then load
      the "pkg.foo.bar" Python symbol.
  
    * ``'pkg.foo.bar'`` : load only the "pkg.foo.bar" Python symbol.
    '''
    pspec  = _parse_spec(spec)
    plugs  = list(_get_registered_plugins(group, pspec))
    plugs  += list(_get_unregistered_plugins(group, plugs, pspec))
    return PluginSet(group, spec, list(_sort_plugins(group, plugs, pspec, spec)))