Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# This workflow will upload a Python Package to PyPI when a release is created
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

name: Upload Python Package

on:
release:
types: [published]

permissions:
contents: read

jobs:
release-build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.x"

- name: Build release distributions
run: |
# NOTE: put your own distribution build steps here.
python -m pip install build
python -m build

- name: Upload distributions
uses: actions/upload-artifact@v4
with:
name: release-dists
path: dist/

pypi-publish:
runs-on: ubuntu-latest
needs:
- release-build
permissions:
# IMPORTANT: this permission is mandatory for trusted publishing
id-token: write

# Dedicated environments with protections for publishing are strongly recommended.
# For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules
environment:
name: pypi
# OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status:
# url: https://pypi.org/p/YOURPROJECT
#
# ALTERNATIVE: if your GitHub Release name is the PyPI project version string
# ALTERNATIVE: exactly, uncomment the following line instead:
# url: https://pypi.org/project/YOURPROJECT/${{ github.event.release.name }}

steps:
- name: Retrieve release distributions
uses: actions/download-artifact@v4
with:
name: release-dists
path: dist/

- name: Publish release distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: dist/
9 changes: 7 additions & 2 deletions make_executable.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,17 @@ def build_executable(spec_file: Path):
["pyinstaller", "--clean", str(spec_file)], f"PyInstaller ({spec_file.name})"
)

name = "gambit-pairing"
# Verify the build
if spec_file.name.endswith("-onedir.spec"):
expected_exe = Path("dist/gambit-pairing/gambit-pairing.exe")
expected_exe = Path("dist") / (
name + (".exe" if sys.platform == "win32" else "")
)
build_type = "onedir"
else:
expected_exe = Path("dist/gambit-pairing.exe")
expected_exe = Path("dist") / (
name + (".exe" if sys.platform == "win32" else "")
)
build_type = "onefile"

if expected_exe.exists():
Expand Down
9 changes: 6 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ dependencies = [
"packaging",
"python-dateutil",
"importlib-resources",
"Pillow", # Required for MSI branding generation
"Pillow",
]
license = {text = "GPL-3.0-or-later"}

Expand Down Expand Up @@ -51,8 +51,8 @@ gambit-pairing = "gambitpairing.__main__:main"

[project.urls]
Homepage = "https://www.chickaboo.net/gambit-pairing/"
Repository = "https://github.com/Chickaboo/gambit-pairing"
Issues = "https://github.com/Chickaboo/gambit-pairing/issues"
Repository = "https://github.com/gambit-devs/gambit-pairing"
Issues = "https://github.com/gambit-devs/gambit-pairing/issues"

[project.optional-dependencies]
dev = [
Expand Down Expand Up @@ -87,6 +87,9 @@ ensure_newline_before_comments = true
"gambitpairing.resources" = ["styles.qss"]
"gambitpairing.resources.icons" = ["*.png", "*.ico", "*.webp", "*.svg"]

[tool.setuptools.dynamic]
version = {attr = "gambitpairing.__version__"}

# Added for static type-checking support
[tool.pyright]
include = ["src", "tests"]
Expand Down
2 changes: 1 addition & 1 deletion src/gambitpairing/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
APP_NAME = "Gambit Pairing"
APP_VERSION = "0.6.4 (alpha)"
APP_VERSION = "0.6.4"
__version__ = APP_VERSION
211 changes: 205 additions & 6 deletions src/gambitpairing/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,218 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.


class PairingException(Exception):
"""Error producing pairings"""
# ========== Base Application Exception ==========


class GambitPairingException(Exception):
"""Base exception for all Gambit Pairing errors.

All custom exceptions in the application should inherit from this class.
This enables catching all application-specific errors with a single except clause.
"""

pass


# ========== Pairing Exceptions ==========


class PairingException(GambitPairingException):
"""Base exception for pairing-related errors."""

pass


class InvalidPairingException(PairingException):
"""Raised when a pairing configuration is invalid."""

pass


class RepeatPairingException(PairingException):
"""Raised when attempting to pair players who have already played."""

pass


class NoPairingAvailableException(PairingException):
"""Raised when no valid pairing can be generated."""

pass


# ========== Tournament Exceptions ==========


class TournamentException(GambitPairingException):
"""Base exception for tournament-related errors."""

pass


class TournamentStateException(TournamentException):
"""Raised when tournament is in an invalid state for the requested operation."""

pass


class RoundNotFoundException(TournamentException):
"""Raised when a requested round does not exist."""

pass


class DuplicatePlayerException(TournamentException):
"""Raised when attempting to add a player that already exists."""

pass


# ========== Player Exceptions ==========


class PlayerException(GambitPairingException):
"""Base exception for player-related errors."""

pass


class PlayerNotFoundException(PlayerException):
"""Raised when a requested player cannot be found."""

pass


class InvalidPlayerDataException(PlayerException):
"""Raised when player data is invalid or incomplete."""

pass


# ========== Result Exceptions ==========


class ResultException(GambitPairingException):
"""Base exception for result recording errors."""

pass


class InvalidResultException(ResultException):
"""Raised when a result is invalid (e.g., score out of range)."""

pass


class DuplicateResultException(ResultException):
"""Raised when attempting to record a result that already exists."""

pass


class ResultNotFoundException(ResultException):
"""Raised when a requested result cannot be found."""

pass


# ========== Validation Exceptions ==========


class ValidationException(GambitPairingException):
"""Base exception for validation errors."""

pass


class EmailValidationException(ValidationException):
"""Raised when an email address is invalid."""

pass


class PhoneValidationException(ValidationException):
"""Raised when a phone number is invalid."""

pass


class RatingValidationException(ValidationException):
"""Raised when a rating value is invalid."""

pass


# ========== File/Resource Exceptions ==========


class ResourceException(GambitPairingException):
"""Base exception for resource-related errors."""

pass


class IconException(ResourceException):
"""Raised when there's an error loading or using the app icon."""

pass


class StyleException(ResourceException):
"""Raised when there's an error loading or applying the app style."""

pass


class FileLoadException(ResourceException):
"""Raised when a file cannot be loaded."""

pass


class FileSaveException(ResourceException):
"""Raised when a file cannot be saved."""

pass


# ========== API Exceptions ==========


class APIException(GambitPairingException):
"""Base exception for API-related errors."""

pass


class FIDEAPIException(APIException):
"""Raised when there's an error communicating with the FIDE API."""

pass


class NetworkException(APIException):
"""Raised when there's a network connectivity error."""

pass


# ========== Configuration Exceptions ==========


class ConfigurationException(GambitPairingException):
"""Base exception for configuration errors."""

pass


class IconException(Exception):
"""Error with the app icon"""
class InvalidConfigurationException(ConfigurationException):
"""Raised when configuration data is invalid."""

pass


class StyleException(Exception):
"""Error with the app Style"""
class MissingConfigurationException(ConfigurationException):
"""Raised when required configuration is missing."""

pass
2 changes: 2 additions & 0 deletions src/gambitpairing/gui/dialogs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from .manual_pairing_dialog import ManualPairingDialog
from .new_tournament_dialog import NewTournamentDialog
from .player_management_dialog import PlayerManagementDialog
from .print_options_dialog import PrintOptionsDialog
from .tournament_settings_dialoug import SettingsDialog
from .update_dialog import UpdateDownloadDialog
from .update_prompt_dialog import UpdatePromptDialog
Expand All @@ -32,4 +33,5 @@
"UpdateDownloadDialog",
"UpdatePromptDialog",
"AboutDialog",
"PrintOptionsDialog",
]
Loading