Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 125 additions & 0 deletions week1_projects/amandapanda00/armstrong_number_checker/README.md
Original file line number Diff line number Diff line change
@@ -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



93 changes: 93 additions & 0 deletions week1_projects/amandapanda00/armstrong_number_checker/main.py
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @amandapanda00 — thanks for the contribution! I reviewed week1_projects/amandapanda00/armstrong_number_checker/main.py. Please make the following changes to improve correctness, robustness, and maintainability:

  1. Fix module docstring
  • Change "sum of the cubes of its digits" to the general definition: an Armstrong number equals the sum of each digit raised to the power of the number of digits.
  1. Handle negative input
  • Reject negative integers (return False) or explicitly document that only non-negative integers are supported. Current code will crash on negative input because of the '-' character in str(number).

Suggested change:
def is_armstrong(number: int) -> bool:
if number < 0:
return False
digits = [int(d) for d in str(number)]
n = len(digits)
return sum(d ** n for d in digits) == number

  1. Improve file handling
  • Open files with explicit encoding (encoding="utf-8").
  • Prefer pathlib.Path for clearer checks (exists/is_file).
  • Keep existing FileNotFoundError/PermissionError handling but check path first to provide clearer messages.
  1. Make functions more testable
  • Keep is_armstrong pure (it already is).
  • Have process_result return the formatted string instead of printing directly; main() can print it. This makes unit testing easier.
  1. Input robustness and UX
  • Catch KeyboardInterrupt and EOFError in main to exit gracefully.
  • Validate filename input (strip and ignore empty input).
  • Consider rejecting lines that contain non-digit characters (or handle leading '+') and report which lines are invalid.
  1. Clean up comments and add type hints
  • Remove noisy inline comments like "# og had ** 3".
  • Add type hints for public functions (e.g., process_file(filename: str) -> None).
  • Improve docstrings (PEP 257 style).
  1. Tests and CI
  • Add unit tests (pytest or unittest) covering:
    • Typical Armstrong numbers: 153, 370, 9474
    • Non-Armstrong numbers
    • 0
    • Negative values
    • File input with invalid lines
  • Consider adding a simple GitHub Actions workflow to run tests.
  1. Optional improvements (nice-to-have)
  • Use argparse for CLI options (single number vs filename).
  • Limit maximum allowed digits/value to avoid CPU/memory DoS from huge inputs and report if input is too large.

Original file line number Diff line number Diff line change
@@ -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()
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
abc
123
153
370
456
xyz
9474
-45
-153
19 changes: 19 additions & 0 deletions week1_projects/amandapanda00/armstrong_number_checker/test_main.py
Original file line number Diff line number Diff line change
@@ -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)