Source code for module_that_can_be_invoked_from_cli

  1"""Calculate arithmetic expressions from command line."""
  2
  3import argparse
  4import enum
  5import sys
  6import typing
  7
  8import pydantic
  9
 10from package_name_to_import_with import (
 11    BinaryArithmeticOperator,
 12    CustomPydanticBaseModel,
 13    CustomStrEnum,
 14    calculate_results,
 15    solve_simplification,
 16)
 17
 18
[docs] 19@enum.unique 20class CalculatorType(CustomStrEnum): 21 """Define supported calculator types.""" 22 23 BINARY = "binary" 24 GENERAL = "general"
25 26
[docs] 27class BinaryInputs(CustomPydanticBaseModel): 28 """Define arguments for binary calculator. 29 30 Attributes 31 ---------- 32 calculator_type : typing.Literal[CalculatorType.BINARY] 33 kind of calculator 34 first_number : float 35 first number for the calculation 36 operator : BinaryArithmeticOperator 37 arithmetic operator to be used 38 second_number : float 39 second number for the calculation 40 """ 41 42 calculator_type: typing.Literal[CalculatorType.BINARY] = pydantic.Field( 43 description="kind of calculator" 44 ) 45 first_number: float = pydantic.Field(description="first number for the calculation") 46 operator: BinaryArithmeticOperator = pydantic.Field( 47 description="arithmetic operator to be used" 48 ) 49 second_number: float = pydantic.Field(description="second number for the calculation")
50 51
[docs] 52class GeneralInputs(CustomPydanticBaseModel): 53 """Define arguments of general calculator. 54 55 Attributes 56 ---------- 57 calculator_type : typing.Literal[CalculatorType.GENERAL] 58 kind of calculator 59 expression : str 60 mathematical expression to be evaluated 61 """ 62 63 calculator_type: typing.Literal[CalculatorType.GENERAL] = pydantic.Field( 64 description="kind of calculator" 65 ) 66 expression: str = pydantic.Field(description="mathematical expression to be evaluated")
67 68
[docs] 69class UserInputs(CustomPydanticBaseModel): 70 """Define sub-commands and arguments of CLI calculator. 71 72 Attributes 73 ---------- 74 inputs : BinaryInputs | GeneralInputs 75 inputs for the calculator 76 """ 77 78 inputs: BinaryInputs | GeneralInputs = pydantic.Field( 79 description="inputs for the calculator", discriminator="calculator_type" 80 )
81 82
[docs] 83@pydantic.validate_call(validate_return=True) 84def capture_user_inputs() -> UserInputs: 85 """Capture user inputs for arithmetic expression. 86 87 Returns 88 ------- 89 UserInputs 90 captured user inputs 91 """ 92 parser = argparse.ArgumentParser(description="calculator for console", add_help=True) 93 94 sub_parsers = parser.add_subparsers( 95 dest="calculator_type", help="types of arithmetic expressions" 96 ) 97 98 binary_parser = sub_parsers.add_parser(CalculatorType.BINARY, help="basic binary operations") 99 general_parser = sub_parsers.add_parser( 100 CalculatorType.GENERAL, help="standard simplification problems" 101 ) 102 103 binary_parser.add_argument("first_number", type=float, help="first number") 104 binary_parser.add_argument( 105 "operator", type=BinaryArithmeticOperator, help="arithmetic operator" 106 ) 107 binary_parser.add_argument("second_number", type=float, help="second number") 108 109 general_parser.add_argument("expression", type=str, help="infix expression") 110 111 parsed_arguments, _ = parser.parse_known_args() 112 113 return UserInputs.model_validate({"inputs": vars(parsed_arguments)})
114 115
[docs] 116@pydantic.validate_call(validate_return=True) 117def console_calculator() -> None: 118 """Calculate arithmetic expressions.""" 119 user_inputs = capture_user_inputs() 120 121 try: 122 match user_inputs.inputs.calculator_type: 123 case CalculatorType.BINARY: 124 operation_result = calculate_results( 125 user_inputs.inputs.first_number, # type: ignore[union-attr] 126 user_inputs.inputs.operator, # type: ignore[union-attr] 127 user_inputs.inputs.second_number, # type: ignore[union-attr] 128 ) 129 case CalculatorType.GENERAL: 130 operation_result = solve_simplification( 131 user_inputs.inputs.expression # type: ignore[union-attr] 132 ) 133 case _: # pragma: no cover 134 operation_result = None 135 except Exception as error: # noqa: BLE001 # pylint: disable=broad-except 136 sys.stderr.write(f"Error: {error}") 137 else: 138 sys.stdout.write(f"Result = {operation_result}")
139 140 141if __name__ == "__main__": 142 console_calculator()