Skip to content

Commit

Permalink
Merge pull request #9 from avrae/build/hypothesis
Browse files Browse the repository at this point in the history
Blackify code, Hypothesis testing
  • Loading branch information
zhudotexe committed Nov 20, 2022
2 parents 591b1aa + 9315a61 commit ad2ce25
Show file tree
Hide file tree
Showing 17 changed files with 384 additions and 111 deletions.
24 changes: 24 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Code Style

on:
[ push, pull_request ]

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0

- name: Set up Python 3.10
uses: actions/setup-python@v2
with:
python-version: "3.10"

- name: Install black
run: pip install black

- name: Ensure code is blackified
run: black . --check --diff
14 changes: 8 additions & 6 deletions .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
@@ -1,38 +1,40 @@
name: Test Package

on: [push]
on: [ push ]

jobs:
build:

runs-on: ubuntu-latest
strategy:
max-parallel: 4
matrix:
python-version: [3.6, 3.7, 3.8]
python-version: [ 3.6, 3.7, 3.8, 3.9, "3.10", "3.x" ]

steps:
- uses: actions/checkout@v1

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r tests/requirements.txt
- name: Lint with flake8
run: |
pip install flake8
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
run: |
pip install pytest
pip install pytest-cov
pytest --cov=./ --cov-report=xml --cov-config=.coveragerc
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
with:
Expand Down
42 changes: 24 additions & 18 deletions d20/dice.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,20 @@

__all__ = ("CritType", "AdvType", "RollContext", "RollResult", "Roller")

POSSIBLE_COMMENT_AMBIGUITIES = {"*", }
POSSIBLE_COMMENT_AMBIGUITIES = {
"*",
}

TreeType = TypeVar('TreeType', bound=ast.ChildMixin)
ASTNode = TypeVar('ASTNode', bound=ast.Node)
ExpressionNode = TypeVar('ExpressionNode', bound=Number)
TreeType = TypeVar("TreeType", bound=ast.ChildMixin)
ASTNode = TypeVar("ASTNode", bound=ast.Node)
ExpressionNode = TypeVar("ExpressionNode", bound=Number)


class CritType(IntEnum):
"""
Integer enumeration representing the crit type of a roll.
"""

NONE = 0
CRIT = 1
FAIL = 2
Expand All @@ -31,6 +34,7 @@ class AdvType(IntEnum):
"""
Integer enumeration representing at what advantage a roll should be made at.
"""

NONE = 0
ADV = 1
DIS = -1
Expand Down Expand Up @@ -147,16 +151,18 @@ def __init__(self, context: Optional[RollContext] = None):
ast.OperatedSet: self._eval_operatedset,
ast.NumberSet: self._eval_numberset,
ast.OperatedDice: self._eval_operateddice,
ast.Dice: self._eval_dice
ast.Dice: self._eval_dice,
}
self._parse_cache: MutableMapping[str, ASTNode] = cachetools.LFUCache(256)
self.context: RollContext = context

