Skip to content

Commit 1b2bbcb

Browse files
author
miskibin
committed
Refactor GitHub Actions workflows for testing and publishing; update Python version to 3.11 and improve package build process
1 parent f3fd96d commit 1b2bbcb

File tree

7 files changed

+139
-94
lines changed

7 files changed

+139
-94
lines changed

.github/workflows/python-app.yml

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,35 @@ permissions:
1010
contents: read
1111

1212
jobs:
13-
build:
13+
test:
1414
runs-on: ubuntu-latest
1515

1616
steps:
17-
- name: Set up Python 3.10
18-
uses: actions/setup-python@v3
17+
- uses: actions/checkout@v4
18+
- name: Set up Python
19+
uses: actions/setup-python@v5
1920
with:
20-
python-version: "3.10"
21-
- uses: actions/checkout@v3
21+
python-version: "3.11"
2222
- name: Install dependencies
23-
working-directory: .
2423
run: |
25-
ls -la
26-
python -m pip install virtualenv
27-
python -m virtualenv .venv
28-
source .venv/bin/activate
29-
pip install pytest
30-
pip install -r requirements.txt
31-
export PYTHONPATH+=$PYTHONPATH:$(pwd)
32-
pip install -e .
33-
- name: Test with pytest
24+
python -m pip install --upgrade pip
25+
pip install -e ".[dev]"
26+
- name: Run tests
3427
run: |
35-
source .venv/bin/activate
36-
python -m pytest . -vv
28+
python -m pytest test/ -v
29+
30+
lint:
31+
runs-on: ubuntu-latest
32+
steps:
33+
- uses: actions/checkout@v4
34+
- name: Set up Python
35+
uses: actions/setup-python@v5
36+
with:
37+
python-version: "3.11"
38+
- name: Install dependencies
39+
run: |
40+
python -m pip install --upgrade pip
41+
pip install -e ".[dev]"
42+
- name: Type check with mypy
43+
run: |
44+
python -m mypy draughts --ignore-missing-imports

.github/workflows/python-publish.yml

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,42 @@ name: Upload Python Package
1010
on:
1111
push:
1212
tags:
13-
- "*"
13+
- "v*"
1414

1515
jobs:
16+
build:
17+
name: Build distribution
18+
runs-on: ubuntu-latest
19+
steps:
20+
- uses: actions/checkout@v4
21+
- name: Set up Python
22+
uses: actions/setup-python@v5
23+
with:
24+
python-version: "3.11"
25+
- name: Install build dependencies
26+
run: python -m pip install --upgrade pip build
27+
- name: Build package
28+
run: python -m build
29+
- name: Store distribution packages
30+
uses: actions/upload-artifact@v4
31+
with:
32+
name: python-package-distributions
33+
path: dist/
34+
1635
pypi-publish:
1736
name: Upload release to PyPI
37+
needs: build
1838
runs-on: ubuntu-latest
1939
environment:
2040
name: pypi
2141
url: https://pypi.org/p/py-draughts
2242
permissions:
2343
id-token: write
2444
steps:
25-
- name: Checkout
26-
uses: actions/checkout@v3
45+
- name: Download distribution packages
46+
uses: actions/download-artifact@v4
47+
with:
48+
name: python-package-distributions
49+
path: dist/
2750
- name: Publish package distributions to PyPI
2851
uses: pypa/gh-action-pypi-publish@release/v1

draughts/boards/base.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,16 @@ class BaseBoard(ABC):
8585

8686
DIAGONAL_LONG_MOVES = ...
8787
"""
88-
Dictionary of pseudo-legal moves for king pieces. Generated only on module import.
89-
This dictionary contains all possible moves for king piece (as if there were no other pieces on the board).
88+
Dictionary of pseudo-legal moves for man pieces. Generated only on module import.
89+
Despite the name, this contains SHORT moves (first 2 squares) sufficient for men.
9090
9191
**Structure:**
9292
``[(right-up moves), (left-up moves), (right-down moves), (left-down moves)]``
9393
"""
9494
DIAGONAL_SHORT_MOVES = ...
9595
"""
96-
Same as ``DIAGONAL_LONG_MOVES`` but contains only first 2 squares of the move.
96+
Dictionary of pseudo-legal moves for king pieces. Generated only on module import.
97+
Despite the name, this contains LONG moves (all squares on diagonal) for kings.
9798
(one for move and one for capture)
9899
"""
99100

@@ -104,6 +105,9 @@ def __init_subclass__(cls, **kwargs):
104105
for var_name, var_value in child_class_vars.items():
105106
if var_name in parent_class_vars and not var_name.startswith("_"):
106107
setattr(parent_class, var_name, var_value)
108+
# Note: Names are intentionally swapped - DIAGONAL_SHORT_MOVES holds long moves (all squares)
109+
# because kings need to traverse entire diagonals, while DIAGONAL_LONG_MOVES holds short moves
110+
# (first 2 squares) which is sufficient for men who only move/capture one square at a time
107111
cls.DIAGONAL_SHORT_MOVES = get_diagonal_moves(len(cls.STARTING_POSITION))
108112
cls.DIAGONAL_LONG_MOVES = get_short_diagonal_moves(len(cls.STARTING_POSITION))
109113

