Skip to content

Commit

Permalink
Starting point for gen doc by using docstrings
Browse files Browse the repository at this point in the history
  • Loading branch information
lewiuberg authored and eliotwrobson committed Oct 25, 2023
1 parent 0dd51f5 commit 677e4fe
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 16 deletions.
192 changes: 177 additions & 15 deletions automata/base/automaton.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ class Automaton(metaclass=abc.ABCMeta):
input_symbols: AbstractSet[str]

def __init__(self, **kwargs: Any) -> None:
"""
Initialize a complete automaton.
"""
if not global_config.allow_mutable_automata:
for attr_name, attr_value in kwargs.items():
object.__setattr__(self, attr_name, freeze_value(attr_value))
Expand All @@ -37,72 +40,188 @@ def __init__(self, **kwargs: Any) -> None:
self.__post_init__()

def __post_init__(self) -> None:
"""
Perform post-initialization validation of the automaton.
"""
if global_config.should_validate_automata:
self.validate()

@abc.abstractmethod
def validate(self) -> None:
"""Return True if this automaton is internally consistent."""
"""
Return True if this automaton is internally consistent.
Raises
------
NotImplementedError
If this method has not been implemented by a subclass.
"""
raise NotImplementedError

def __setattr__(self, name: str, value: Any) -> NoReturn:
"""Set custom setattr to make class immutable."""
"""
Set custom setattr to make class immutable.
Parameters
----------
name : str
The name of the attribute to set.
value : Any
The value to set the attribute to.
Returns
-------
NoReturn
This method does not return anything as it always raises.
Raises
------
AttributeError
If this method is called.
"""
raise AttributeError(f"This {type(self).__name__} is immutable")

def __delattr__(self, name: str) -> None:
"""Set custom delattr to make class immutable."""
"""
Set custom delattr to make class immutable.
Parameters
----------
name : str
The name of the attribute to delete.
Raises
------
AttributeError
If this method is called.
"""
raise AttributeError(f"This {type(self).__name__} is immutable")

def __getstate__(self) -> Any:
"""Return the object's state, described by its input parameters"""
"""
Return the object's state, described by its input parameters.
Returns
-------
Any
The object's state, described by its input parameters.
"""
return self.input_parameters

def __setstate__(self, d: Dict[str, Any]) -> None:
"""Restore the object state from its input parameters"""
"""
Restore the object state from its input parameters.
Parameters
----------
d : Dict[str, Any]
The object's input parameters.
"""
# Notice that the default __setstate__ method won't work
# because __setattr__ is disabled due to immutability
self.__init__(**d) # type: ignore

@abc.abstractmethod
def read_input_stepwise(self, input_str: str) -> Generator[Any, None, None]:
"""Return a generator that yields each step while reading input."""
"""
Return a generator that yields each step while reading input.
Parameters
----------
input_str : str
The input string to read.
Yields
------
Generator[Any, None, None]
A generator that yields the current configuration of the automaton
after each step of reading input.
Raises
------
NotImplementedError
If this method has not been implemented by a subclass.
"""
raise NotImplementedError

def read_input(self, input_str: str) -> AutomatonStateT:
"""
Check if the given string is accepted by this automaton.
Return the automaton's final configuration if this string is valid.
Parameters
----------
input_str : str
The input string to check.
Returns
-------
AutomatonStateT
The final configuration of the automaton after reading the input.
"""
# "Fast-forward" generator to get its final value
for config in self.read_input_stepwise(input_str):
pass
return config

def accepts_input(self, input_str: str) -> bool:
"""Return True if this automaton accepts the given input."""
"""
Return True if this automaton accepts the given input.
Parameters
----------
input_str : str
The input string to check.
Returns
-------
bool
True if this automaton accepts the given input; False otherwise.
"""
try:
self.read_input(input_str)
return True
except exceptions.RejectionException:
return False

def _validate_initial_state(self) -> None:
"""Raise an error if the initial state is invalid."""
"""
Raise an error if the initial state is invalid.
Raises
------
exceptions.InvalidStateError
If the initial state is invalid.
"""
if self.initial_state not in self.states:
raise exceptions.InvalidStateError(
"{} is not a valid initial state".format(self.initial_state)
)

