diff --git a/.vscode/settings.json b/.vscode/settings.json index 058679944..d3ba05557 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -114,7 +114,17 @@ // Enable/disable update table of contents on save "markdown.extension.toc.updateOnSave": false, + "[python]": { - "editor.defaultFormatter": "ms-python.black-formatter" - } + "editor.defaultFormatter": "charliermarsh.ruff", + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll.ruff": "explicit", + "source.organizeImports.ruff": "explicit" + } + }, + "cSpell.words": [ + "Falaq", + "Youniss" + ] } diff --git a/solutions/cumulative_sum.py b/solutions/cumulative_sum.py new file mode 100644 index 000000000..2e77fb9d0 --- /dev/null +++ b/solutions/cumulative_sum.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Module: cumulative_sum + +Description: + This module provides a function to calculate the cumulative sum of + a list of numbers(integers\float). It is useful for applications requiring progressive + accumulation of values, such as financial calculations, data analysis, + or custom mathematical operations. + +Module Contents: + - cumulative_sum(numbers: list) -> list: + Computes and returns a list of cumulative sums from the input list. + +Author: Falaq Youniss +Date: 29/12/2024 +""" + + +def cumulative_sum(numbers: list) -> list: + """ + Computes the cumulative sum of a list of numbers. + + Args: + numbers (list): A list of numeric values (integers or floats). + + Returns: + list: A list where each element is the cumulative sum up to that index. + + Raises: + AssertionError: + - If the input is not a list. + - If the list contains non-numeric values. + - If the input is `None`. + + >>> cumulative_sum([1, 2, 3, 4]) + [1, 3, 6, 10] + >>> cumulative_sum([-1, -2, -3, -4]) + [-1, -3, -6, -10] + >>> cumulative_sum([1.0, 2.0, 3.0, 4.0]) + [1.0, 3.0, 6.0, 10.0] + """ + # Validate input + assert numbers is not None, "Input cannot be None." + assert isinstance(numbers, list), "Input must be a list of numeric values." + assert all( + isinstance(num, (int, float)) for num in numbers + ), "All elements in the list must be numeric." + # Compute cumulative sums + cumulative_list = [] + current_sum = 0 + for num in numbers: + current_sum += num + cumulative_list.append(current_sum) + + return cumulative_list diff --git a/solutions/is_positive.py b/solutions/is_positive.py new file mode 100644 index 000000000..37cb1015c --- /dev/null +++ b/solutions/is_positive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on XX XX XX + +A module for checking if an integer is positive. + +@author: Luyando .E. Chitindi +""" + + +def is_positive(number: int) -> bool: + """ + This checks if an integer is positive. + + Parameters: + number: int, the number to check + + Returns -> bool: + True if the number is positive, false otherwise. + + Raises: + AssertionError: if the input is not an integer + + Example: + >>> is_positive(4) + True + >>> is_positive(-3) + False + >>> is_positive(0) + False + >>> is_positive("hello") + Traceback (most recent call last): + ... + AssertionError: Input must be an integer. + """ + assert isinstance(number, int), "Input must be an integer" + return number > 0 diff --git a/solutions/tests/__init__.py b/solutions/tests/__init__.py index 8b1378917..e69de29bb 100644 --- a/solutions/tests/__init__.py +++ b/solutions/tests/__init__.py @@ -1 +0,0 @@ - diff --git a/solutions/tests/test_cumulative_sum.py b/solutions/tests/test_cumulative_sum.py new file mode 100644 index 000000000..a1c29af72 --- /dev/null +++ b/solutions/tests/test_cumulative_sum.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Module: test_cumulative_sum + +Description: + This module contains test cases for the `cumulative_sum` function defined + in the `cumulative_sum.py` module. It tests the function's behavior with + various input scenarios, ensuring that it handles different edge cases and + returns the expected cumulative sums. + +Test Categories: + - Standard cases: List of positive integers, negative integers, and floating-point numbers. + - Edge cases: Empty list, single-element list, list with zeros, large number list. + - Defensive tests: None input, Non-list inputs, list with non-numeric elements. + +Author: Falaq Youniss +Date: 29/12/2024 +""" + +import unittest +from ..cumulative_sum import cumulative_sum + + +class TestCumulativeSum(unittest.TestCase): + """Test for cumulative_sum function that handles different cases""" + + # Standard test cases + def test_positive_int(self): + """It should return a cumulative list of positive integers.""" + self.assertEqual(cumulative_sum([1, 2, 3, 4]), [1, 3, 6, 10]) + + def test_negative_int(self): + """It should return a cumulative list of negative integers.""" + self.assertEqual(cumulative_sum([-1, -2, -3, -4]), [-1, -3, -6, -10]) + + def test_positive_float(self): + """It should return a cumulative list of positive floats.""" + self.assertEqual(cumulative_sum([1.0, 2.0, 3.0, 4.0]), [1.0, 3.0, 6.0, 10.0]) + + def test_negative_float(self): + """It should return a cumulative list of negative floats.""" + self.assertEqual( + cumulative_sum([-1.0, -2.0, -3.0, -4.0]), [-1.0, -3.0, -6.0, -10.0] + ) + + def test_positive_negative(self): + """It should return a cumulative list of negative and positive integers.""" + self.assertEqual(cumulative_sum([-1, 2, -3, 4]), [-1, 1, -2, 2]) + + def test_integer_float(self): + """It should return a cumulative list of integers and floats.""" + self.assertEqual(cumulative_sum([1.0, 2, 3.0, 4]), [1, 3, 6.0, 10.0]) + + def test_combination(self): + """It should return a cumulative list of mixed positive and negative integers/floats.""" + self.assertEqual(cumulative_sum([1.0, -2, -3.0, 4]), [1, -1, -4, 0]) + + def test_same(self): + """It should return a cumulative list of positive integers.""" + self.assertEqual(cumulative_sum([3, 3, 3]), [3, 6, 9]) + + # Edge cases + def test_zero(self): + """It should return a list of zeros.""" + self.assertEqual(cumulative_sum([0, 0, 0, 0]), [0, 0, 0, 0]) + + def test_empty(self): + """It should return an empty list.""" + self.assertEqual(cumulative_sum([]), []) + + def test_one(self): + """It should return the same single-item list.""" + self.assertEqual(cumulative_sum([1]), [1]) + + def test_large_numbers(self): + """It should correctly handle large numbers.""" + self.assertEqual(cumulative_sum([1e6, 2e6, 3e6]), [1e6, 3e6, 6e6]) + + # Defensive tests + def test_none(self): + """It should raise AssertionError for None input.""" + with self.assertRaises(AssertionError): + cumulative_sum(None) + + def test_not_list(self): + """It should raise AssertionError for non-list input.""" + with self.assertRaises(AssertionError): + cumulative_sum("hello") + + def test_not_num(self): + """It should raise AssertionError for non-numeric list elements.""" + with self.assertRaises(AssertionError): + cumulative_sum([1, "cat", 3]) diff --git a/solutions/tests/test_is_positive.py b/solutions/tests/test_is_positive.py new file mode 100644 index 000000000..cadb586d0 --- /dev/null +++ b/solutions/tests/test_is_positive.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Unit tests for the is_positive function. + +@author: Luyando .E. Chitindi +""" + +import unittest +from solutions.is_positive import is_positive + + +class TestIsPositive(unittest.TestCase): + """Test the is_positive function""" + + def test_positive_number(self): + """It should evaluate 4 to True""" + actual = is_positive(4) + expected = True + self.assertEqual(actual, expected) + + def test_negative_number(self): + """It should evaluate -3 to False""" + actual = is_positive(-3) + expected = False + self.assertEqual(actual, expected) + + def test_zero(self): + """It should evaluate 0 to False""" + actual = is_positive(0) + expected = False + self.assertEqual(actual, expected) + + def test_non_integer_input(self): + """It should raise an assertion error if the argument is not an integer""" + with self.assertRaises(AssertionError): + is_positive(3.5) + + with self.assertRaises(AssertionError): + is_positive("string") + + +if __name__ == "__main__": + unittest.main()