Source code for module_that_can_be_invoked_from_cli

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