From 17b887287e9b47adaa201227439a6fda74b879b6 Mon Sep 17 00:00:00 2001 From: "exercism-solutions-syncer[bot]" <211797793+exercism-solutions-syncer[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 05:28:19 +0000 Subject: [PATCH 1/6] [Sync Iteration] python/leap/1 --- solutions/python/leap/1/leap.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 solutions/python/leap/1/leap.py diff --git a/solutions/python/leap/1/leap.py b/solutions/python/leap/1/leap.py new file mode 100644 index 0000000..dd1abb3 --- /dev/null +++ b/solutions/python/leap/1/leap.py @@ -0,0 +1,32 @@ +"""Solution for Leap exercise.""" + + +def leap_year(year: int) -> bool: + """ + Determine whether a given year is a leap year. + + A leap year (in the Gregorian calendar) occurs: + - In every year that is evenly divisible by 4. + - Unless the year is evenly divisible by 100, + in which case it's only a leap year if the + year is also evenly divisible by 400. + + Some examples: + + - 1997 was not a leap year as it's not divisible by 4. + - 1900 was not a leap year as it's not divisible by 400. + - 2000 was a leap year! + + :param year: any year + :type year: int + :return: whether a given year is a leap year + :rtype: bool + """ + if year % 4 == 0: + if year % 100 == 0: + if year % 400 == 0: + return True + return False + return True + + return False From 8b3679c857950135b2cdf05fd0dd9a740c9f470b Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Mon, 25 Aug 2025 22:18:20 -0700 Subject: [PATCH 2/6] Ruff --- .github/workflows/ruff.yml | 21 +++++++++++++ pyproject.toml | 60 +++++++++++++++++++++++++++++++++++++ requirements.txt | Bin 470 -> 496 bytes 3 files changed, 81 insertions(+) create mode 100644 .github/workflows/ruff.yml create mode 100644 pyproject.toml diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml new file mode 100644 index 0000000..f01a2a3 --- /dev/null +++ b/.github/workflows/ruff.yml @@ -0,0 +1,21 @@ +name: Ruff Lint and Format + +on: [push, pull_request] + +jobs: + ruff: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: '3.12' + - name: Install Ruff + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + - name: Run Ruff lint + run: ruff check --output-format=github . + - name: Run Ruff format check + run: ruff format --check . \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..50718dd --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,60 @@ +[tool.ruff] +# Exclude commonly ignored directories +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".ipynb_checkpoints", + ".mypy_cache", + ".nox", + ".pants.d", + ".pyenv", + ".pytest_cache", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + ".vscode", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "site-packages", + "venv", +] + +# Line length and indentation settings, same as Black +line-length = 88 +indent-width = 4 + +# Set target version to Python 3.12 +target-version = "py312" + +[tool.ruff.lint] +# Enable Pyflakes (F) and a subset of pycodestyle (E) codes by default +select = ["E4", "E7", "E9", "F"] +ignore = [] + +# Allow fixes for all enabled rules when --fix is provided +fixable = ["ALL"] +unfixable = [] + +# Allow unused variables when underscore-prefixed +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" + +[tool.ruff.format] +# Enable formatter settings, similar to Black +quote-style = "double" +indent-style = "space" +skip-magic-trailing-comma = false +line-ending = "auto" + +# Auto-formatting of code examples in docstrings is currently disabled by default +docstring-code-format = false +docstring-code-line-length = "dynamic" \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index ad58882afce5f0a1f504e0fdc86c550ca687c885..44bbf70f2f84f6ba7c278ad0f37467689713853d 100644 GIT binary patch delta 37 mcmcb{{DFDH7DmY;hEj$!AhZQS0|q??Lk1%-X)t*`qcQ-w!w4<_ delta 16 Xcmeyse2sa-7RJe!80A=a8Mqh#H}C|} From a77d89126905e244a44805e202d4d7a4c62e4b6c Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Mon, 25 Aug 2025 22:20:32 -0700 Subject: [PATCH 3/6] Update pyproject.toml --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 50718dd..36d7520 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,6 +27,9 @@ exclude = [ "node_modules", "site-packages", "venv", + "tests/", + "*_test.py", + "test_*.py" ] # Line length and indentation settings, same as Black From 60880d231426f80126278541197c4cc79cb99eff Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Mon, 25 Aug 2025 22:21:41 -0700 Subject: [PATCH 4/6] Update pyproject.toml --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 36d7520..8418471 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,8 @@ exclude = [ "venv", "tests/", "*_test.py", - "test_*.py" + "test_*.py", + "solutions/" ] # Line length and indentation settings, same as Black From a026afd0c56f118cbfc7c7fbdf252ad8c3ecd35d Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Mon, 25 Aug 2025 22:26:35 -0700 Subject: [PATCH 5/6] Ruff format changes --- black-jack/black_jack.py | 10 +++++----- card-games/lists.py | 3 +-- chaitanas-colossal-coaster/list_methods.py | 23 ++++++++++------------ currency-exchange/exchange.py | 22 ++++++++------------- ghost-gobble-arcade-game/arcade_game.py | 6 +++--- grains/grains.py | 2 +- guidos-gorgeous-lasagna/lasagna.py | 7 +++---- hello-world/hello_world.py | 2 +- little-sisters-vocab/strings.py | 10 +++++----- making-the-grade/loops.py | 14 +++++++------ meltdown-mitigation/conditionals.py | 22 ++++++++++++--------- triangle/triangle.py | 8 +++++--- 12 files changed, 63 insertions(+), 66 deletions(-) diff --git a/black-jack/black_jack.py b/black-jack/black_jack.py index fb9dec8..4d9a3fe 100644 --- a/black-jack/black_jack.py +++ b/black-jack/black_jack.py @@ -17,10 +17,10 @@ def value_of_card(card) -> int: 2. 'A' (ace card) = 1 3. '2' - '10' = numerical value. """ - if card in 'JKQ': + if card in "JKQ": return 10 - if card == 'A': + if card == "A": return 1 return int(card) @@ -62,7 +62,7 @@ def value_of_ace(card_one, card_two) -> int: total: int = value_of_card(card_one) + value_of_card(card_two) # Hint: if we already have an ace in hand, then the value for # the upcoming ace would be 1. - if card_one == 'A' or card_two == 'A': + if card_one == "A" or card_two == "A": return 1 # The value of the hand with the ace needs to be as high as # possible without going over 21. @@ -89,10 +89,10 @@ def is_blackjack(card_one, card_two) -> bool: """ # If a player is dealt an ace (A) and a ten-card (10, K, Q, or J) # as their first two cards, then the player has a score of 21. - if card_one == 'A' and card_two in ('J', 'Q', 'K', '10'): + if card_one == "A" and card_two in ("J", "Q", "K", "10"): return True - if card_two == 'A' and card_one in ('J', 'Q', 'K', '10'): + if card_two == "A" and card_one in ("J", "Q", "K", "10"): return True return False diff --git a/card-games/lists.py b/card-games/lists.py index 55f76fc..ba00613 100644 --- a/card-games/lists.py +++ b/card-games/lists.py @@ -15,8 +15,7 @@ def get_rounds(number: int) -> list[int]: return [number, number + 1, number + 2] -def concatenate_rounds(rounds_1: list[int], - rounds_2: list[int]) -> list[int]: +def concatenate_rounds(rounds_1: list[int], rounds_2: list[int]) -> list[int]: """ Concatenate two lists of round numbers. diff --git a/chaitanas-colossal-coaster/list_methods.py b/chaitanas-colossal-coaster/list_methods.py index 029b503..4e24015 100644 --- a/chaitanas-colossal-coaster/list_methods.py +++ b/chaitanas-colossal-coaster/list_methods.py @@ -1,10 +1,12 @@ """Functions to manage and organize queues at Chaitana's roller coaster.""" -def add_me_to_the_queue(express_queue: list[str], - normal_queue: list[str], - ticket_type: int, - person_name: str) -> list[str]: +def add_me_to_the_queue( + express_queue: list[str], + normal_queue: list[str], + ticket_type: int, + person_name: str, +) -> list[str]: """ Add a person to the 'express' or 'normal' queue depending on the ticket number. @@ -22,8 +24,7 @@ def add_me_to_the_queue(express_queue: list[str], return normal_queue -def find_my_friend(queue: list[str], - friend_name: str) -> int: +def find_my_friend(queue: list[str], friend_name: str) -> int: """ Search the queue for a name and return their queue position (index). @@ -34,9 +35,7 @@ def find_my_friend(queue: list[str], return queue.index(friend_name) -def add_me_with_my_friends(queue: list[str], - index: int, - person_name: str) -> list[str]: +def add_me_with_my_friends(queue: list[str], index: int, person_name: str) -> list[str]: """ Insert the late arrival's name at a specific index of the queue. @@ -49,8 +48,7 @@ def add_me_with_my_friends(queue: list[str], return queue -def remove_the_mean_person(queue: list[str], - person_name: str) -> list[str]: +def remove_the_mean_person(queue: list[str], person_name: str) -> list[str]: """ Remove the mean person from the queue by the provided name. @@ -62,8 +60,7 @@ def remove_the_mean_person(queue: list[str], return queue -def how_many_namefellows(queue: list[str], - person_name: str) -> int: +def how_many_namefellows(queue: list[str], person_name: str) -> int: """ Count how many times the provided name appears in the queue. diff --git a/currency-exchange/exchange.py b/currency-exchange/exchange.py index ee23d07..25025a1 100644 --- a/currency-exchange/exchange.py +++ b/currency-exchange/exchange.py @@ -9,8 +9,7 @@ """ -def exchange_money(budget: float, - exchange_rate: float) -> float: +def exchange_money(budget: float, exchange_rate: float) -> float: """ Return the value of the exchanged currency. @@ -24,8 +23,7 @@ def exchange_money(budget: float, return budget / exchange_rate -def get_change(budget: float, - exchanging_value: float) -> float: +def get_change(budget: float, exchanging_value: float) -> float: """ Return the amount of money that "is left" from the budget. @@ -36,8 +34,7 @@ def get_change(budget: float, return budget - exchanging_value # pylint: disable=R0801 -def get_value_of_bills(denomination: float, - number_of_bills: float) -> float: +def get_value_of_bills(denomination: float, number_of_bills: float) -> float: """ Return only the total value of the bills (excluding fractional amounts) the booth would give back. @@ -52,8 +49,7 @@ def get_value_of_bills(denomination: float, return denomination * number_of_bills -def get_number_of_bills(amount: float, - denomination: int) -> int: +def get_number_of_bills(amount: float, denomination: int) -> int: """ Return the _number of currency bills_ that you can receive within the given _amount_. @@ -64,8 +60,7 @@ def get_number_of_bills(amount: float, return int(amount // denomination) -def get_leftover_of_bills(amount: float, - denomination: int) -> float: +def get_leftover_of_bills(amount: float, denomination: int) -> float: """ Return the _leftover amount_ that cannot be returned from your starting _amount_ given the denomination of bills. @@ -78,10 +73,9 @@ def get_leftover_of_bills(amount: float, # pylint: disable=R0801 -def exchangeable_value(budget: float, - exchange_rate: float, - spread: int, - denomination: int) -> int: +def exchangeable_value( + budget: float, exchange_rate: float, spread: int, denomination: int +) -> int: """ Return the maximum value of the new currency after calculating the *exchange rate* plus the *spread*. diff --git a/ghost-gobble-arcade-game/arcade_game.py b/ghost-gobble-arcade-game/arcade_game.py index eb5fe64..3cb4bc2 100644 --- a/ghost-gobble-arcade-game/arcade_game.py +++ b/ghost-gobble-arcade-game/arcade_game.py @@ -34,9 +34,9 @@ def lose(power_pellet_active: bool, touching_ghost: bool) -> bool: return touching_ghost and not power_pellet_active -def win(has_eaten_all_dots: bool, - power_pellet_active: bool, - touching_ghost: bool) -> bool: +def win( + has_eaten_all_dots: bool, power_pellet_active: bool, touching_ghost: bool +) -> bool: """ Trigger the victory event when all dots have been eaten. diff --git a/grains/grains.py b/grains/grains.py index 277079e..b86139f 100644 --- a/grains/grains.py +++ b/grains/grains.py @@ -31,4 +31,4 @@ def total() -> int: :rtype: int """ # return sum(square(sqr) for sqr in range(1, 65)) - return 2 ** 64 - 1 + return 2**64 - 1 diff --git a/guidos-gorgeous-lasagna/lasagna.py b/guidos-gorgeous-lasagna/lasagna.py index 577645a..99722f8 100644 --- a/guidos-gorgeous-lasagna/lasagna.py +++ b/guidos-gorgeous-lasagna/lasagna.py @@ -8,7 +8,6 @@ of a module and its functions and/or classes. """ - EXPECTED_BAKE_TIME: int = 40 PREPARATION_TIME: int = 2 @@ -45,8 +44,7 @@ def preparation_time_in_minutes(number_of_layers: int) -> int: return int(PREPARATION_TIME * number_of_layers) -def elapsed_time_in_minutes(number_of_layers: int, - elapsed_bake_time: int) -> int: +def elapsed_time_in_minutes(number_of_layers: int, elapsed_bake_time: int) -> int: """ Calculate elapsed time in minutes. @@ -62,4 +60,5 @@ def elapsed_time_in_minutes(number_of_layers: int, :rtype: int """ return preparation_time_in_minutes(number_of_layers=number_of_layers) + ( - EXPECTED_BAKE_TIME - bake_time_remaining(elapsed_bake_time)) + EXPECTED_BAKE_TIME - bake_time_remaining(elapsed_bake_time) + ) diff --git a/hello-world/hello_world.py b/hello-world/hello_world.py index 4d0815d..318a3bc 100644 --- a/hello-world/hello_world.py +++ b/hello-world/hello_world.py @@ -1,3 +1,3 @@ # pylint: disable=C0116, C0114 def hello(): - return 'Hello, World!' + return "Hello, World!" diff --git a/little-sisters-vocab/strings.py b/little-sisters-vocab/strings.py index f94c355..419c4a4 100644 --- a/little-sisters-vocab/strings.py +++ b/little-sisters-vocab/strings.py @@ -8,7 +8,7 @@ def add_prefix_un(word: str) -> str: :param word: str - containing the root word. :return: str - of root word prepended with 'un'. """ - return f'un{word}' + return f"un{word}" def make_word_groups(vocab_words: list[str]) -> str: @@ -27,7 +27,7 @@ def make_word_groups(vocab_words: list[str]) -> str: For example: list('en', 'close', 'joy', 'lighten'), produces the following string: 'en :: enclose :: enjoy :: enlighten'. """ - return f' :: {vocab_words[0]}'.join(vocab_words) + return f" :: {vocab_words[0]}".join(vocab_words) def remove_suffix_ness(word: str) -> str: @@ -39,7 +39,7 @@ def remove_suffix_ness(word: str) -> str: For example: "heaviness" becomes "heavy", but "sadness" becomes "sad". """ - return f'{word[:-5]}y' if word[-5] == 'i' else word[:-4] + return f"{word[:-5]}y" if word[-5] == "i" else word[:-4] def adjective_to_verb(sentence: str, index: int) -> str: @@ -53,5 +53,5 @@ def adjective_to_verb(sentence: str, index: int) -> str: For example, ("It got dark as the sun set.", 2) becomes "darken". """ words: list[str] = sentence.split() - word: str = words[index].strip('.,!?;:') - return f'{word}en' + word: str = words[index].strip(".,!?;:") + return f"{word}en" diff --git a/making-the-grade/loops.py b/making-the-grade/loops.py index 06668b7..3889505 100644 --- a/making-the-grade/loops.py +++ b/making-the-grade/loops.py @@ -21,8 +21,7 @@ def count_failed_students(student_scores: list) -> int: return len([score for score in student_scores if score <= 40.0]) # pylint: disable=R0801 -def above_threshold(student_scores: list, - threshold: int) -> list: +def above_threshold(student_scores: list, threshold: int) -> list: """ Filter out above threshold scores. @@ -55,8 +54,7 @@ def letter_grades(highest: int) -> list: # pylint: disable=R0801 -def student_ranking(student_scores: list, - student_names: list) -> list[str]: +def student_ranking(student_scores: list, student_names: list) -> list[str]: """ Organize the student's rank, name, and grade information in descending order. @@ -64,8 +62,12 @@ def student_ranking(student_scores: list, :param student_names: list - of string names by exam score in descending order. :return: list - of strings in format [". : "]. """ - return [f"{i}. {name}: {score}" for i, score, name in zip( - range(1, len(student_scores) + 1), student_scores, student_names)] + return [ + f"{i}. {name}: {score}" + for i, score, name in zip( + range(1, len(student_scores) + 1), student_scores, student_names + ) + ] # pylint: disable=R0801 diff --git a/meltdown-mitigation/conditionals.py b/meltdown-mitigation/conditionals.py index 7029096..e26fa94 100644 --- a/meltdown-mitigation/conditionals.py +++ b/meltdown-mitigation/conditionals.py @@ -15,7 +15,11 @@ def is_criticality_balanced(temperature, neutrons_emitted) -> bool: - The number of neutrons emitted per second is greater than 500. - The product of temperature and neutrons emitted per second is less than 500000. """ - return temperature < 800 and neutrons_emitted > 500 and (temperature * neutrons_emitted) < 500000 + return ( + temperature < 800 + and neutrons_emitted > 500 + and (temperature * neutrons_emitted) < 500000 + ) def reactor_efficiency(voltage, current, theoretical_max_power) -> str: @@ -39,18 +43,18 @@ def reactor_efficiency(voltage, current, theoretical_max_power) -> str: where generated power = voltage * current """ generated_power = voltage * current - efficiency = (generated_power/theoretical_max_power)*100 + efficiency = (generated_power / theoretical_max_power) * 100 if efficiency < 30: - return 'black' + return "black" if 30 <= efficiency < 60: - return 'red' + return "red" if 60 <= efficiency < 80: - return 'orange' + return "orange" - return 'green' + return "green" def fail_safe(temperature, neutrons_produced_per_second, threshold) -> str: @@ -70,9 +74,9 @@ def fail_safe(temperature, neutrons_produced_per_second, threshold) -> str: thr_percent = threshold / 100 if thr_percent - 10 <= current_state <= thr_percent + 10: - return 'NORMAL' + return "NORMAL" if current_state < thr_percent - 10: - return 'LOW' + return "LOW" - return 'DANGER' + return "DANGER" diff --git a/triangle/triangle.py b/triangle/triangle.py index 6537e75..eefee03 100644 --- a/triangle/triangle.py +++ b/triangle/triangle.py @@ -39,9 +39,11 @@ def no_inequality_violation(sides: list) -> bool: b + c ≥ a a + c ≥ b """ - return (sides[0] + sides[1] >= sides[2] and - sides[0] + sides[2] >= sides[1] and - sides[2] + sides[1] >= sides[0]) + return ( + sides[0] + sides[1] >= sides[2] + and sides[0] + sides[2] >= sides[1] + and sides[2] + sides[1] >= sides[0] + ) def all_sides_positive(sides: list) -> bool: From edebb649a44cc083af6ea2a36ed8311b1ddc925c Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Mon, 25 Aug 2025 22:27:29 -0700 Subject: [PATCH 6/6] Update ruff.yml --- .github/workflows/ruff.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml index f01a2a3..f493ef7 100644 --- a/.github/workflows/ruff.yml +++ b/.github/workflows/ruff.yml @@ -1,6 +1,10 @@ name: Ruff Lint and Format -on: [push, pull_request] +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] jobs: ruff: