Skip to content

Commit

Permalink
Document all code with proper docstrings except for the 'pages' module.
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasvana10 committed Aug 2, 2024
1 parent 63eac19 commit 56c896b
Show file tree
Hide file tree
Showing 14 changed files with 671 additions and 133 deletions.
2 changes: 1 addition & 1 deletion src/xpuz/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
"""Play procedurally generated crosswords."""
"""Play procedurally generated crosswords. Toplevel `__init__` module for `xpuz`."""
9 changes: 7 additions & 2 deletions src/xpuz/__main__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Entry point for initialising ``xpuz``."""
"""Entry point of ``xpuz``."""

from configparser import ConfigParser
try:
Expand All @@ -16,7 +16,11 @@


def _get_os_language() -> str:
"""Infer language code from operating system data."""
"""Infer language code from operating system data.
Returns:
The locale.
"""
if os_name == "posix":
return environ["LANG"].split("-")[0]
else:
Expand All @@ -26,6 +30,7 @@ def _get_os_language() -> str:


def main() -> None:
"""Main function to initialise the `xpuz` GUI."""
cfg: ConfigParser = ConfigParser()
_read_cfg(cfg)

Expand Down
2 changes: 1 addition & 1 deletion src/xpuz/app/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
"""test docstring"""
"""The crossword game, hosted locally with a `Flask` server."""
33 changes: 24 additions & 9 deletions src/xpuz/app/app.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""Flask web app to produce an interactive interface to complete a crossword.
The app is run when the user presses the "Load crossword" button in the main GUI.
"""
"""Flask web app that produces an interactive interface to complete a crossword."""

from typing import Any, Dict
from configparser import ConfigParser
from logging import ERROR, getLogger
from multiprocessing import Process
Expand All @@ -21,10 +20,13 @@
cfg: ConfigParser = ConfigParser()


