Step 1: Simple calculator

Step 1: Simple calculator

We build a script that takes two floating-point values as an argument, adds them and displays them.

In the code below, we write our own Parser subclass to parse floating-point numbers.

Let’s observe a few things.

On the code general structure:

  • The most used configpile identifiers are imported when writing from configpile import *; they are aliases of identifiers in subpackages (for example configpile.Config is an alias of configpile.config.Config).

  • The “configuration” is a dataclass using dataclass(). It should be frozen because there is no reason not to.

  • The “configuration” is also a subclass of configpile.config.Config.

  • The script help is given in the class docstring; argument descriptions are written using sphinx autodoc style comments (they start with #:).

On the parser declaration:

  • A parser is a subclass of configpile.parsers.Parser, which is generic: when declaring the inheritance relation, we specify what this parser returns: a float.

    To subclass a parser, one only needs to implement the parse() method.

On the parameter declarations:

  • The parameters are dataclass fields. They are automatically filled by configpile when calling configpile.config.Config.from_command_line_() using the information given in the annotated type annotation.

  • The extra information provided in the typing.Annotated wrapper is removed when type checking, and is used only by configpile when it performs its introspection. For mypy, the fields x and y have type float.

  • The extra information is of type Param, and the concept is detailed in Params (parameters).

  • Here, we instantiate a Param through the configpile.arg.Param.store() static method. This a kind of parameter that takes the last value provided. Note that we did not define a default value for the parameters, thus both of them will be required.

  • The command-line flags --x and --y are automatically deduced from the Python identifiers.

On the sample script executions:

  • Note that when the script is called with a --help argument, or when the configuration cannot be parsed, the script execution is aborted. When configpile deals with a --help argument, the script execution has an exit value of 0, but when there is an error, the exit value will be positive to signal this fact.

  • When several errors occur, configpile does not stop at the first error encountered but accumulates them.

Code

"""
Calculator tutorial, step 1
"""
from dataclasses import dataclass

from typing_extensions import Annotated

from configpile import Config, Err, Param, Parser, Res


class FloatPT(Parser[float]):
    """
    Parameter type that parses floats
    """

    def parse(self, arg: str) -> Res[float]:
        try:
            return float(arg)
        except ValueError as e:
            return Err.make(str(e))


floatPT = FloatPT()


@dataclass(frozen=True)
class Calc(Config):
    """
    Command-line tool that sums two floating point numbers
    """

    #: First argument
    x: Annotated[float, Param.store(floatPT)]

    #: Second argument
    y: Annotated[float, Param.store(floatPT)]


c = Calc.from_command_line_()
print(f"{c.x} + {c.y} = {c.x+c.y}")

Executions

Note that on the examples below, the path to the Python script is relative to the docs/source folder.

$ python ../../examples/calculator1.py --help
usage: ../../examples/calculator1.py [--x X] [--y Y]

Command-line tool that sums two floating point numbers

required arguments:
  --x X  First argument
  --y Y  Second argument
$ python ../../examples/calculator1.py --x 1 --y 2
1.0 + 2.0 = 3.0
$ python ../../examples/calculator1.py --x asd --y zxc
Encountered errors:

 0 In flag: --x                                                                 
   In param: x                                                                  
   could not convert string to float: 'asd'                                     
 1 In flag: --y                                                                 
   In param: y                                                                  
   could not convert string to float: 'zxc'                                     
 
usage: ../../examples/calculator1.py [--x X] [--y Y]

Command-line tool that sums two floating point numbers

required arguments:
  --x X  First argument
  --y Y  Second argument