diff --git a/week1_projects/amandapanda00/armstrong_number_checker/README.md b/week1_projects/amandapanda00/armstrong_number_checker/README.md new file mode 100644 index 0000000..6a46162 --- /dev/null +++ b/week1_projects/amandapanda00/armstrong_number_checker/README.md @@ -0,0 +1,125 @@ +Amandapanda00 – Armstrong Number Checker +What the project does: +This project determines whether a given integer is an Armstrong number. An Armstrong number is a number that is equal to the sum of its digits, each raised to the power of the number of digits. (153 = 1³ + 5³ + 3³ = 153). + +The program allows you to: + +* Enter numbers directly from the keyboard, or + +* Read and process multiple numbers from a file. + +It includes proper error handling, file-processing safety, and clear output formatting. + +How to run it: +1. Make sure Python is installed on your computer. +2. Clone or download this repository. +3. Open the project in an environment that supports Python such as VS code or PyCharm. +4. Run the `main.py` file. +5. When prompted, choose an input method: + +* Keyboard input: Enter a number directly. + +* File input: Enter a filename to check numbers from a file (e.g., numbers.txt). + The program will read each line and check if it is an Armstrong number. + Invalid lines are skipped with a message for the user. + +Example input/output + +Example Input: + +153 + +Expected Output: + +153 is an Armstrong number + +Another Example: + +numbers.txt file + +Line 1: abc: Raises a ValueError when converting to int. The program prints: +Invalid entry on line 1: 'abc' + +Line 2: 123 = Successfully converted to an integer. Checked by is_armstrong(). Output: +123 is not an Armstrong number. + +Line 3: 153 = Successfully converted to an integer. Checked by is_armstrong(). Output: +153 is an Armstrong number. + +Line 4: 370 = Successfully converted to an integer. Checked by is_armstrong(). Output: +370 is an Armstrong number. + +Line 5: 456 = Successfully converted to an integer. Checked by is_armstrong(). Output: +456 is not an Armstrong number. + +Line 6: xyz Raises a ValueError. Output: +Invalid entry on line 6: 'xyz' + +Line 7: 9474 = Successfully converted to an integer. Checked by is_armstrong(). Output: +9474 is an Armstrong number. + +Line 8: -45 = Successfully converted to an integer. Checked by is_armstrong(). Output: +-45 is not an Armstrong number. + +Line 9: -153 = Successfully converted to an integer. Checked by is_armstrong(). Output: +-153 is not an Armstrong number. + +This file demonstrates: + +* Try/except blocks catching invalid data (abc and xyz). + +* Data integrity: only valid numbers are processed. File "r" read only. + +* File handling: reads multiple lines from a file. + + +Error Handling + +try/except blocks are used to handle invalid input/value errors. + +* This ensures the program is not going to crash if a user enters a non-integer value. + +* When reading a file, invalid entries are skipped, and the line number is reported to help track and identify errors. + +* File handling is done with "r" mode (read-only) to protect the file and prevent accidental changes. + + +Testing + +* PyCharm Debugger: Used to step through code and verify logic. + +* Pytest: Automatically tests the functionality of the Armstrong Number Checker, including both keyboard input and file input. Ensures that the program behaves correctly for a variety of cases. + +* Flake8: Checks code against Python style guidelines (PEP 8). + +* Pydocstyle: Checks that documentation is complete and clear, ensuring maintainability. + +Updates Included in This Version + +1. process_result() now returns a string instead of printing directly. This improves testability and separation of concerns. + +2. main() is updated so all printing happens in one place, following recommended best practices. + +3. Improved documentation for clarity. + +4. Updated file-processing function to include: +* Files are opened using encoding="utf-8" to ensure proper handling of characters in different environments and locales. + +* This prevents issues with non-ASCII characters and ensures consistent behavior across operating systems. + + +Future Improvements / Suggestions + +Here are recommended enhancements that could be added: + + +* Add GUI version + +* Limit maximum allowed digits/value to avoid CPU/memory DoS from huge inputs and report if input is too large. + +* Expand pytest coverage to include file-processing tests + +* Add a GitHub Actions workflow + + + diff --git a/week1_projects/amandapanda00/armstrong_number_checker/main.py b/week1_projects/amandapanda00/armstrong_number_checker/main.py new file mode 100644 index 0000000..0b7d5d9 --- /dev/null +++ b/week1_projects/amandapanda00/armstrong_number_checker/main.py @@ -0,0 +1,93 @@ +# Armstrong Number Checker +# Author: amandapanda00 +# Date: 11/04/2025 +""" +This program checks whether a given integer is an Armstrong number. + +An Armstrong number is equal to the sum of its digits each raised +to the power of the number of digits. +""" + + +def is_armstrong(number): + """ + Determine whether a given integer is an Armstrong number. + + An Armstrong number equals the sum of its digits raised to the power + of the number of digits. Negative numbers automatically return False. + + Parameter: + number (int): The integer to be tested. + + Returns: + bool: True if the number is an Armstrong number, False otherwise. + """ + if number < 0: + return False # negative numbers are not Armstrong numbers + + digits = [int(d) for d in str(number)] + n = len(digits) + total = sum(d ** n for d in digits) + return total == number + + +def process_result(number): + """Return the formatted Armstrong result string.""" + if is_armstrong(number): + return f"{number} is an Armstrong number." + else: + return f"{number} is not an Armstrong number." + + +def process_file(filename="numbers.txt"): + """ + Read lines from a file and test each entry to determine whether it + is an Armstrong number. + + Invalid lines and empty lines are skipped with an explanation. + """ + try: + with open(filename, "r", encoding="utf-8") as file: + for line_num, line in enumerate(file, start=1): + line = line.strip() + + if line: + try: + number = int(line) + result = process_result(number) + print(result) + except ValueError: + print(f"Invalid entry on line {line_num}: '{line}'") + + except FileNotFoundError: + print(f"Error: File '{filename}' not found.") + except PermissionError: + print(f"Error: Not allowed to read '{filename}'.") + + +def main(): + """Run the main program menu and input handling.""" + print("Choose input method:") + print("1. Enter a number using the keyboard") + print("2. Read a number from a file") + + choice = input("Enter choice (1 or 2): ").strip() + + if choice == "1": + try: + num = int(input("Enter a number: ")) + result = process_result(num) + print(result) + except ValueError: + print("Invalid input. Please enter a valid integer.") + + elif choice == "2": + filename = input("Enter filename: ").strip() + process_file(filename) + + else: + print("Invalid choice.") + + +if __name__ == "__main__": + main() diff --git a/week1_projects/amandapanda00/armstrong_number_checker/numbers.txt b/week1_projects/amandapanda00/armstrong_number_checker/numbers.txt new file mode 100644 index 0000000..6a0fd9f --- /dev/null +++ b/week1_projects/amandapanda00/armstrong_number_checker/numbers.txt @@ -0,0 +1,9 @@ +abc +123 +153 +370 +456 +xyz +9474 +-45 +-153 \ No newline at end of file diff --git a/week1_projects/amandapanda00/armstrong_number_checker/test_main.py b/week1_projects/amandapanda00/armstrong_number_checker/test_main.py new file mode 100644 index 0000000..9507543 --- /dev/null +++ b/week1_projects/amandapanda00/armstrong_number_checker/test_main.py @@ -0,0 +1,19 @@ +from main import is_armstrong + + +def test_3_digit_armstrong(): + assert is_armstrong(153) + assert not is_armstrong(123) + + +def test_4_digit_armstrong(): + assert is_armstrong(9474) + assert not is_armstrong(9475) + + +def test_1_digit_armstrong(): + assert is_armstrong(5) + + +def test_negative_number(): + assert not is_armstrong(-153)