def _validate_initial_state_transitions(self) -> None:
"""Raise an error if the initial state has no transitions defined."""
"""
Raise an error if the initial state has no transitions defined.
Raises
------
exceptions.MissingStateError
If the initial state has no transitions defined.
"""
if self.initial_state not in self.transitions and len(self.states) > 1:
raise exceptions.MissingStateError(
"initial state {} has no transitions defined".format(self.initial_state)
)

def _validate_final_states(self) -> None:
"""Raise an error if any final states are invalid."""
"""
Raise an error if any final states are invalid.
Raises
------
exceptions.InvalidStateError
If any final states are invalid.
"""
invalid_states = self.final_states - self.states
if invalid_states:
raise exceptions.InvalidStateError(
Expand All @@ -113,15 +232,29 @@ def _validate_final_states(self) -> None:

@property
def input_parameters(self) -> Dict[str, Any]:
"""Return the public attributes for this automaton."""
"""
Return the public attributes for this automaton.
Returns
-------
Dict[str, Any]
A dictionary mapping attribute names to their values.
"""
return {
attr_name: getattr(self, attr_name)
for attr_name in self.__slots__
if not attr_name.startswith("_")
}

def copy(self) -> Self:
"""Create a deep copy of the automaton."""
"""
Create a deep copy of the automaton.
Returns
-------
Self
A deep copy of the automaton.
"""
return self.__class__(**self.input_parameters)

# Format the given value for string output via repr() or str(); this exists
Expand All @@ -131,7 +264,17 @@ def _get_repr_friendly_value(self, value: Any) -> Any:
"""
A helper function to convert the given value / structure into a fully
mutable one by recursively processing said structure and any of its
members, unfreezing them along the way
members, unfreezing them along the way.
Parameters
----------
value : Any
The value to convert.
Returns
-------
Any
A representation-friendly version of the given value.
"""
if isinstance(value, frozenset):
return set(value)
Expand All @@ -144,15 +287,34 @@ def _get_repr_friendly_value(self, value: Any) -> Any:
return value

def __repr__(self) -> str:
"""Return a string representation of the automaton."""
"""
Return a string representation of the automaton.
Returns
-------
str
A string representation of the automaton.
"""
values = ", ".join(
f"{attr_name}={self._get_repr_friendly_value(attr_value)!r}"
for attr_name, attr_value in self.input_parameters.items()
)
return f"{self.__class__.__qualname__}({values})"

def __contains__(self, item: Any) -> bool:
"""Returns whether the word is accepted by the automaton."""
"""
Returns whether the word is accepted by the automaton.
Parameters
----------
item : Any
The item to check.
Returns
-------
bool
_description_
"""

if not isinstance(item, str):
return False
Expand Down
7 changes: 7 additions & 0 deletions docs/api/class-automaton.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
author: "Lewi Lie Uberg"
---

# class Automaton(metaclass=ABCMeta)

::: automata.base.automaton.Automaton
7 changes: 7 additions & 0 deletions docs/api/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
author: "Lewi Lie Uberg"
---

# API

This is the API documentation generated by the class and method docstrings for the `automata` package.
11 changes: 11 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ plugins:
# enabled_if_env: ENABLE_PDF_EXPORT
- macros:
enabled_if_env: ENABLE_PDF_EXPORT
- mkdocstrings:
enabled: !ENV [ENABLE_MKDOCSTRINGS, true]
custom_templates: templates
default_handler: python
handlers:
python:
options:
show_source: false
markdown_extensions:
- toc:
permalink: true
Expand Down Expand Up @@ -113,6 +121,9 @@ extra:
# - javascripts/extra.js
copyright: Copyright © 2016 - 2023 Caleb Evans
nav:
- API:
- api/index.md
- Class Automaton: api/class-automaton.md
- API Documentation:
- Class Automaton:
- class-automaton.md
Expand Down
4 changes: 3 additions & 1 deletion requirements.docs.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mkdocs==1.4.2
mkdocs-material==9.1.9
mkdocs-macros-plugin==0.7.0
mkdocs-macros-plugin==0.7.0
mkdocstrings==0.23.0
mkdocstrings-python==1.7.3

0 comments on commit 677e4fe

Please sign in to comment.