@@ -314,29 +318,29 @@ def from_fen(cls, fen: str) -> BaseBoard:
314318
except AttributeError as e:
315319
raise AttributeError(f"Invalid FEN: {fen} \n {e}")
316320
logger.debug(f"turn: {turn}, white: {white}, black: {black}")
317-
cls.STARTING_POSITION = np.zeros(cls.STARTING_POSITION.shape, dtype=np.int8)
321+
position = np.zeros(cls.STARTING_POSITION.shape, dtype=np.int8)
318322
if len(turn) != 1 or (len(white) == 0 and len(black) == 0):
319323
raise ValueError(f"Invalid FEN: {fen}")
320324
try:
321-
cls.__populate_from_list(white.split(","), Color.WHITE)
322-
cls.__populate_from_list(black.split(","), Color.BLACK)
325+
cls.__populate_from_list(white.split(","), Color.WHITE, position)
326+
cls.__populate_from_list(black.split(","), Color.BLACK, position)
323327
except ValueError as e:
324328
logger.error(f"Invalid FEN: {fen} \n {e}")
325329
turn_color = Color.WHITE if turn == "W" else Color.BLACK
326-
return cls(cls.STARTING_POSITION, turn_color)
330+
return cls(position, turn_color)
327331

328332
@classmethod
329-
def __populate_from_list(cls, fen_list: list[str], color: Color) -> None:
330-
board_range = range(1, cls.STARTING_POSITION.shape[0] + 1)
333+
def __populate_from_list(cls, fen_list: list[str], color: Color, position: np.ndarray) -> None:
334+
board_range = range(1, position.shape[0] + 1)
331335
for sq in fen_list:
332336
if sq.isdigit() and int(sq) in board_range:
333-
cls.STARTING_POSITION[int(sq) - 1] = color.value
337+
position[int(sq) - 1] = color.value
334338
elif sq.startswith("K") and sq[1:].isdigit() and int(sq[1:]) in board_range:
335-
cls.STARTING_POSITION[int(sq[1:]) - 1] = color.value * Figure.KING.value
339+
position[int(sq[1:]) - 1] = color.value * Figure.KING.value
336340
else:
337341
raise ValueError(
338342
f"invalid square value: {sq} for board with length\
339-
{cls.STARTING_POSITION.shape[0]}"
343+
{position.shape[0]}"
340344
)
341345

342346
@property

draughts/move.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ class Move:
2727
def __init__(
2828
self,
2929
visited_squares: list[int],
30-
captured_list: list[int] = [],
31-
captured_entities: list[int] = [],
30+
captured_list: list[int] | None = None,
31+
captured_entities: list[int] | None = None,
3232
is_promotion: bool = False,
3333
) -> None:
3434
self.square_list = visited_squares
35-
self.captured_list = captured_list
36-
self.captured_entities = captured_entities
35+
self.captured_list = captured_list if captured_list is not None else []
36+
self.captured_entities = captured_entities if captured_entities is not None else []
3737
self.is_promotion = is_promotion
3838
self.halfmove_clock = 0
3939

draughts/py.typed

Whitespace-only changes.

pyproject.toml

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
[build-system]
2+
requires = ["setuptools>=61.0", "wheel"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "py-draughts"
7+
version = "1.3.1"
8+
description = "A draughts library with advanced (customizable) WEB UI move generation and validation, PDN parsing and writing. Supports multiple variants of game."
9+
readme = "readme.md"
10+
license = {file = "LICENSE"}
11+
authors = [
12+
{ name = "Michał Skibiński", email = "mskibinski109@gmail.com" }
13+
]
14+
keywords = ["draughts", "checkers", "AI", "mini-max", "game", "board"]
15+
classifiers = [
16+
"Development Status :: 5 - Production/Stable",
17+
"Intended Audience :: Developers",
18+
"Intended Audience :: Science/Research",
19+
"Operating System :: OS Independent",
20+
"Programming Language :: Python :: 3 :: Only",
21+
"Programming Language :: Python :: 3.9",
22+
"Programming Language :: Python :: 3.10",
23+
"Programming Language :: Python :: 3.11",
24+
"Programming Language :: Python :: 3.12",
25+
"Programming Language :: Python :: 3.13",
26+
"Programming Language :: Python :: 3.14",
27+
"Topic :: Games/Entertainment :: Board Games",
28+
"Topic :: Games/Entertainment :: Turn Based Strategy",
29+
"Topic :: Software Development :: Libraries :: Python Modules",
30+
"Typing :: Typed",
31+
]
32+
requires-python = ">=3.9"
33+
dependencies = [
34+
"tqdm",
35+
"numpy",
36+
"easy_logs",
37+
"fastapi",
38+
"uvicorn",
39+
"jinja2",
40+
]
41+
42+
[project.urls]
43+
Homepage = "https://github.com/michalskibinski109/py-draughts"
44+
Documentation = "https://michalskibinski109.github.io/py-draughts/index.html"
45+
Repository = "https://github.com/michalskibinski109/py-draughts"
46+
47+
[project.optional-dependencies]
48+
dev = [
49+
"pytest",
50+
"mypy",
51+
"sphinx",
52+
]
53+
54+
[tool.setuptools.packages.find]
55+
where = ["."]
56+
57+
[tool.setuptools.package-data]
58+
draughts = [
59+
"server/static/js/*",
60+
"server/static/css/*",
61+
"server/templates/*",
62+
"py.typed",
63+
]
64+
65+
[tool.mypy]
66+
python_version = "3.9"
67+
warn_return_any = true
68+
warn_unused_configs = true

setup.py

Lines changed: 0 additions & 58 deletions
This file was deleted.

0 commit comments

Comments
 (0)