def roll(self,
expr: Union[str, ASTNode],
stringifier: Optional[Stringifier] = None,
allow_comments: bool = False,
advantage: AdvType = AdvType.NONE) -> RollResult:
def roll(
self,
expr: Union[str, ASTNode],
stringifier: Optional[Stringifier] = None,
allow_comments: bool = False,
advantage: AdvType = AdvType.NONE,
) -> RollResult:
"""
Rolls the dice.
Expand Down Expand Up @@ -206,28 +212,28 @@ def parse(self, expr: str, allow_comments: bool = False) -> ast.Expression:

def _parse_no_comment(self, expr: str) -> ast.Expression:
# see if this expr is in cache
clean_expr = expr.replace(' ', '')
clean_expr = expr.replace(" ", "")
if clean_expr in self._parse_cache:
return self._parse_cache[clean_expr]
dice_tree = ast.parser.parse(expr, start='expr')
dice_tree = ast.parser.parse(expr, start="expr")
self._parse_cache[clean_expr] = dice_tree
return dice_tree

def _parse_with_comments(self, expr: str) -> ast.Expression:
try:
return ast.parser.parse(expr, start='commented_expr')
return ast.parser.parse(expr, start="commented_expr")
except lark.UnexpectedInput as ui:
# if the statement up to the unexpected token ends with an operator, remove that from the end
successful_fragment = expr[:ui.pos_in_stream]
successful_fragment = expr[: ui.pos_in_stream]
for op in POSSIBLE_COMMENT_AMBIGUITIES:
if successful_fragment.endswith(op):
successful_fragment = successful_fragment[:-len(op)]
force_comment = expr[len(successful_fragment):]
successful_fragment = successful_fragment[: -len(op)]
force_comment = expr[len(successful_fragment) :]
break
else:
raise
# and parse again (handles edge cases like "1d20 keep the dragon grappled")
result = ast.parser.parse(successful_fragment, start='commented_expr')
result = ast.parser.parse(successful_fragment, start="commented_expr")
result.comment = force_comment
return result

Expand All @@ -243,7 +249,7 @@ def _eval_expression(self, node: ast.Expression) -> Expression:

def _eval_annotatednumber(self, node: ast.AnnotatedNumber) -> ExpressionNode:
target = self._eval(node.value)
target.annotation = ''.join(node.annotations)
target.annotation = "".join(node.annotations)
return target

def _eval_literal(self, node: ast.Literal) -> Literal:
Expand Down
17 changes: 10 additions & 7 deletions d20/diceast.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ def __str__(self):

class Expression(Node): # expr
"""Expressions are usually the root of all ASTs."""

__slots__ = ("roll", "comment")

def __init__(self, roll, comment=None):
Expand All @@ -173,6 +174,7 @@ def __str__(self):

class AnnotatedNumber(Node): # numexpr
"""Represents a value with an annotation."""

__slots__ = ("value", "annotations")

def __init__(self, value, *annotations):
Expand Down Expand Up @@ -205,7 +207,7 @@ def __init__(self, value):
"""
super().__init__()
if isinstance(value, Token):
self.value = int(value) if value.type == 'INTEGER' else float(value)
self.value = int(value) if value.type == "INTEGER" else float(value)
else:
self.value = value

Expand Down Expand Up @@ -437,15 +439,16 @@ def __str__(self):
return f"{self.num}d{self.size}"


with open(os.path.join(os.path.dirname(__file__), 'grammar.lark')) as f:
with open(os.path.join(os.path.dirname(__file__), "grammar.lark")) as f:
grammar = f.read()
parser = Lark(grammar, start=['expr', 'commented_expr'], parser='lalr', transformer=RollTransformer(),
maybe_placeholders=True)
parser = Lark(
grammar, start=["expr", "commented_expr"], parser="lalr", transformer=RollTransformer(), maybe_placeholders=True
)

if __name__ == '__main__':
if __name__ == "__main__":
while True:
parser = Lark(grammar, start=['expr', 'commented_expr'], parser='lalr', maybe_placeholders=True)
result = parser.parse(input(), start='expr')
parser = Lark(grammar, start=["expr", "commented_expr"], parser="lalr", maybe_placeholders=True)
result = parser.parse(input(), start="expr")
print(result.pretty())
print(result)
expr = RollTransformer().transform(result)
Expand Down
8 changes: 6 additions & 2 deletions d20/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,20 @@ def __init__(self, line, col, got, expected):
self.got = got
self.expected = expected

msg = f"Unexpected input on line {line}, col {col}: expected {', '.join([str(ex) for ex in expected])}, " \
f"got {str(got)}"
msg = (
f"Unexpected input on line {line}, col {col}: expected {', '.join([str(ex) for ex in expected])}, "
f"got {str(got)}"
)
super().__init__(msg)


class RollValueError(RollError):
"""A bad value was passed to an operator."""

pass


class TooManyRolls(RollError):
"""Too many dice rolled (in an individual dice or in rerolls)."""

pass
Loading

0 comments on commit ad2ce25

Please sign in to comment.