From da34432c38af94381f43f403c967ca9fcdecc8e2 Mon Sep 17 00:00:00 2001 From: Medha Date: Mon, 23 Dec 2024 15:33:03 +0530 Subject: [PATCH 1/6] Add Kadane's Algorithm implementation --- .pre-commit-config.yaml | 1 + data_structures/arrays/kadanes_algorithm.py | 56 +++++++++++++++++++++ pyproject.toml | 45 +++++++++-------- 3 files changed, 81 insertions(+), 21 deletions(-) create mode 100644 data_structures/arrays/kadanes_algorithm.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0c8108ac55be..4e7c9eceb020 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -32,6 +32,7 @@ repos: rev: "v2.5.0" hooks: - id: pyproject-fmt + language_version: python3.12 - repo: local hooks: diff --git a/data_structures/arrays/kadanes_algorithm.py b/data_structures/arrays/kadanes_algorithm.py new file mode 100644 index 000000000000..446b1d6f0d10 --- /dev/null +++ b/data_structures/arrays/kadanes_algorithm.py @@ -0,0 +1,56 @@ +class KadaneAlgorithm: + """ + Kadane's Algorithm to find the maximum sum + of a contiguous subarray in a given array. + + Time Complexity: O(n) + Space Complexity: O(1) + + The function works efficiently with both positive and negative integers. + + Usage: + >>> kadane = KadaneAlgorithm() + >>> kadane.max_subarray_sum([1, 2, 3, -2, 5]) + 9 + >>> kadane.max_subarray_sum([-1, -2, -3, -4]) + -1 + >>> kadane.max_subarray_sum([1, 2, 3, 4]) + 10 + >>> kadane.max_subarray_sum([10, -10, 20, -5, 10]) + 25 + """ + + def __init__(self): + pass + + def max_subarray_sum(self, arr: list[int]) -> int: + """ + This function finds the maximum sum of a + contiguous subarray using Kadane's Algorithm. + + :param arr: List of integers. + :return: Maximum sum of a contiguous subarray. + + Raises: + ValueError: If the input array is empty. + + >>> kadane = KadaneAlgorithm() + >>> kadane.max_subarray_sum([1, 2, 3, -2, 5]) + 9 + >>> kadane.max_subarray_sum([-1, -2, -3, -4]) + -1 + >>> kadane.max_subarray_sum([1, 2, 3, 4]) + 10 + >>> kadane.max_subarray_sum([10, -10, 20, -5, 10]) + 25 + """ + if not arr: + raise ValueError("Input array cannot be empty.") + + max_sum = current_sum = arr[0] + + for num in arr[1:]: + current_sum = max(num, current_sum + num) + max_sum = max(max_sum, current_sum) + + return max_sum diff --git a/pyproject.toml b/pyproject.toml index 7b7176705c44..6fdc82564f3b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,30 @@ euler-validate = [ [tool.ruff] target-version = "py313" +[tool.codespell] +ignore-words-list = "3rt,ans,bitap,crate,damon,fo,followings,hist,iff,kwanza,manuel,mater,secant,som,sur,tim,toi,zar" +skip = "./.*,*.json,*.lock,ciphers/prehistoric_men.txt,project_euler/problem_022/p022_names.txt,pyproject.toml,strings/dictionary.txt,strings/words.txt" + +[tool.pytest.ini_options] +markers = [ + "mat_ops: mark a test as utilizing matrix operations.", +] +addopts = [ + "--durations=10", + "--doctest-modules", + "--showlocals", +] + +[tool.coverage.report] +omit = [ + ".env/*", + "project_euler/*", +] +sort = "Cover" + +[tool.mypy] +python_version = "3.12" + output-format = "full" lint.select = [ # https://beta.ruff.rs/docs/rules @@ -158,27 +182,6 @@ lint.pylint.max-branches = 20 # default: 12 lint.pylint.max-returns = 8 # default: 6 lint.pylint.max-statements = 88 # default: 50 -[tool.codespell] -ignore-words-list = "3rt,ans,bitap,crate,damon,fo,followings,hist,iff,kwanza,manuel,mater,secant,som,sur,tim,toi,zar" -skip = "./.*,*.json,*.lock,ciphers/prehistoric_men.txt,project_euler/problem_022/p022_names.txt,pyproject.toml,strings/dictionary.txt,strings/words.txt" - -[tool.pytest.ini_options] -markers = [ - "mat_ops: mark a test as utilizing matrix operations.", -] -addopts = [ - "--durations=10", - "--doctest-modules", - "--showlocals", -] - -[tool.coverage.report] -omit = [ - ".env/*", - "project_euler/*", -] -sort = "Cover" - [tool.sphinx-pyproject] copyright = "2014, TheAlgorithms" autoapi_dirs = [ From dd311fbf5dd22ff20b23e311920b58fea25561cb Mon Sep 17 00:00:00 2001 From: Medha Date: Mon, 23 Dec 2024 15:51:04 +0530 Subject: [PATCH 2/6] Add SECURITY.md file for vulnerability reporting --- security.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 security.md diff --git a/security.md b/security.md new file mode 100644 index 000000000000..da2a591a0e70 --- /dev/null +++ b/security.md @@ -0,0 +1,50 @@ +# Security Policy + +## Reporting a Vulnerability + +If you believe you've found a security vulnerability in **TheAlgorithms/Python**, please follow these steps to report it: + +1. **Do not open an issue or pull request**: To ensure that the vulnerability is handled responsibly and securely, please **do not create a public issue or PR**. This will allow us to address the issue in a secure manner before any information becomes public. + +2. **Contact the maintainers**: Send a detailed description of the vulnerability to **[security@thealgorithms.com]**. Please include the following information: + - A description of the vulnerability. + - Steps to reproduce the issue, if applicable. + - Any relevant code or configuration files. + - Your contact details (optional). + + If you don't have a direct contact, feel free to create a private email or open a responsible disclosure channel via GitHub Discussions, with a direct request to the maintainers. + +3. **Timeline for Response**: We strive to respond to all security reports within 48 hours. The severity of the issue may affect the response time. + +## Security Measures + +- **Vulnerability Fixes**: Once a vulnerability is identified and reported, we will work to fix it as soon as possible. We will issue a patch release if necessary. +- **Security Advisory**: We will provide a public security advisory with the details of the vulnerability, once the patch has been released. This advisory will include steps for users to mitigate the issue. + +## Secure Coding Practices + +We follow the best practices in secure coding to ensure our code is resilient against common security vulnerabilities, including but not limited to: +- Input validation and sanitization +- Secure handling of sensitive data (e.g., passwords, API keys) +- Proper encryption and decryption mechanisms +- Avoiding common vulnerabilities such as SQL injection, cross-site scripting (XSS), and buffer overflows + +## Data Handling + +We recommend that contributors and users do not store sensitive data (such as passwords or private keys) in the repository. Any sensitive information should be handled securely, using appropriate encryption or key management tools. + +## Patching and Updates + +We encourage contributors to regularly update dependencies to minimize security vulnerabilities in third-party libraries. + +## Additional Resources + +For more information on secure coding practices and related resources, you can refer to: +- [OWASP Top 10](https://owasp.org/www-project-top-ten/) +- [CWE - Common Weakness Enumeration](https://cwe.mitre.org/) + +## Responsible Disclosure + +We adhere to responsible disclosure practices and ask that any vulnerabilities be reported privately. We are committed to working with the security community to address any issues as quickly and efficiently as possible. + +--- \ No newline at end of file From 5b4b242ad7bca043cd6dc37df43a6f923a5884c7 Mon Sep 17 00:00:00 2001 From: Medha Date: Mon, 23 Dec 2024 16:58:12 +0530 Subject: [PATCH 3/6] added butterfy_pattern under strings folder --- strings/butterfly_pattern.py | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 strings/butterfly_pattern.py diff --git a/strings/butterfly_pattern.py b/strings/butterfly_pattern.py new file mode 100644 index 000000000000..af851e65c876 --- /dev/null +++ b/strings/butterfly_pattern.py @@ -0,0 +1,37 @@ +def print_butterfly(n: int) -> None: + """ + Prints a butterfly pattern using the character '*' based on the input size. + + The butterfly pattern has a symmetrical structure with an upper and lower half. + + :param n: The size of the butterfly (side length). + :return: None + + Example: + >>> print_butterfly(5) + * * + ** ** + *** *** + **** **** + ********* + **** **** + *** *** + ** ** + * * + """ + # Upper half of the butterfly + for i in range(1, n + 1): + print("*" * i, end="") + print(" " * (2 * (n - i)), end="") + print("*" * i) + + # Lower half of the butterfly + for i in range(n, 0, -1): + print("*" * i, end="") + print(" " * (2 * (n - i)), end="") + print("*" * i) + + +# Ask the user for input and print the butterfly +n = int(input("Enter the value of n: ")) +print_butterfly(n) From ae70a55c8ee0687e0bfed41b77247a00d7f640c5 Mon Sep 17 00:00:00 2001 From: Medha Date: Mon, 23 Dec 2024 17:06:39 +0530 Subject: [PATCH 4/6] added butterfy_pattern under strings folder --- strings/butterfly_pattern.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/strings/butterfly_pattern.py b/strings/butterfly_pattern.py index af851e65c876..893724b0688a 100644 --- a/strings/butterfly_pattern.py +++ b/strings/butterfly_pattern.py @@ -30,8 +30,3 @@ def print_butterfly(n: int) -> None: print("*" * i, end="") print(" " * (2 * (n - i)), end="") print("*" * i) - - -# Ask the user for input and print the butterfly -n = int(input("Enter the value of n: ")) -print_butterfly(n) From 2a11d8be2fab25958350157abadfd067bc6df235 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 23 Dec 2024 07:09:57 -0500 Subject: [PATCH 5/6] Delete data_structures/arrays/kadanes_algorithm.py --- data_structures/arrays/kadanes_algorithm.py | 56 --------------------- 1 file changed, 56 deletions(-) delete mode 100644 data_structures/arrays/kadanes_algorithm.py diff --git a/data_structures/arrays/kadanes_algorithm.py b/data_structures/arrays/kadanes_algorithm.py deleted file mode 100644 index 446b1d6f0d10..000000000000 --- a/data_structures/arrays/kadanes_algorithm.py +++ /dev/null @@ -1,56 +0,0 @@ -class KadaneAlgorithm: - """ - Kadane's Algorithm to find the maximum sum - of a contiguous subarray in a given array. - - Time Complexity: O(n) - Space Complexity: O(1) - - The function works efficiently with both positive and negative integers. - - Usage: - >>> kadane = KadaneAlgorithm() - >>> kadane.max_subarray_sum([1, 2, 3, -2, 5]) - 9 - >>> kadane.max_subarray_sum([-1, -2, -3, -4]) - -1 - >>> kadane.max_subarray_sum([1, 2, 3, 4]) - 10 - >>> kadane.max_subarray_sum([10, -10, 20, -5, 10]) - 25 - """ - - def __init__(self): - pass - - def max_subarray_sum(self, arr: list[int]) -> int: - """ - This function finds the maximum sum of a - contiguous subarray using Kadane's Algorithm. - - :param arr: List of integers. - :return: Maximum sum of a contiguous subarray. - - Raises: - ValueError: If the input array is empty. - - >>> kadane = KadaneAlgorithm() - >>> kadane.max_subarray_sum([1, 2, 3, -2, 5]) - 9 - >>> kadane.max_subarray_sum([-1, -2, -3, -4]) - -1 - >>> kadane.max_subarray_sum([1, 2, 3, 4]) - 10 - >>> kadane.max_subarray_sum([10, -10, 20, -5, 10]) - 25 - """ - if not arr: - raise ValueError("Input array cannot be empty.") - - max_sum = current_sum = arr[0] - - for num in arr[1:]: - current_sum = max(num, current_sum + num) - max_sum = max(max_sum, current_sum) - - return max_sum From 57805c2a8373f6bb8eb15cabb48f01731f23a7ea Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 23 Dec 2024 07:44:12 -0500 Subject: [PATCH 6/6] Delete pyproject.toml --- pyproject.toml | 267 ------------------------------------------------- 1 file changed, 267 deletions(-) delete mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 6fdc82564f3b..000000000000 --- a/pyproject.toml +++ /dev/null @@ -1,267 +0,0 @@ -[project] -name = "thealgorithms-python" -version = "0.0.1" -description = "TheAlgorithms in Python" -authors = [ { name = "TheAlgorithms Contributors" } ] -requires-python = ">=3.13" -classifiers = [ - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.13", -] -dependencies = [ - "beautifulsoup4>=4.12.3", - "fake-useragent>=1.5.1", - "imageio>=2.36.1", - "keras>=3.7", - "lxml>=5.3", - "matplotlib>=3.9.3", - "numpy>=2.1.3", - "opencv-python>=4.10.0.84", - "pandas>=2.2.3", - "pillow>=11", - "requests>=2.32.3", - "rich>=13.9.4", - "scikit-learn>=1.5.2", - "sphinx-pyproject>=0.3", - "statsmodels>=0.14.4", - "sympy>=1.13.3", - "tweepy>=4.14", - "typing-extensions>=4.12.2", - "xgboost>=2.1.3", -] - -[dependency-groups] -test = [ - "pytest>=8.3.4", - "pytest-cov>=6", -] - -docs = [ - "myst-parser>=4", - "sphinx-autoapi>=3.4", - "sphinx-pyproject>=0.3", -] -euler-validate = [ - "numpy>=2.1.3", - "requests>=2.32.3", -] - -[tool.ruff] -target-version = "py313" - -[tool.codespell] -ignore-words-list = "3rt,ans,bitap,crate,damon,fo,followings,hist,iff,kwanza,manuel,mater,secant,som,sur,tim,toi,zar" -skip = "./.*,*.json,*.lock,ciphers/prehistoric_men.txt,project_euler/problem_022/p022_names.txt,pyproject.toml,strings/dictionary.txt,strings/words.txt" - -[tool.pytest.ini_options] -markers = [ - "mat_ops: mark a test as utilizing matrix operations.", -] -addopts = [ - "--durations=10", - "--doctest-modules", - "--showlocals", -] - -[tool.coverage.report] -omit = [ - ".env/*", - "project_euler/*", -] -sort = "Cover" - -[tool.mypy] -python_version = "3.12" - -output-format = "full" -lint.select = [ - # https://beta.ruff.rs/docs/rules - "A", # flake8-builtins - "ARG", # flake8-unused-arguments - "ASYNC", # flake8-async - "B", # flake8-bugbear - "BLE", # flake8-blind-except - "C4", # flake8-comprehensions - "C90", # McCabe cyclomatic complexity - "DJ", # flake8-django - "DTZ", # flake8-datetimez - "E", # pycodestyle - "EM", # flake8-errmsg - "EXE", # flake8-executable - "F", # Pyflakes - "FA", # flake8-future-annotations - "FLY", # flynt - "G", # flake8-logging-format - "I", # isort - "ICN", # flake8-import-conventions - "INP", # flake8-no-pep420 - "INT", # flake8-gettext - "ISC", # flake8-implicit-str-concat - "N", # pep8-naming - "NPY", # NumPy-specific rules - "PD", # pandas-vet - "PGH", # pygrep-hooks - "PIE", # flake8-pie - "PL", # Pylint - "PT", # flake8-pytest-style - "PYI", # flake8-pyi - "RSE", # flake8-raise - "RUF", # Ruff-specific rules - "S", # flake8-bandit - "SIM", # flake8-simplify - "SLF", # flake8-self - "T10", # flake8-debugger - "TD", # flake8-todos - "TID", # flake8-tidy-imports - "UP", # pyupgrade - "W", # pycodestyle - "YTT", # flake8-2020 - # "ANN", # flake8-annotations -- FIX ME? - # "COM", # flake8-commas -- DO NOT FIX - # "D", # pydocstyle -- FIX ME? - # "ERA", # eradicate -- DO NOT FIX - # "FBT", # flake8-boolean-trap # FIX ME - # "PTH", # flake8-use-pathlib # FIX ME - # "Q", # flake8-quotes - # "RET", # flake8-return # FIX ME? - # "T20", # flake8-print - # "TCH", # flake8-type-checking - # "TRY", # tryceratops -] -lint.ignore = [ - # `ruff rule S101` for a description of that rule - "B904", # Within an `except` clause, raise exceptions with `raise ... from err` -- FIX ME - "B905", # `zip()` without an explicit `strict=` parameter -- FIX ME - "EM101", # Exception must not use a string literal, assign to variable first - "EXE001", # Shebang is present but file is not executable -- DO NOT FIX - "G004", # Logging statement uses f-string - "ISC001", # Conflicts with ruff format -- DO NOT FIX - "PLC1901", # `{}` can be simplified to `{}` as an empty string is falsey - "PLW060", # Using global for `{name}` but no assignment is done -- DO NOT FIX - "PLW2901", # PLW2901: Redefined loop variable -- FIX ME - "PT011", # `pytest.raises(Exception)` is too broad, set the `match` parameter or use a more specific exception - "PT018", # Assertion should be broken down into multiple parts - "S101", # Use of `assert` detected -- DO NOT FIX - "S311", # Standard pseudo-random generators are not suitable for cryptographic purposes -- FIX ME - "SLF001", # Private member accessed: `_Iterator` -- FIX ME - "UP038", # Use `X | Y` in `{}` call instead of `(X, Y)` -- DO NOT FIX -] - -lint.per-file-ignores."data_structures/hashing/tests/test_hash_map.py" = [ - "BLE001", -] -lint.per-file-ignores."hashes/enigma_machine.py" = [ - "BLE001", -] -lint.per-file-ignores."machine_learning/sequential_minimum_optimization.py" = [ - "SIM115", -] -lint.per-file-ignores."matrix/sherman_morrison.py" = [ - "SIM103", -] -lint.per-file-ignores."other/l*u_cache.py" = [ - "RUF012", -] -lint.per-file-ignores."physics/newtons_second_law_of_motion.py" = [ - "BLE001", -] -lint.per-file-ignores."project_euler/problem_099/sol1.py" = [ - "SIM115", -] -lint.per-file-ignores."sorts/external_sort.py" = [ - "SIM115", -] -lint.mccabe.max-complexity = 17 # default: 10 -lint.pylint.allow-magic-value-types = [ - "float", - "int", - "str", -] -lint.pylint.max-args = 10 # default: 5 -lint.pylint.max-branches = 20 # default: 12 -lint.pylint.max-returns = 8 # default: 6 -lint.pylint.max-statements = 88 # default: 50 - -[tool.sphinx-pyproject] -copyright = "2014, TheAlgorithms" -autoapi_dirs = [ - "audio_filters", - "backtracking", - "bit_manipulation", - "blockchain", - "boolean_algebra", - "cellular_automata", - "ciphers", - "compression", - "computer_vision", - "conversions", - "data_structures", - "digital_image_processing", - "divide_and_conquer", - "dynamic_programming", - "electronics", - "file_transfer", - "financial", - "fractals", - "fuzzy_logic", - "genetic_algorithm", - "geodesy", - "geometry", - "graphics", - "graphs", - "greedy_methods", - "hashes", - "knapsack", - "linear_algebra", - "linear_programming", - "machine_learning", - "maths", - "matrix", - "networking_flow", - "neural_network", - "other", - "physics", - "project_euler", - "quantum", - "scheduling", - "searches", - "sorts", - "strings", - "web_programming", -] -autoapi_member_order = "groupwise" -# autoapi_python_use_implicit_namespaces = true -exclude_patterns = [ - ".*/*", - "docs/", -] -extensions = [ - "autoapi.extension", - "myst_parser", -] -html_static_path = [ "_static" ] -html_theme = "alabaster" -myst_enable_extensions = [ - "amsmath", - "attrs_inline", - "colon_fence", - "deflist", - "dollarmath", - "fieldlist", - "html_admonition", - "html_image", - # "linkify", - "replacements", - "smartquotes", - "strikethrough", - "substitution", - "tasklist", -] -myst_fence_as_directive = [ - "include", -] -templates_path = [ "_templates" ] -[tool.sphinx-pyproject.source_suffix] -".rst" = "restructuredtext" -# ".txt" = "markdown" -".md" = "markdown"