Skip to content

Commit

Permalink
chore: update dependencies and Python version across project
Browse files Browse the repository at this point in the history
- Bumped pre-commit hooks: black (24.2.0 to 24.10.0), flake8 (7.0.0 to 7.1.1), mypy (v1.8.0 to v1.14.0), and others.
- Updated Dockerfile to use Python 3.12.
- Updated pydantic version in pdm.lock and pyproject.toml to >=2.6.1.
- Adjusted GitHub workflows to set up Python 3.12.
- Refactored code to utilize new Python features and improve type hints.
- Enhanced logging and configuration validation in utils and config modules.

This commit ensures compatibility with the latest dependencies and Python version, improving overall project stability and performance.
  • Loading branch information
oedokumaci committed Dec 29, 2024
1 parent d243318 commit 743b4b2
Show file tree
Hide file tree
Showing 19 changed files with 1,023 additions and 900 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ jobs:
- name: Checkout
uses: actions/checkout@v3

- name: Set up Python 3.10
- name: Set up Python 3.12
uses: actions/setup-python@v4
with:
python-version: "3.10"
python-version: "3.12"

- name: Set up PDM
uses: pdm-project/setup-pdm@v3
with:
python-version: "3.10"
python-version: "3.12"

- name: Install dependencies and pre-commit hooks
run: make setup
Expand Down
4 changes: 1 addition & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ jobs:
- macos-latest
- windows-latest
python-version:
- "3.9"
- "3.10"
- "3.11"
- "3.12"

runs-on: ${{ matrix.os }}

Expand Down
20 changes: 10 additions & 10 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
repos:
- repo: https://github.com/psf/black
rev: 24.2.0
rev: 24.10.0
hooks:
- id: black

- repo: https://github.com/PyCQA/flake8
rev: 7.0.0
rev: 7.1.1
hooks:
- id: flake8
args:
Expand All @@ -24,7 +24,7 @@ repos:
- --profile=black # to be compatible with black

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
rev: v5.0.0
hooks:
- id: end-of-file-fixer
- id: check-yaml
Expand All @@ -33,34 +33,34 @@ repos:
- id: requirements-txt-fixer

- repo: https://github.com/codespell-project/codespell
rev: v2.2.6
rev: v2.3.0
hooks:
- id: codespell
exclude: ^config/

- repo: https://github.com/asottile/pyupgrade
rev: v3.15.1
rev: v3.19.1
hooks:
- id: pyupgrade
args: [--py310-plus]
args: [--py312-plus]

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.8.0
rev: v1.14.0
hooks:
- id: mypy
args:
- src
- tests
pass_filenames: false
additional_dependencies:
- pydantic==1.10.8
- pydantic>=2.0.0
- pytest
- rich
- typer
- types-PyYAML

- repo: https://github.com/nbQA-dev/nbQA
rev: 1.7.1
rev: 1.9.1
hooks:
- id: nbqa-black
# additional_dependencies: [jupytext] # optional, only if you're using Jupytext
Expand All @@ -70,7 +70,7 @@ repos:
args: [--float-to-top, --profile=black]

- repo: https://github.com/kynan/nbstripout
rev: 0.7.1
rev: 0.8.1
hooks:
- id: nbstripout

Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Use an official Python runtime as a parent image
FROM python:3.11
FROM python:3.12

# Set the working directory in the container
WORKDIR /usr/src/app
Expand Down
737 changes: 348 additions & 389 deletions pdm.lock

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ authors = [
{name = "oedokumaci", email = "oral.ersoy.dokumaci@gmail.com"},
]
dependencies = [
"pdm>=2.5.3",
"pyyaml>=6.0",
"pydantic==1.10.13",
"typer>=0.7.0",
"pdm>=2.12.3",
"pyyaml>=6.0.1",
"pydantic>=2.6.1",
"typer>=0.9.0",
]
requires-python = ">=3.9"
requires-python = ">=3.12"
readme = "README.md"
license = {text = "MIT"}

Expand Down
8 changes: 4 additions & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# This file is @generated by PDM.
# Please do not edit it manually.

pdm>=2.5.3
pdm>=2.12.3
pre-commit>=3.0.4
pydantic==1.10.13
pydantic>=2.6.1
pytest>=7.2.1
pyyaml>=6.0
typer>=0.7.0
pyyaml>=6.0.1
typer>=0.9.0
75 changes: 35 additions & 40 deletions src/gale_shapley/algorithm.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,21 @@
"""Algorithm module."""

from __future__ import annotations # needed in 3.9 for | of Python 3.10

import logging
from dataclasses import dataclass
from typing import Final

from gale_shapley.person import Proposer, Responder
from gale_shapley.utils import timer_decorator


@dataclass(slots=True)
class Algorithm:
"""Gale-Shapley Algorithm class.
Uses __slots__ instead of the default __dict__ for memory efficiency."""

__slots__ = ("proposers", "responders", "round")

def __init__(self, proposers: list[Proposer], responders: list[Responder]) -> None:
"""Constructor for Algorithm class.
Uses slots for memory efficiency."""

