I want to get a job, and one of the questions:

Write a simple implementation of the function to parse command line parameters ( getopt ).

  • We assume that we need a data structure containing a previously known admissible set of parameters of various types — строки , целые числа , числа с плавающей точкой целые числа , etc., as well as a признак, является ли этот параметр обязательным .

  • We assume that the parameters can be transmitted only in a "long" format with a mandatory -- before the parameter name ( that is - --my-option-name my-option-val , - --my-option-name=my-option-val , --my-boolean-option ).

  • Parameters can be several.

  • The function must be able to handle the --help parameter ( if it is listed in the parameter list when calling the function ), which displays an example of use ( optional parameters must be displayed in square brackets ).

    Tell me what they want from me, I do not understand the task ...

    You need to write in python .

  • Closed due to the fact that the issue is too general for the participants m9_psy , Xander , Kromster , Alexey Shimansky , Sasha Omelchenko 21 Apr '17 at 14:38 .

    Please correct the question so that it describes the specific problem with sufficient detail to determine the appropriate answer. Do not ask a few questions at once. See “How to ask a good question?” For clarification. If the question can be reformulated according to the rules set out in the certificate , edit it .

    • 2
      Read about the argparse module - they want you to write a simplified version of this module ... - MaxU
    • Thanks, it became clearer, but still not to the end. I need to write a function to which I cannot add a parameter, but only to use the finished ones written in it? (Ala - complicate (3) and (5)) and the help parameter which displays these parameters and a description? - Nikita

    2 answers 2

    You need to create an argument parser that will work with the sys.argv array.

    Roughly speaking, you need to create a class that will be capable of the following:

  • Work with long arguments (for example, --help or --value=2 )
  • Which, when running a script with an argument --help will display help for the script, where the optional arguments will be indicated in square brackets .
  • The parser must be able to handle multiple arguments.

    getopt documentation
    argparse

    • thanks, now I understand everything - Nikita

    To implement an analogue of argparse , docopt , it is enough to specify the way how to set the expected command line parameters and recognize the actual arguments passed to the program, which correspond to these parameters.

    For specification of parameters, you can use the annotation of the main() function, which is called when the script starts:

     REQUIRED = object() @simple_cli(__doc__) def main(*, number: int = REQUIRED, flag: bool = False): # some filler code that uses the parsed args print(number + 1, flag, sep=' | ') if __name__ == '__main__': main() 

    This says that the script takes two parameters --number and --flag . --number takes an integer value and is required, and --flag is a simple boolean flag (obviously, which is optional and disabled by default).

    Here, simple_cli() is the decorator, which turns sys.argv (command line arguments) into the actual parameters of the main() function:

     #!/usr/bin/env python3 """Usage: parse-args --number=<int> [--flag]""" import inspect import functools import sys def simple_cli(description): """Implement a simple annotation-based command-line parser.""" def decorator(main): @functools.wraps(main) def wrapper(argv=None): if argv is None: argv = sys.argv if '--help' in argv: sys.exit(description) params = inspect.signature(main).parameters parser = ArgumentParser.from_params(*params.values()) try: return main(**parser.parse_args(argv[1:])) except ArgumentError as e: sys.exit(f"Error: {e}\n{description}") return wrapper return decorator 

    Examples of using:

     $ parse-args.py --help Usage: parse-args --number=<int> [--flag] $ parse-args --number=1 --flag 2 | True 

    Here the docstring module is used as the --help message. If desired, you can generate the usage automatically from the declaration of the main() function to eliminate duplication of information about the parameters. Or vice versa: from the docstring generate a parser for command line arguments like this docopt does.

    The actual recognition of the arguments is handled by the ArgumentParser class:

     from collections import namedtuple Parameter = namedtuple('Parameter', 'name type required') class ArgumentError(Exception): pass class ArgumentParser: """(--option[=value])*""" def __init__(self, params): self.params = params # parameters specification @classmethod def from_params(cls, *params): return cls({p.name: Parameter(p.name, str if p.annotation is p.empty else p.annotation, p.default is REQUIRED) for p in params if p.kind == p.KEYWORD_ONLY}) def parse_args(self, argv): args = {name[2:]: value if '=' in arg else None for arg in argv for name, value in [arg.partition('=')[::2]]} required_params = { p.name: p for p in self.params.values() if p.required} if not (required_params.keys() <= args.keys()): raise ArgumentError("missing required parameters") if not (args.keys() <= self.params.keys()): raise ArgumentError("unknown parameters") for name, value in args.items(): param = self.params[name] if param.type is bool: if value is not None: raise ArgumentError("flag with a value") args[name] = True elif param.type is not str: if value is None: raise ArgumentError(f"--{name} option is missing value") try: args[name] = param.type(value) except ValueError as e: raise ArgumentError(str(e)) return args 

    From the point of view of Argparser each argument has the form --option[=value] , where square brackets say that the value may not be present. --option value not supported (can be added).

    The specification of possible parameters is represented by the Parameter list of objects. from_params() converts the specification from the inspect.Parameter format to Parameter(name, type, required) .

    parse_args() turns the command line arguments ( sys.argv[1:] ) into arguments that can be passed to main() . The code is straightforward. The noticeable part is devoted to throwing an ArgumentError exception if the input arguments do not match the specified specification.