Step 1: Simple calculator
Contents
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 writingfrom configpile import *
; they are aliases of identifiers in subpackages (for exampleconfigpile.Config
is an alias ofconfigpile.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: afloat
.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 callingconfigpile.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 byconfigpile
when it performs its introspection. For mypy, the fieldsx
andy
have typefloat
.The extra information is of type
Param
, and the concept is detailed in Params (parameters).Here, we instantiate a
Param
through theconfigpile.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. Whenconfigpile
deals with a--help
argument, the script execution has an exit value of0
, 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