Args:
proposers (list[Proposer]): list of proposers
responders (list[Responder]): list of responders
"""
self.proposers = proposers
self.responders = responders
self.round: int = 0
proposers: list[Proposer]
responders: list[Responder]
round: int = 0

@property
def persons(self) -> list[Proposer | Responder]:
Expand Down Expand Up @@ -60,35 +52,36 @@ def report_matches(self) -> None:
"""Prints all matches, does not print unmatched responders."""
logging.info("Printing the matching:")
for proposer in self.proposers:
if (
proposer.match is not None
): # mypy complains if proposer.is_matched is used
logging.info(
f"{proposer.name} is matched to {'self' if proposer.name == proposer.match.name else proposer.match.name}."
)
else:
logging.info(f"{proposer.name} is unmatched.")
match proposer.match:
case None:
logging.info(f"{proposer.name} is unmatched.")
case match if match.name == proposer.name:
logging.info(f"{proposer.name} is matched to self.")
case match:
logging.info(f"{proposer.name} is matched to {match.name}.")

for responder in self.responders:
if responder.match == responder:
logging.info(f"{responder.name} is matched to self.")
elif not responder.is_matched:
logging.info(f"{responder.name} is unmatched.")
match responder.match:
case match if match == responder:
logging.info(f"{responder.name} is matched to self.")
case None:
logging.info(f"{responder.name} is unmatched.")

@timer_decorator
def print_all_preferences(self, compact: bool = True) -> None:
"""Prints the preferences of all proposers and responders.
Args:
compact (bool, optional): If True prints all in one table. Defaults to True.
compact (bool): If True prints all in one table. Defaults to True.
"""
if compact:
logging.info(
"Printing preferences in compact format, only showing acceptables:"
)
header: list[str] = [p.name for p in self.persons]
first_column: list[str] = [
f"{i + 1}."
for i in range(max(len(self.proposers), len(self.responders)) + 1)
header: Final[list[str]] = [p.name for p in self.persons]
first_column: Final[list[str]] = [
f"{i}."
for i in range(1, max(len(self.proposers), len(self.responders)) + 2)
]
data: list[list[str]] = []
for i in range(len(first_column)):
Expand All @@ -104,9 +97,7 @@ def print_all_preferences(self, compact: bool = True) -> None:
for person in self.persons
]
)
format_row: str = "{:8}" * ( # TODO: fix this
len(header) + 1
) # doing with f-strings could be a pain
format_row: Final[str] = "{:8}" * (len(header) + 1)
logging.info(format_row.format("", *header))
logging.info(format_row.format("", *["-" * len(h) for h in header]))
for pref, row in zip(first_column, data):
Expand All @@ -128,21 +119,25 @@ def run(
"""Runs the algorithm and prints desired information.
Args:
print_all_preferences (bool, optional): Prints individual preferences before running, defaults to False
compact (bool, optional): If True prints all in one table, defaults to True
report_matches (bool, optional): Reports the final matching, defaults to True
print_all_preferences (bool): Prints individual preferences before running. Defaults to True.
compact (bool): If True prints all in one table. Defaults to True.
report_matches (bool): Reports the final matching. Defaults to True.
"""
if print_all_preferences:
self.print_all_preferences(compact=compact)
logging.info("")
logging.info("")

logging.info("Running algorithm...")
while not self.terminate():
self.proposers_propose()
self.responders_respond()
self.round += 1
for responder in self.responders: # change None to self matches

# Change None to self matches for unmatched responders
for responder in self.responders:
if not responder.is_matched:
responder.match = responder

logging.info(f"Algorithm terminated after {self.round} rounds.")
if report_matches:
self.report_matches()
37 changes: 22 additions & 15 deletions src/gale_shapley/cli.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
"""Command line application module for Gale-Shapley algorithm."""

from typing import Final, NoReturn

import typer
from rich import print as rprint

from gale_shapley.config import config_input, side_swap
from gale_shapley.simulator import Simulator
from gale_shapley.utils import LOG_PATH, init_logger, log_config_info

number_of_simulations_argument = typer.Argument(
number_of_simulations_argument: Final = typer.Argument(
1, min=1, help="Desired number of simulations"
)
print_all_preferences_option = typer.Option(True, help="Print preferences of all")
compact_option = typer.Option(
print_all_preferences_option: Final = typer.Option(
True, help="Print preferences of all"
)
compact_option: Final = typer.Option(
True, help="Prints all preferences in one table compactly"
)
report_matches_option = typer.Option(
report_matches_option: Final = typer.Option(
True, help="Reports the final matching of each simulation"
)

swap_sides_option = typer.Option(False, help="Swaps proposers and responders")
swap_sides_option: Final = typer.Option(False, help="Swaps proposers and responders")


def main(
Expand All @@ -26,22 +30,25 @@ def main(
compact: bool = compact_option,
report_matches: bool = report_matches_option,
swap_sides: bool = swap_sides_option,
) -> None:
) -> NoReturn:
"""Simulates the Gale-Shapley Algorithm desired times and logs the results."""
# Check if log file exists, if so ask to overwrite
log_file = LOG_PATH / config_input.log_file_name
if log_file.exists(): # if log file exists ask to overwrite
if log_file.exists():
user_input = (
input(
f"log_file_name {config_input.log_file_name!r} already exists, overwrite? y/n (n): "
)
or "n"
)
if user_input != "y":
raise SystemExit(
"exiting not to overwrite, please change 'log_file_name' in 'config.yaml'"
)
print("")
match user_input:
case "y":
pass
case _:
raise SystemExit(
"exiting not to overwrite, please change 'log_file_name' in 'config.yaml'"
)
rprint("")

# Initialize logger
init_logger(config_input.log_file_name)
Expand All @@ -61,7 +68,7 @@ def main(
)

# Print log file path
print("")
print(f"logs are saved to {log_file.resolve()}")
rprint("")
rprint(f"logs are saved to {log_file.resolve()}")

raise typer.Exit()
Loading

0 comments on commit 743b4b2

Please sign in to comment.