Compare commits
5
Commits
planning
...
9030510773
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9030510773 | ||
|
|
5e1067b4f3 | ||
|
|
c90e5afb7c | ||
|
|
1237f41840 | ||
|
|
6809db7930 |
@@ -173,3 +173,6 @@ cython_debug/
|
||||
|
||||
# PyPI configuration file
|
||||
.pypirc
|
||||
|
||||
# Doxygen output
|
||||
docs/doxygen/
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# Doxygen configuration for the console calculator.
|
||||
# Generate the API documentation with: doxygen Doxyfile
|
||||
PROJECT_NAME = "Calculator"
|
||||
PROJECT_BRIEF = "Console calculator (Udemy 100 Days of Code, day 10)"
|
||||
OUTPUT_DIRECTORY = docs/doxygen
|
||||
INPUT = src
|
||||
FILE_PATTERNS = *.py
|
||||
RECURSIVE = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = YES
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_PRIVATE = NO
|
||||
GENERATE_HTML = YES
|
||||
GENERATE_LATEX = NO
|
||||
QUIET = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_NO_PARAMDOC = YES
|
||||
@@ -0,0 +1,22 @@
|
||||
[build-system]
|
||||
requires = ["setuptools>=69"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "calc"
|
||||
version = "0.1.0"
|
||||
description = "A console calculator (Udemy 100 Days of Code, day 10)."
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
license = { text = "AGPL-3.0-or-later" }
|
||||
dependencies = []
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = ["pytest>=8"]
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["src"]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
pythonpath = ["src"]
|
||||
@@ -0,0 +1,4 @@
|
||||
"""!
|
||||
@file __init__.py
|
||||
@brief Console calculator package (Udemy 100 Days of Code, day 10).
|
||||
"""
|
||||
@@ -0,0 +1,57 @@
|
||||
"""!
|
||||
@file constants.py
|
||||
@brief Constants used by the console calculator.
|
||||
"""
|
||||
|
||||
## Operation symbols, in the order they are offered to the user.
|
||||
SYMBOL_ADD: str = "+"
|
||||
SYMBOL_SUBTRACT: str = "-"
|
||||
SYMBOL_MULTIPLY: str = "*"
|
||||
SYMBOL_DIVIDE: str = "/"
|
||||
|
||||
## Answers accepted after a calculation.
|
||||
ANSWER_CONTINUE: str = "y"
|
||||
ANSWER_NEW: str = "n"
|
||||
ANSWER_QUIT: str = "q"
|
||||
|
||||
## Prompts and messages shown to the user.
|
||||
PROMPT_FIRST_NUMBER: str = "What's the first number?: "
|
||||
PROMPT_NEXT_NUMBER: str = "What's the next number?: "
|
||||
PROMPT_OPERATION: str = "Pick an operation: "
|
||||
PROMPT_AGAIN: str = (
|
||||
f"Type '{ANSWER_CONTINUE}' to continue calculating with {{result}}, "
|
||||
f"'{ANSWER_NEW}' to start a new calculation, "
|
||||
f"or '{ANSWER_QUIT}' to quit: "
|
||||
)
|
||||
MESSAGE_INVALID_NUMBER: str = "That is not a number, please try again."
|
||||
MESSAGE_INVALID_OPERATION: str = "That is not a valid operation, please try again."
|
||||
MESSAGE_INVALID_ANSWER: str = "Please answer with one of the listed letters."
|
||||
MESSAGE_DIVIDE_BY_ZERO: str = "You cannot divide by zero."
|
||||
MESSAGE_GOODBYE: str = "Goodbye!"
|
||||
|
||||
## ASCII title shown when the program starts.
|
||||
ASCII_TITLE: str = r"""
|
||||
____ _ _ _
|
||||
/ ___|__ _ | | ___ _ _| | __ _| |_ ___ _ __
|
||||
| | / _` | | |/ __| | | | |/ _` | __/ _ \| '__|
|
||||
| |__| (_| | | | (__| |_| | | (_| | || (_) | |
|
||||
\____\__,_| |_|\___|\__,_|_|\__,_|\__\___/|_|
|
||||
"""
|
||||
|
||||
## ASCII calculator shown under the title.
|
||||
ASCII_CALCULATOR: str = r"""
|
||||
_____________________
|
||||
| _________________ |
|
||||
| | 0 | |
|
||||
| |_________________| |
|
||||
| ___ ___ ___ ___ |
|
||||
| | 7 | 8 | 9 | | + | |
|
||||
| |___|___|___| |___| |
|
||||
| | 4 | 5 | 6 | | - | |
|
||||
| |___|___|___| |___| |
|
||||
| | 1 | 2 | 3 | | x | |
|
||||
| |___|___|___| |___| |
|
||||
| | . | 0 | = | | / | |
|
||||
| |___|___|___| |___| |
|
||||
|_____________________|
|
||||
"""
|
||||
@@ -0,0 +1,63 @@
|
||||
"""!
|
||||
@file operations.py
|
||||
@brief Arithmetic operations and the dictionary that maps symbols to them.
|
||||
"""
|
||||
|
||||
from collections.abc import Callable
|
||||
|
||||
from calc.constants import (
|
||||
SYMBOL_ADD,
|
||||
SYMBOL_DIVIDE,
|
||||
SYMBOL_MULTIPLY,
|
||||
SYMBOL_SUBTRACT,
|
||||
)
|
||||
|
||||
|
||||
def add(n1: float, n2: float) -> float:
|
||||
"""!
|
||||
@brief Add two numbers.
|
||||
@param n1 The first number.
|
||||
@param n2 The second number.
|
||||
@return The sum of @p n1 and @p n2.
|
||||
"""
|
||||
return n1 + n2
|
||||
|
||||
|
||||
def subtract(n1: float, n2: float) -> float:
|
||||
"""!
|
||||
@brief Subtract the second number from the first.
|
||||
@param n1 The first number.
|
||||
@param n2 The second number.
|
||||
@return The difference @p n1 minus @p n2.
|
||||
"""
|
||||
return n1 - n2
|
||||
|
||||
|
||||
def multiply(n1: float, n2: float) -> float:
|
||||
"""!
|
||||
@brief Multiply two numbers.
|
||||
@param n1 The first number.
|
||||
@param n2 The second number.
|
||||
@return The product of @p n1 and @p n2.
|
||||
"""
|
||||
return n1 * n2
|
||||
|
||||
|
||||
def divide(n1: float, n2: float) -> float:
|
||||
"""!
|
||||
@brief Divide the first number by the second.
|
||||
@param n1 The dividend.
|
||||
@param n2 The divisor.
|
||||
@return The quotient @p n1 divided by @p n2.
|
||||
@throws ZeroDivisionError When @p n2 is zero.
|
||||
"""
|
||||
return n1 / n2
|
||||
|
||||
|
||||
## Maps an operation symbol to its function. The functions are stored, not called.
|
||||
OPERATIONS: dict[str, Callable[[float, float], float]] = {
|
||||
SYMBOL_ADD: add,
|
||||
SYMBOL_SUBTRACT: subtract,
|
||||
SYMBOL_MULTIPLY: multiply,
|
||||
SYMBOL_DIVIDE: divide,
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
"""!
|
||||
@file test_operations.py
|
||||
@brief Tests for the arithmetic operations.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from calc.operations import OPERATIONS, add, divide, multiply, subtract
|
||||
|
||||
|
||||
def test_add_returns_sum() -> None:
|
||||
assert add(2, 3) == 5
|
||||
|
||||
|
||||
def test_subtract_returns_difference() -> None:
|
||||
assert subtract(2, 3) == -1
|
||||
|
||||
|
||||
def test_multiply_returns_product() -> None:
|
||||
assert multiply(4, 2.5) == 10
|
||||
|
||||
|
||||
def test_divide_returns_quotient() -> None:
|
||||
assert divide(9, 3) == 3
|
||||
|
||||
|
||||
def test_divide_when_divisor_is_zero() -> None:
|
||||
with pytest.raises(ZeroDivisionError):
|
||||
divide(1, 0)
|
||||
|
||||
|
||||
def test_operations_maps_symbols_to_functions() -> None:
|
||||
assert OPERATIONS == {"+": add, "-": subtract, "*": multiply, "/": divide}
|
||||
Reference in New Issue
Block a user