def _app_process(*args, **kwargs) -> None:
"""Ran as a new Process using the ``multiprocessing`` module. Kwargs are
forwarded from ``_create_app``, which forwards the arguments from
``main.init_webapp``.
def _app_process(**kwargs: Dict[str, Any]) -> None:
"""This function is executed as a new Process with the `multiprocessing`
module to ensure the web application does not block the execution of the
Tkinter GUI.
Args:
**kwargs: Jinja2 template and crossword-related data.
"""

@app.route("/")
Expand Down Expand Up @@ -59,18 +61,31 @@ def index() -> str:


def _is_port_in_use(port: int) -> bool:
"""Check if `port` is in use.
Args:
port: The port to check
Returns:
Whether the port is in use or not.
"""
with socket(AF_INET, SOCK_STREAM) as s:
return s.connect_ex(("localhost", port)) == 0


def _create_app(**kwargs) -> None:
"""Execute the ``_app_process`` function as a multithreaded process."""
def _create_app(**kwargs: Dict[str, Any]) -> None:
"""Execute the ``_app_process`` function as a multithreaded process.
Args:
**kwargs: Jinja2 template and crossword-related data.
"""
global server
server = Process(target=_app_process, kwargs=kwargs)
server.start()


def _terminate_app() -> None:
"""Terminate the app process."""
if "server" in globals().keys():
server.terminate()
server.join()
61 changes: 48 additions & 13 deletions src/xpuz/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from configparser import ConfigParser
from platform import system
from typing import Dict, List, Tuple
from typing import Dict, List, Union, Tuple, Callable, Literal

from babel import Locale
from customtkinter import (
Expand All @@ -26,6 +26,7 @@ class Addons:
"""Convenience and utility methods for all page classes."""

def _set_fonts(self) -> None:
"""Initialise this instance with all the required CTkFont objects."""
self.TITLE_FONT = CTkFont(size=31, weight="bold", slant="roman")
self.SUBHEADING_FONT = CTkFont(size=24, weight="normal", slant="roman")
self.TEXT_FONT = CTkFont(size=15, weight="normal", slant="roman")
Expand All @@ -40,11 +41,20 @@ def _set_fonts(self) -> None:
def _confirm_route(
self,
*,
action: bool = None,
action: Callable = None,
condition: bool = None,
confirmation: Dict[str, bool] = {"close": True},
) -> bool:
"""Allow the user to confirm if they wish to route through a messagebox."""
"""Allow the user to confirm if they wish to route through a messagebox.
Args:
action: A function to call if the user confirms to route.
condition: Only perform the confirmation if `True`.
confirmation: Passed in `**kwargs` syntax to the [messagebox helper](utils.md#xpuz.utils.GUIHelper.confirm_with_messagebox)
Returns:
The status of the route confirmation; whether it was accepted or not.
"""

if (
condition
Expand All @@ -60,15 +70,24 @@ def _confirm_route(

def _route(
self,
page_ref: str, # Name of the page instance
base: "Base", # Reference to base instance
title: str, # Title of the new page
**kwargs,
page_ref: Literal,
base: CTk,
title: str,
**kwargs: Dict[str, bool],
) -> bool:
"""Method for all page-related classes to simplify navigation.
All class instances that use ``_route`` must have their content packed
and contain 4 content generation methods, as seen below.
and contain 4 content generation methods, as seen in the source code.
Args:
page_ref: The new page's name, used to retrieve the corresponding class from `locals()`.
base: The main app instance.
title: The new page's title.
**kwargs: Confirmation dictionary routed to [_confirm_route](base.md#xpuz.base.Addons._confirm_route).
Returns:
Status of the route; whether it was performed or not.
"""
if (
kwargs
Expand Down Expand Up @@ -107,13 +126,19 @@ class Base(CTk, Addons):
"""The main app instance. Contains methods used by all pages."""

base_container: CTkFrame = None
lang_info: Tuple[Dict[str, str], List[str]] = []
locale: Locale = None
cfg: ConfigParser = None
lang_info: Tuple[Dict[str, str], List[str]] = []
locale: Locale = None
cfg: ConfigParser = None
fullscreen: bool = False
page_inst: object = None

def __init__(self, **kwargs) -> None:
def __init__(self, **kwargs: Dict[str, Union[Tuple[Dict[str, str], List[str]], Locale, ConfigParser]]) -> None:
"""Initialise the base instance and container and apply widget scaling,
theme and appearance.
Args:
**kwargs: `lang_info`, `cfg`, and `locale` objects passed from [main](__main__.md#xpuz.__main__.main).
"""
super().__init__()

base_container = CTkFrame(self)
Expand Down Expand Up @@ -141,6 +166,11 @@ def __init__(self, **kwargs) -> None:
self._route(page, self, _(PAGE_MAP[page]))

def _set_dim(self, dim: Tuple[int, int] = DIM) -> None:
"""Set the dimensions of the program during runtime.
Args:
dim: The dimensions.
"""
scale = float(Base.cfg.get("m", "scale"))
new_width = dim[0] * scale
new_height = dim[1] * scale
Expand All @@ -152,6 +182,7 @@ def _set_dim(self, dim: Tuple[int, int] = DIM) -> None:
self.update()

def _toggle_fullscreen(self) -> None:
"""Enable or disabled fullscreen mode."""
Base.fullscreen = not Base.fullscreen
if self.fullscreen:
self.maxsize(self.winfo_screenwidth(), self.winfo_screenheight())
Expand All @@ -171,9 +202,13 @@ def _increment_launches(self) -> None:
def _exit_handler(
self, restart: bool = False, webapp_on: bool = False
) -> None:
"""Called when the event "WM_DELETE_WINDOW" occurs or when the the
"""Called when the event `WM_DELETE_WINDOW` occurs or when the the
program must be restarted, in which case the ``restart`` default
parameter is overridden.
Args:
restart: Whether to perform a restart or not.
webapp_on: Whether the `Flask` web app is running or not.
"""
# If user wants to exit/restart
if GUIHelper.confirm_with_messagebox(exit_=True, restart=restart):
Expand Down
18 changes: 12 additions & 6 deletions src/xpuz/constants.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
"""Constant values used across the source code, defining values such as paths
and colour values for both the GUI and the web application.
NOTE: You can view the attributes that do not belong to any classes in this module
by pressing the `View source of this page` to the left of the table of contents.
"""

from os import path
Expand All @@ -11,9 +14,10 @@


class Colour:
"""Global and light/dark hex colours."""
"""Hex colour specification for both the GUI and the web app."""

class Global:
"""Global hex colours."""
BUTTON: str = "#21528C"
BUTTON_HOVER: str = "#13385F"
EXIT_BUTTON: str = "#ED3B4D"
Expand All @@ -25,6 +29,7 @@ class Global:
DIFFICULTIES: List[str] = ["#089E19", "#FCBA03", "#E01C07", "#6408A6"]

class Light:
"""Light mode hex colours."""
MAIN: str = "#C7D0D4"
SUB: str = "#DFE8ED"
TEXT: str = "#242424"
Expand All @@ -35,6 +40,7 @@ class Light:
WRONG: str = "#FC0A2A"

class Dark:
"""Dark mode hex colours."""
MAIN: str = "#263238"
SUB: str = "#37474F"
TEXT: str = "#D7D6D6"
Expand All @@ -45,7 +51,7 @@ class Dark:
WRONG: str = "#D90D28"


"""Absolute paths used across the source code."""
# Absolute paths used across the source code.
DIR_PATH = Path(__file__).resolve().parents[0]
TEMPLATE_CFG_PATH = path.join(DIR_PATH, "template.config.ini")
DOC_PATH = user_documents_dir()
Expand All @@ -72,7 +78,7 @@ class Dark:
ATTEMPTS_DB_PATH = path.join(DIR_PATH, "data", "attempts_db.json")


"""Crossword-related constants."""
# Crossword-related constants.
DIFFICULTIES: List[str] = ["Easy", "Medium", "Hard", "Extreme"]
ACROSS: str = "ACROSS"
DOWN: str = "DOWN"
Expand All @@ -89,7 +95,7 @@ class Dark:
DIMENSIONS_CONSTANT: int = 1


"""PDF-related constants"""
# PDF-related constants
PDF_WIDTH = 3508
PDF_HEIGHT = 2480
PDF_MARGIN = 150
Expand All @@ -98,7 +104,7 @@ class Dark:
PAGE_DEF_MAX = 25


"""Base english strings"""
# Base english strings
BASE_ENG_CWORD_QUALITIES: List[str] = [
"terrible",
"poor",
Expand All @@ -112,7 +118,7 @@ class Dark:
BASE_ENG_EXPORTS: List[str] = ["PDF", "ipuz"]


"""Misc constants"""
# Misc constants
PYPI_URL = "https://pypi.org/project/xpuz/"
RELEASE_API_URL = (
"https://api.github.com/repos/tomasvana10/xpuz/releases/latest"
Expand Down
Loading

0 comments on commit 56c896b

Please sign in to comment.