Skip to content

Commit

Permalink
Migrate to ruff (#170)
Browse files Browse the repository at this point in the history
* Add Ruff and its settings

* Format code base

* Separate out linting dependencies

* Bump minimum Python version to 3.7

* Move from tox to ruff in CI

* Add `docs` dependencies to tests CI

When we test the documentation, we need its dependencies.

* Make docs testing one-line command

* Increase `max-parallel` CI runners to 10

* Set bash as default shell
  • Loading branch information
daffidwilde authored Oct 21, 2023
1 parent 497602e commit 867f5c0
Show file tree
Hide file tree
Showing 12 changed files with 88 additions and 78 deletions.
39 changes: 30 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
name: CI
on: [push, pull_request]
on:
pull_request:
push:
branches:
- "main"
- "dev*"

jobs:
build:
ci:

runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash
strategy:
max-parallel: 8
max-parallel: 10
matrix:
os: [ubuntu-latest, windows-latest]
python-version: [3.7, 3.8, 3.9]
python-version: [3.7, 3.8, 3.9, "3.10", "3.11"]

steps:
- name: Check out repository
Expand All @@ -19,13 +27,26 @@ jobs:
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
cache: "pip"

- name: Update pip
- name: Update pip and install dependencies
run: |
python -m pip install --upgrade pip
- name: Install tox
python -m pip install ".[docs,test]"
- name: Run tests
run: |
python -m pip install tox tox-gh-actions
- name: Run tox
python -m doctest README.md
python -m doctest paper.md
python -m pytest docs --nbval --nbval-current-env -p no:randomly
python -m pytest tests \
--cov=matching --cov-fail-under=100 --hypothesis-profile=ci
- name: Install and run linters (3.11-ubuntu only)
if: |
matrix.python-version == '3.11' &&
matrix.os == 'ubuntu-latest'
run: |
python -m tox
python -m pip install ".[lint]"
python -m black --check .
python -m ruff check .
1 change: 1 addition & 0 deletions docs/tutorials/hospital_resident.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"outputs": [],
"source": [
"import urllib\n",
"\n",
"import yaml\n",
"\n",
"\n",
Expand Down
3 changes: 2 additions & 1 deletion docs/tutorials/student_allocation.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -1028,7 +1028,8 @@
},
"outputs": [],
"source": [
"from collections import Counter, defaultdict\n",
"from collections import Counter\n",
"\n",
"import matplotlib.pyplot as plt\n",
"\n",
"plt.style.use(\"tableau-colorblind10\")\n",
Expand Down
41 changes: 24 additions & 17 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ authors = [
]
description = "A package for solving matching games"
readme = "README.md"
requires-python = ">=3.5"
requires-python = ">=3.7"
license = {text = "MIT License"}
keywords = [
"game-theory",
Expand Down Expand Up @@ -49,12 +49,12 @@ docs = [
"PyYAML>=6",
"quartodoc>=0.5.0; python_version>'3.8'",
]
dev = [
lint = [
"black[jupyter]>=22.6.0,<23",
"flake8>=4.0.1",
"interrogate>=1.5.0",
"isort>=5.10.1",
"matching[docs,test]",
"ruff>=0.1.1",
]
dev = [
"matching[docs,lint,test]",
]

[project.urls]
Expand All @@ -68,16 +68,23 @@ version = {attr = "matching.__version__"}
[tool.black]
line-length = 79

[tool.isort]
profile = "black"
line_length = 79
[tool.coverage.report]
omit = ["src/**/__init__.py"]

[tool.ruff]
extend-include = ["*.ipynb"]
extend-select = ["D", "I", "W"]
ignore = ["D105", "D107", "D202"]
line-length = 79

[tool.ruff.isort]
known-first-party = ["matching"]

[tool.interrogate]
ignore-init-method = true
ignore-init-module = true
ignore-magic = true
fail-under = 100
verbose = 1
[tool.ruff.per-file-ignores]
"docs/*" = ["D100", "D103", "E402"]
"tests/**/*.py" = ["D104", "D401", "E741"]
"src/**/*.py" = ["D105", "D107"]
"src/matching/base.py" = ["D401"]

[tool.coverage.report]
omit = ["src/**/__init__.py"]
[tool.ruff.pydocstyle]
convention = "numpy"
12 changes: 7 additions & 5 deletions src/matching/algorithms/hospital_resident.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ def _check_available(hospital):


def hospital_resident(residents, hospitals, optimal="resident"):
"""Solve an instance of HR using an adapted Gale-Shapley algorithm
:cite:`Rot84`. A unique, stable and optimal matching is found for
the given set of residents and hospitals. The optimality of the
matching is found with respect to one party and is subsequently the
worst stable matching for the other.
"""Solve an instance of HR.
This function uses an adapted Gale-Shapley algorithm :cite:`Rot84`.
A unique, stable and optimal matching is found for the given set of
residents and hospitals. The optimality of the matching is found
with respect to one party and is subsequently the worst stable
matching for the other.
Parameters
----------
Expand Down
7 changes: 4 additions & 3 deletions src/matching/algorithms/stable_marriage.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ def _unmatch_pair(suitor, reviewer):


def stable_marriage(suitors, reviewers, optimal="suitor"):
"""An extended version of the original Gale-Shapley algorithm.
"""Solve an instance of SM.
This version makes use of the inherent structures of SM instances. A
unique, stable and optimal matching is found for any valid set of
This function uses an extended version of the original Gale-Shapley
algorithm that makes use of the inherent structures of SM instances.
A unique, stable and optimal matching is found for any valid set of
suitors and reviewers. The optimality of the matching is with
respect to one party and is subsequently the worst stable matching
for the other.
Expand Down
10 changes: 6 additions & 4 deletions src/matching/algorithms/stable_roommates.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" Functions for the SR algorithm. """
"""Functions for the SR algorithm."""

import warnings

Expand Down Expand Up @@ -33,7 +33,8 @@ def first_phase(players):
def locate_all_or_nothing_cycle(player):
"""Locate a cycle of (least-preferable, second-choice) pairs.
Any such cycle will be removed from the game."""
Any such cycle will be removed from the game.
"""

lasts = [player]
seconds = []
Expand All @@ -56,7 +57,7 @@ def locate_all_or_nothing_cycle(player):


def get_pairs_to_delete(cycle):
"""Find the set of pairs to remove given an all-or-nothing cycle.
r"""Find the set of pairs to remove given an all-or-nothing cycle.
Based on an all-or-nothing cycle (also referred to as a "rotation")
:math:`(x_1, y_1), \\ldots, (x_n, y_n)`, for each
Expand All @@ -71,7 +72,8 @@ def get_pairs_to_delete(cycle):
:cite:`Irv85` is the removal of unpreferable pairs, identified using
an all-or-nothing cycle, in addition to those contained in the
cycle. Without doing so, tails of cycles can be removed rather than
whole cycles, leaving some conflicting pairs in the game."""
whole cycles, leaving some conflicting pairs in the game.
"""

pairs = []
for i, (_, right) in enumerate(cycle):
Expand Down
2 changes: 1 addition & 1 deletion src/matching/algorithms/student_allocation.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" Functions for the SA algorithm. """
"""Functions for the SA algorithm."""

from .util import _delete_pair, _match_pair

Expand Down
5 changes: 2 additions & 3 deletions src/matching/algorithms/util.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
""" Useful functions for the running of the various core algorithms. """
"""Useful functions for the running of the various core algorithms."""


def _delete_pair(player, other):
"""Make a player forget another (and vice versa), deleting the pair from
further consideration in the game."""
"""Make two players forget each other."""

player._forget(other)
other._forget(player)
Expand Down
21 changes: 10 additions & 11 deletions src/matching/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@


class BasePlayer:
"""An abstract base class to represent a player within a matching game.
"""An abstract base class to represent a player in a matching game.
Parameters
----------
Expand All @@ -20,16 +20,17 @@ class BasePlayer:
Attributes
----------
prefs : List[BasePlayer]
The player's preferences. Defaults to ``None`` and is updated using the
``set_prefs`` method.
The player's preferences. Defaults to ``None`` and is updated
using the ``set_prefs`` method.
matching : Optional[BasePlayer]
The current match of the player. ``None`` if not currently matched.
The current match of the player. ``None`` if not currently
matched.
_pref_names : Optional[List]
A list of the names in ``prefs``. Updates with ``prefs`` via
``set_prefs`` method.
_original_prefs : Optional[List[BasePlayer]]
The original set of player preferences. Defaults to ``None`` and does
not update after the first ``set_prefs`` method call.
The original set of player preferences. Defaults to ``None``
and does not update after the first ``set_prefs`` method call.
"""

def __init__(self, name):
Expand All @@ -44,8 +45,7 @@ def __repr__(self):
return str(self.name)

def _forget(self, other):
"""Forget another player by removing them from the player's preference
list."""
"""Remove another player from the player's preferences."""

self.prefs = [p for p in self.prefs if p != other]

Expand All @@ -72,8 +72,7 @@ def set_prefs(self, players):
self._original_prefs = players[:]

def prefers(self, player, other):
"""Determines whether the player prefers a player over some other
player."""
"""Check whether the player prefers one player over another."""

prefs = self._original_prefs
return prefs.index(player) < prefs.index(other)
Expand Down Expand Up @@ -244,7 +243,7 @@ def __getitem__(self, player):

@abc.abstractmethod
def __setitem__(self, player, new_match):
"""A placeholder function for how to update the matching."""
"""Placeholder function for how to update the matching."""

def _check_player_in_keys(self, player):
"""Raise an error if ``player`` is not in the dictionary."""
Expand Down
2 changes: 1 addition & 1 deletion src/matching/players/player.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" The base Player class for use in various games. """
"""The base Player class for use in various games."""

from matching import BasePlayer

Expand Down
23 changes: 0 additions & 23 deletions tox.ini

This file was deleted.

0 comments on commit 867f5c0

Please sign in to comment.