Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added documentation and types for prolog and examples packages #184

Merged
merged 2 commits into from
Oct 20, 2024
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
4 changes: 3 additions & 1 deletion .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ version: 2

# Set the OS, Python version and other tools you might need
build:
os: ubuntu-22.04
os: ubuntu-24.04
tools:
python: "3.12"
apt_packages:
- swi-prolog-nox

# Build documentation in the "docs/" directory with Sphinx
sphinx:
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.PHONY: build clean coverage upload-coverage test upload

build:
build
pyproject-build

clean:
rm -rf dist build pyswip.egg-info
Expand Down
3 changes: 2 additions & 1 deletion dev-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ ruff==0.6.2
build
pytest-cov
mypy>=1.0.0
Sphinx
Sphinx
sphinx-autodoc-typehints
11 changes: 11 additions & 0 deletions docs/source/api/examples.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Examples
--------

.. automodule:: pyswip.examples
:members:

Sudoku
^^^^^^

.. automodule:: pyswip.examples.sudoku
:members:
10 changes: 10 additions & 0 deletions docs/source/api/modules.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
API Documentation
-----------------

.. toctree::

examples
prolog



5 changes: 5 additions & 0 deletions docs/source/api/prolog.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Prolog
------

.. automodule:: pyswip.prolog
:members:
17 changes: 16 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,18 @@
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

import sys
from pathlib import Path

sys.path.insert(0, str(Path("..", "..", "src").resolve()))

from pyswip import __VERSION__

project = "PySwip"
copyright = "2024, Yüce Tekol and PySwip Contributors"
author = "Yüce Tekol and PySwip Contributors"
version = __VERSION__
release = version

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand All @@ -17,6 +26,7 @@
"sphinx.ext.duration",
"sphinx.ext.doctest",
"sphinx.ext.autodoc",
"sphinx_autodoc_typehints",
]

templates_path = ["_templates"]
Expand All @@ -26,11 +36,16 @@
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

html_theme = "alabaster"
html_theme = "bizstyle"
html_static_path = ["_static"]

source_suffix = {
".rst": "restructuredtext",
".txt": "markdown",
".md": "markdown",
}

autodoc_member_order = "bysource"
autoclass_content = "both"

html_logo = "https://pyswip.org/images/pyswip_logo_sm_256colors.gif"
9 changes: 9 additions & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,13 @@ It features an SWI-Prolog foreign language interface, a utility class that makes
:caption: Contents:

get_started
api/modules

Indices and Tables
==================

.. toctree::

genindex
modindex

10 changes: 8 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ keywords = [
"prolog",
]
classifiers = [
"Development Status :: 3 - Alpha",
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Intended Audience :: Science/Research",
"License :: OSI Approved :: MIT License",
Expand All @@ -45,4 +45,10 @@ ignore = ["F403", "F405", "E721"]
[tool.pytest.ini_options]
markers = [
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
]
]

[tool.setuptools.package-data]
"pyswip" = ["py.typed"]

[tool.setuptools.packages.find]
where = ["src"]
104 changes: 90 additions & 14 deletions src/pyswip/examples/sudoku.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,20 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import sys
from typing import List, Union, Literal
"""
Sudoku example

You can run this module using::

$ python3 -m pyswip.examples.sudoku
"""

from typing import List, Union, Literal, Optional, IO
from io import StringIO

from pyswip.prolog import Prolog


__all__ = "Matrix", "solve", "prolog_source"
__all__ = "Matrix", "prolog_source", "sample_puzzle", "solve"

_DIMENSION = 9
_SOURCE_PATH = "sudoku.pl"
Expand All @@ -38,6 +44,8 @@


class Matrix:
"""Represents a 9x9 Sudoku puzzle"""

def __init__(self, matrix: List[List[int]]) -> None:
if not matrix:
raise ValueError("matrix must be given")
Expand All @@ -49,7 +57,33 @@ def __init__(self, matrix: List[List[int]]) -> None:

