Source code for emsm.core.argparse_

#!/usr/bin/env python3

# The MIT License (MIT)
#
# Copyright (c) 2014-2018 <see AUTHORS.txt>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

"""
This module contains the :class:`ArgumentParser` class which wraps a
Python :class:`argparse.ArgumentParser` for the EMSM.
"""


# Modules
# ------------------------------------------------

# std
import argparse
import subprocess
import logging

# local
from .license_ import LICENSE
from .version import VERSION


# Data
# ------------------------------------------------

__all__ = [
    "LongHelpAction",
    "ArgumentParser"
    ]

log = logging.getLogger(__file__)


# Classes
# ------------------------------------------------

[docs]class LongHelpAction(argparse.Action): """ Prints the *description* using less (if available) and exists. """ def __init__(self, option_strings, description=None, dest=argparse.SUPPRESS, default=argparse.SUPPRESS): """ """ self.description = description if description is not None else str() self.description.strip() super().__init__( option_strings = option_strings, dest = dest, default = default, nargs = 0, help = "shows the manual and exists" ) return None def __call__(self, parser, namespace, values, option_string=None): """ Prints the :attr:`description`. """ # We print the docstring under linux using *less*, if available. was_printed = False try: less_proc = subprocess.Popen("less", stdin=subprocess.PIPE) try: less_proc.stdin.write(self.description.encode()) was_printed = True except IOError as err: print(err) finally: less_proc.stdin.close() less_proc.wait() except (OSError, ValueError) as err: pass # Use print() if nothing else worked. if not was_printed: print(self.description) was_printed = True parser.exit() return None
[docs]class ArgumentParser(object): """ Wraps an :class:`argparse.ArgumentParser` instance. This class handles the *root* EMSM argument parser. The root parser only has a few global EMSM commands like ``-w``, ``-s``. Each plugin has its own subparser: .. code-block:: bash $ foo@bar: minecraft [emsm args] (plugin_name) [plugin args] **Example:** .. code-block:: bash # Call the *worlds* plugin with the world *foo* as target. $ foo@bar: minecraft -w foo worlds --status """ def __init__(self, app): """ """ self._app = app self._argparser = argparse.ArgumentParser( description = "Extendable Minecraft Server Manager (EMSM)", epilog = "Visit https://emsm.readthedocs.io for "\ "further information.", add_help=True ) # This subparser contains the parsers for the plugins. self._plugin_subparsers = self._argparser.add_subparsers( title = "plugin", dest = "plugin", description = "The name of the plugin, you want to invoke." ) # Contains and caches the parsed arguments. self._args = None return None
[docs] def argparser(self): """ Returns the wrapped :class:`argparse.ArgumentParser` instance. """ return self._argparser
[docs] def args(self, cache=True): """ Parses (if not yet done) the command line arguments and returns a namespace object that contains the result. :param bool cache: If ``True``, and the arguments have already been parsed, the result of the previous parse is returned. .. seealso:: * :meth:`argparse.ArgumentParser.parse_args` """ if self._args is None or not cache: log.info("parsing arguments ...".format(self._args)) self._args = self._argparser.parse_args() log.info("parsed arguments: {}".format(self._args)) return self._args
[docs] def plugin_parser(self, plugin_name): """ Returns the subparser for the plugin with the name *plugin_name*. """ return self._plugin_subparsers.add_parser(plugin_name)
[docs] def setup(self): """ Adds the global EMSM arguments to the root argument parser. This method has to be called, when the :class:`~emsm.core.worlds.WorldManager` and :class:`~emsm.core.server.ServerManager` have been loaded, since we require the names of the available worlds and server. """ log.info("adding emsm arguments ...") # The selectable worlds. worlds_group = self._argparser.add_mutually_exclusive_group() worlds_group.add_argument( "-w", "--world", action = "append", dest = "worlds", metavar = "WORLD", choices = self._app.worlds().get_names(), default = list(), help = "Selects the world." ) worlds_group.add_argument( "-W", "--all-worlds", action = "store_const", dest = "all_worlds", const = True, default = False, help = "Selects all available worlds." ) # The selectable server. server_group = self._argparser.add_mutually_exclusive_group() server_group.add_argument( "-s", "--server", action = "append", dest = "server", metavar = "SERVER", choices = self._app.server().get_names(), default = list(), help = "Selects single server software." ) server_group.add_argument( "-S", "--all-server", action = "store_const", dest = "all_server", const = True, default = False, help = "Selects all available server software." ) return None