@classmethod
def from_text(cls, text: str) -> "Matrix":
lines = text.strip().split("\n")
"""
Create a Matrix from the given string

The following are valid characters in the string:

* `.`: Blank column
* `1-9`: Numbers

The text must contain exactly 9 rows and 9 columns.
Each row ends with a newline character.
You can use blank lines and spaces/tabs between columns.

:param text: The text to use for creating the Matrix

>>> puzzle = Matrix.from_text('''
... . . 5 . 7 . 2 6 8
... . . 4 . . 2 . . .
... . . 1 . 9 . . . .
... . 8 . . . . 1 . .
... . 2 . 9 . . . 7 .
... . . 6 . . . . 3 .
... . . 2 . 4 . 7 . .
... . . . 5 . . 9 . .
... 9 5 7 . 3 . . . .
... ''')
"""
lines = [row for line in text.strip().split("\n") if (row := line.strip())]
dimension = len(lines)
rows = []
for i, line in enumerate(lines):
Expand Down Expand Up @@ -82,7 +116,25 @@ def __str__(self) -> str:
def __repr__(self) -> str:
return str(self.matrix)

def pretty_print(self, *, file=sys.stdout) -> None:
def pretty_print(self, *, file: Optional[IO] = None) -> None:
"""
Prints the matrix as a grid

:param file: The file to use for printing

>>> import sys
>>> puzzle = sample_puzzle()
>>> puzzle.pretty_print(file=sys.stdout)
. . 5 . 7 . 2 6 8
. . 4 . . 2 . . .
. . 1 . 9 . . . .
. 8 . . . . 1 . .
. 2 . 9 . . . 7 .
. . 6 . . . . 3 .
. . 2 . 4 . 7 . .
. . . 5 . . 9 . .
9 5 7 . 3 . . . .
"""
for row in self.matrix:
row = " ".join(str(x or ".") for x in row)
print(row, file=file)
Expand All @@ -92,12 +144,29 @@ def solve(matrix: Matrix) -> Union[Matrix, Literal[False]]:
"""
Solves the given Sudoku puzzle

Parameters:
matrix (Matrix): The matrix that contains the Sudoku puzzle

Returns:
Matrix: Solution matrix
False: If no solutions was found
:param matrix: The matrix that contains the Sudoku puzzle

>>> puzzle = sample_puzzle()
>>> print(puzzle)
. . 5 . 7 . 2 6 8
. . 4 . . 2 . . .
. . 1 . 9 . . . .
. 8 . . . . 1 . .
. 2 . 9 . . . 7 .
. . 6 . . . . 3 .
. . 2 . 4 . 7 . .
. . . 5 . . 9 . .
9 5 7 . 3 . . . .
>>> print(solve(puzzle))
3 9 5 4 7 1 2 6 8
8 7 4 6 5 2 3 9 1
2 6 1 3 9 8 5 4 7
5 8 9 7 6 3 1 2 4
1 2 3 9 8 4 6 7 5
7 4 6 2 1 5 8 3 9
6 1 2 8 4 9 7 5 3
4 3 8 5 2 7 9 1 6
9 5 7 1 3 6 4 8 2
"""
p = repr(matrix).replace("0", "_")
result = list(Prolog.query(f"L={p},sudoku(L)", maxresult=1))
Expand All @@ -110,15 +179,17 @@ def solve(matrix: Matrix) -> Union[Matrix, Literal[False]]:


def prolog_source() -> str:
"""Returns the Prolog source file that solves Sudoku puzzles"""
from pathlib import Path

path = Path(__file__).parent / _SOURCE_PATH
with open(path) as f:
return f.read()


def main():
puzzle = Matrix.from_text("""
def sample_puzzle() -> Matrix:
"""Returns the sample Sudoku puzzle"""
matrix = Matrix.from_text("""
. . 5 . 7 . 2 6 8
. . 4 . . 2 . . .
. . 1 . 9 . . . .
Expand All @@ -129,6 +200,11 @@ def main():
. . . 5 . . 9 . .
9 5 7 . 3 . . . .
""")
return matrix


def main():
puzzle = sample_puzzle()
print("\n-- PUZZLE --")
puzzle.pretty_print()
print("\n-- SOLUTION --")
Expand Down
Loading