valanga 0.1.1__tar.gz → 0.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {valanga-0.1.1/src/valanga.egg-info → valanga-0.1.3}/PKG-INFO +8 -2
- valanga-0.1.3/README.md +43 -0
- {valanga-0.1.1 → valanga-0.1.3}/pyproject.toml +53 -3
- {valanga-0.1.1 → valanga-0.1.3}/src/valanga/__init__.py +2 -2
- {valanga-0.1.1 → valanga-0.1.3}/src/valanga/evaluations.py +1 -1
- {valanga-0.1.1 → valanga-0.1.3}/src/valanga/game.py +3 -1
- valanga-0.1.3/src/valanga/policy.py +42 -0
- {valanga-0.1.1 → valanga-0.1.3/src/valanga.egg-info}/PKG-INFO +8 -2
- {valanga-0.1.1 → valanga-0.1.3}/src/valanga.egg-info/SOURCES.txt +4 -1
- {valanga-0.1.1 → valanga-0.1.3}/src/valanga.egg-info/requires.txt +9 -1
- valanga-0.1.3/tests/test_over_event.py +106 -0
- valanga-0.1.3/tests/test_representation_factory.py +70 -0
- valanga-0.1.1/README.md +0 -2
- {valanga-0.1.1 → valanga-0.1.3}/LICENSE +0 -0
- {valanga-0.1.1 → valanga-0.1.3}/setup.cfg +0 -0
- {valanga-0.1.1 → valanga-0.1.3}/src/valanga/evaluator_types.py +0 -0
- {valanga-0.1.1 → valanga-0.1.3}/src/valanga/over_event.py +0 -0
- {valanga-0.1.1 → valanga-0.1.3}/src/valanga/progress_messsage.py +0 -0
- {valanga-0.1.1 → valanga-0.1.3}/src/valanga/py.typed +0 -0
- {valanga-0.1.1 → valanga-0.1.3}/src/valanga/representation_factory.py +0 -0
- {valanga-0.1.1 → valanga-0.1.3}/src/valanga/represention_for_evaluation.py +0 -0
- {valanga-0.1.1 → valanga-0.1.3}/src/valanga.egg-info/dependency_links.txt +0 -0
- {valanga-0.1.1 → valanga-0.1.3}/src/valanga.egg-info/top_level.txt +0 -0
- {valanga-0.1.1 → valanga-0.1.3}/tests/test_placeholder.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: valanga
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Shared types and utilities for evalaution
|
|
5
5
|
Requires-Python: >=3.13
|
|
6
6
|
License-File: LICENSE
|
|
@@ -8,6 +8,12 @@ Provides-Extra: test
|
|
|
8
8
|
Requires-Dist: pytest>=8.4.1; extra == "test"
|
|
9
9
|
Requires-Dist: coverage; extra == "test"
|
|
10
10
|
Requires-Dist: pytest-cov>=6.0.0; extra == "test"
|
|
11
|
+
Provides-Extra: lint
|
|
12
|
+
Requires-Dist: ruff>=0.14.10; extra == "lint"
|
|
13
|
+
Requires-Dist: pylint>=4.0.4; extra == "lint"
|
|
14
|
+
Provides-Extra: typecheck
|
|
15
|
+
Requires-Dist: mypy>=1.19.1; extra == "typecheck"
|
|
16
|
+
Requires-Dist: pyright[nodejs]>=1.1.408; extra == "typecheck"
|
|
11
17
|
Provides-Extra: dev
|
|
12
18
|
Requires-Dist: tox>=4.32.0; extra == "dev"
|
|
13
19
|
Requires-Dist: types-PyYAML>=6.0.12.12; extra == "dev"
|
|
@@ -15,7 +21,7 @@ Requires-Dist: ruff>=0.14.10; extra == "dev"
|
|
|
15
21
|
Requires-Dist: pylint>=4.0.4; extra == "dev"
|
|
16
22
|
Requires-Dist: black>=25.12.0; extra == "dev"
|
|
17
23
|
Requires-Dist: mypy>=1.19.1; extra == "dev"
|
|
18
|
-
Requires-Dist: pyright>=1.1.
|
|
24
|
+
Requires-Dist: pyright[nodejs]>=1.1.408; extra == "dev"
|
|
19
25
|
Requires-Dist: build; extra == "dev"
|
|
20
26
|
Requires-Dist: twine; extra == "dev"
|
|
21
27
|
Requires-Dist: sphinx; extra == "dev"
|
valanga-0.1.3/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# valanga
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
[](https://github.com/victorgabillon/valanga/actions/workflows/ci.yaml)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
Shared Python types and lightweight utilities for describing turn-based games and their evaluations. The package exposes protocols for representing states, outcomes, and state representations that other libraries can build on.
|
|
8
|
+
|
|
9
|
+
## Key concepts
|
|
10
|
+
- **Game primitives**: `Color`, `BranchKey`, `State`, and related protocols describe whose turn it is, how to enumerate legal branches, and how to copy or advance a state. 【F:src/valanga/game.py†L14-L95】
|
|
11
|
+
- **Evaluations**: `FloatyStateEvaluation` captures heuristic scores while `ForcedOutcome` records a definitive result plus the line of play that forces it. Both are grouped under `BoardEvaluation`. 【F:src/valanga/evaluations.py†L13-L43】
|
|
12
|
+
- **Game termination**: `OverEvent` combines how a game ended with who won, backed by `HowOver` and `Winner` enums. Utility helpers like `is_over()` and `get_over_tag()` simplify downstream checks. 【F:src/valanga/over_event.py†L8-L115】
|
|
13
|
+
- **State representations**: `ContentRepresentation` defines how to turn a `State` into evaluator input, and `RepresentationFactory` builds or updates those representations from states and modifications. 【F:src/valanga/represention_for_evaluation.py†L9-L22】【F:src/valanga/representation_factory.py†L7-L55】
|
|
14
|
+
- **Progress reporting**: `PlayerProgressMessage` communicates per-player progress percentages during long-running work. 【F:src/valanga/progress_messsage.py†L9-L18】
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
```bash
|
|
18
|
+
pip install .
|
|
19
|
+
```
|
|
20
|
+
The project targets Python 3.13 and has no required runtime dependencies.
|
|
21
|
+
|
|
22
|
+
## Quick start
|
|
23
|
+
Below is a minimal example that marks a finished game and obtains an evaluation structure:
|
|
24
|
+
```python
|
|
25
|
+
from valanga import ForcedOutcome, OverEvent
|
|
26
|
+
from valanga.over_event import HowOver, Winner
|
|
27
|
+
|
|
28
|
+
# A checkmate where white wins.
|
|
29
|
+
over_event = OverEvent(how_over=HowOver.WIN, who_is_winner=Winner.WHITE)
|
|
30
|
+
|
|
31
|
+
# Record the forced outcome and the line of optimal moves that lead to it.
|
|
32
|
+
forced = ForcedOutcome(outcome=over_event, line=["e2e4", "e7e5"])
|
|
33
|
+
print(forced.outcome.get_over_tag()) # -> OverTags.TAG_WIN_WHITE
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
To wire in a custom state representation, supply callables to `RepresentationFactory` that know how to build representations from a `State` and its modifications.
|
|
37
|
+
|
|
38
|
+
## Development
|
|
39
|
+
Install the development dependencies and run the test suite:
|
|
40
|
+
```bash
|
|
41
|
+
pip install -e '.[dev]'
|
|
42
|
+
pytest
|
|
43
|
+
```
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "valanga"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.3"
|
|
8
8
|
description = "Shared types and utilities for evalaution"
|
|
9
9
|
requires-python = ">=3.13"
|
|
10
10
|
dependencies = []
|
|
@@ -20,6 +20,16 @@ test = [
|
|
|
20
20
|
"pytest-cov>=6.0.0"
|
|
21
21
|
]
|
|
22
22
|
|
|
23
|
+
lint = [
|
|
24
|
+
"ruff>=0.14.10",
|
|
25
|
+
"pylint>=4.0.4",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
typecheck = [
|
|
29
|
+
"mypy>=1.19.1",
|
|
30
|
+
"pyright[nodejs]>=1.1.408",
|
|
31
|
+
]
|
|
32
|
+
|
|
23
33
|
|
|
24
34
|
dev = [
|
|
25
35
|
# Development dependencies (includes test)
|
|
@@ -33,7 +43,7 @@ dev = [
|
|
|
33
43
|
|
|
34
44
|
# Type checking
|
|
35
45
|
"mypy>=1.19.1",
|
|
36
|
-
"pyright>=1.1.
|
|
46
|
+
"pyright[nodejs]>=1.1.408 ",
|
|
37
47
|
|
|
38
48
|
# Building & publishing
|
|
39
49
|
"build",
|
|
@@ -150,4 +160,44 @@ reportMissingImports = true
|
|
|
150
160
|
reportUnusedImport = true
|
|
151
161
|
reportMissingTypeStubs = false
|
|
152
162
|
reportUnknownMemberType = false
|
|
153
|
-
reportPrivateImportUsage = false
|
|
163
|
+
reportPrivateImportUsage = false
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
#################### TOX ####################
|
|
167
|
+
|
|
168
|
+
[tool.tox]
|
|
169
|
+
min_version = "4.32.0"
|
|
170
|
+
env_list = ["py313", "lint", "typecheck"]
|
|
171
|
+
isolated_build = true
|
|
172
|
+
|
|
173
|
+
[tool.tox.env_run_base]
|
|
174
|
+
base_python = ["python3.13"]
|
|
175
|
+
|
|
176
|
+
[tool.tox.env.py313]
|
|
177
|
+
description = "Run tests"
|
|
178
|
+
extras = ["test"]
|
|
179
|
+
commands = [["pytest", "{posargs}"]]
|
|
180
|
+
|
|
181
|
+
[tool.tox.env.lint]
|
|
182
|
+
description = "ruff + pylint (fast, no package install)"
|
|
183
|
+
package = "skip"
|
|
184
|
+
deps = ["ruff>=0.14.10", "pylint>=4.0.4"]
|
|
185
|
+
set_env = { PYTHONPATH = "{toxinidir}/src" }
|
|
186
|
+
commands = [
|
|
187
|
+
["python", "-m", "ruff", "check", "src", "tests"],
|
|
188
|
+
["python", "-m", "ruff", "format", "--check", "src", "tests"],
|
|
189
|
+
["python", "-m", "pylint", "src/valanga"],
|
|
190
|
+
]
|
|
191
|
+
|
|
192
|
+
[tool.tox.env.typecheck]
|
|
193
|
+
description = "mypy + pyright (fast, no package install)"
|
|
194
|
+
package = "skip"
|
|
195
|
+
deps = ["mypy>=1.19.1", "pyright[nodejs]>=1.1.408"]
|
|
196
|
+
set_env = { MYPYPATH = "{toxinidir}/src" }
|
|
197
|
+
commands = [
|
|
198
|
+
["python", "-m", "mypy", "--config-file", "pyproject.toml", "src/valanga"],
|
|
199
|
+
["python", "-m", "pyright", "src/valanga"],
|
|
200
|
+
]
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
#################### END TOX ####################
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Common types and utilities shared by multiple libraries."""
|
|
2
2
|
|
|
3
|
-
from .evaluations import
|
|
3
|
+
from .evaluations import EvalItem, FloatyStateEvaluation, ForcedOutcome, StateEvaluation
|
|
4
4
|
from .game import (
|
|
5
5
|
BLACK,
|
|
6
6
|
WHITE,
|
|
@@ -22,7 +22,7 @@ from .represention_for_evaluation import ContentRepresentation
|
|
|
22
22
|
__all__ = [
|
|
23
23
|
"ForcedOutcome",
|
|
24
24
|
"FloatyStateEvaluation",
|
|
25
|
-
"
|
|
25
|
+
"StateEvaluation",
|
|
26
26
|
"EvalItem",
|
|
27
27
|
"OverEvent",
|
|
28
28
|
"Color",
|
|
@@ -6,6 +6,8 @@ from collections.abc import Hashable
|
|
|
6
6
|
from enum import Enum
|
|
7
7
|
from typing import Annotated, Iterator, Protocol, Self, Sequence, TypeVar
|
|
8
8
|
|
|
9
|
+
type Seed = Annotated[int, "seed"]
|
|
10
|
+
|
|
9
11
|
type StateTag = Annotated[Hashable, "A label or identifier for a state in a game"]
|
|
10
12
|
|
|
11
13
|
type StateModifications = Annotated[
|
|
@@ -16,7 +18,7 @@ type StateModifications = Annotated[
|
|
|
16
18
|
type BranchKey = Annotated[Hashable, "A label or identifier for a branch in a tree"]
|
|
17
19
|
|
|
18
20
|
|
|
19
|
-
T_co = TypeVar("T_co", bound=BranchKey, covariant=True)
|
|
21
|
+
T_co = TypeVar("T_co", bound=BranchKey, covariant=True, default=BranchKey)
|
|
20
22
|
|
|
21
23
|
|
|
22
24
|
class BranchKeyGeneratorP(Protocol[T_co]):
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Policy-related classes and protocols for branch selection in game trees.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Mapping, Protocol
|
|
7
|
+
|
|
8
|
+
from valanga.evaluations import StateEvaluation
|
|
9
|
+
from valanga.game import BranchKey, Seed, State
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass(frozen=True, slots=True)
|
|
13
|
+
class BranchPolicy:
|
|
14
|
+
"""
|
|
15
|
+
Represents a probability distribution over branches.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
probs: Mapping[BranchKey, float] # should sum to ~1.0
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass(frozen=True, slots=True)
|
|
22
|
+
class Recommendation:
|
|
23
|
+
"""A recommendation for a specific branch in a tree node."""
|
|
24
|
+
|
|
25
|
+
recommended_key: BranchKey
|
|
26
|
+
evaluation: StateEvaluation | None = None
|
|
27
|
+
policy: BranchPolicy | None = None
|
|
28
|
+
branch_evals: Mapping[BranchKey, StateEvaluation] | None = None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class BranchSelector(Protocol):
|
|
32
|
+
"""Protocol for a branch selector."""
|
|
33
|
+
|
|
34
|
+
def recommend(self, state: State, seed: Seed) -> Recommendation:
|
|
35
|
+
"""Given a state and a seed, recommends a branch to take.
|
|
36
|
+
Args:
|
|
37
|
+
state (State): The current state of the game.
|
|
38
|
+
seed (Seed): A seed for any randomness involved in the selection.
|
|
39
|
+
Returns:
|
|
40
|
+
Recommendation: The recommended branch to take.
|
|
41
|
+
"""
|
|
42
|
+
...
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: valanga
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Shared types and utilities for evalaution
|
|
5
5
|
Requires-Python: >=3.13
|
|
6
6
|
License-File: LICENSE
|
|
@@ -8,6 +8,12 @@ Provides-Extra: test
|
|
|
8
8
|
Requires-Dist: pytest>=8.4.1; extra == "test"
|
|
9
9
|
Requires-Dist: coverage; extra == "test"
|
|
10
10
|
Requires-Dist: pytest-cov>=6.0.0; extra == "test"
|
|
11
|
+
Provides-Extra: lint
|
|
12
|
+
Requires-Dist: ruff>=0.14.10; extra == "lint"
|
|
13
|
+
Requires-Dist: pylint>=4.0.4; extra == "lint"
|
|
14
|
+
Provides-Extra: typecheck
|
|
15
|
+
Requires-Dist: mypy>=1.19.1; extra == "typecheck"
|
|
16
|
+
Requires-Dist: pyright[nodejs]>=1.1.408; extra == "typecheck"
|
|
11
17
|
Provides-Extra: dev
|
|
12
18
|
Requires-Dist: tox>=4.32.0; extra == "dev"
|
|
13
19
|
Requires-Dist: types-PyYAML>=6.0.12.12; extra == "dev"
|
|
@@ -15,7 +21,7 @@ Requires-Dist: ruff>=0.14.10; extra == "dev"
|
|
|
15
21
|
Requires-Dist: pylint>=4.0.4; extra == "dev"
|
|
16
22
|
Requires-Dist: black>=25.12.0; extra == "dev"
|
|
17
23
|
Requires-Dist: mypy>=1.19.1; extra == "dev"
|
|
18
|
-
Requires-Dist: pyright>=1.1.
|
|
24
|
+
Requires-Dist: pyright[nodejs]>=1.1.408; extra == "dev"
|
|
19
25
|
Requires-Dist: build; extra == "dev"
|
|
20
26
|
Requires-Dist: twine; extra == "dev"
|
|
21
27
|
Requires-Dist: sphinx; extra == "dev"
|
|
@@ -6,6 +6,7 @@ src/valanga/evaluations.py
|
|
|
6
6
|
src/valanga/evaluator_types.py
|
|
7
7
|
src/valanga/game.py
|
|
8
8
|
src/valanga/over_event.py
|
|
9
|
+
src/valanga/policy.py
|
|
9
10
|
src/valanga/progress_messsage.py
|
|
10
11
|
src/valanga/py.typed
|
|
11
12
|
src/valanga/representation_factory.py
|
|
@@ -15,4 +16,6 @@ src/valanga.egg-info/SOURCES.txt
|
|
|
15
16
|
src/valanga.egg-info/dependency_links.txt
|
|
16
17
|
src/valanga.egg-info/requires.txt
|
|
17
18
|
src/valanga.egg-info/top_level.txt
|
|
18
|
-
tests/
|
|
19
|
+
tests/test_over_event.py
|
|
20
|
+
tests/test_placeholder.py
|
|
21
|
+
tests/test_representation_factory.py
|
|
@@ -6,7 +6,7 @@ ruff>=0.14.10
|
|
|
6
6
|
pylint>=4.0.4
|
|
7
7
|
black>=25.12.0
|
|
8
8
|
mypy>=1.19.1
|
|
9
|
-
pyright>=1.1.
|
|
9
|
+
pyright[nodejs]>=1.1.408
|
|
10
10
|
build
|
|
11
11
|
twine
|
|
12
12
|
sphinx
|
|
@@ -14,7 +14,15 @@ sphinx-rtd-theme
|
|
|
14
14
|
sphinx-autodoc-typehints
|
|
15
15
|
pre-commit
|
|
16
16
|
|
|
17
|
+
[lint]
|
|
18
|
+
ruff>=0.14.10
|
|
19
|
+
pylint>=4.0.4
|
|
20
|
+
|
|
17
21
|
[test]
|
|
18
22
|
pytest>=8.4.1
|
|
19
23
|
coverage
|
|
20
24
|
pytest-cov>=6.0.0
|
|
25
|
+
|
|
26
|
+
[typecheck]
|
|
27
|
+
mypy>=1.19.1
|
|
28
|
+
pyright[nodejs]>=1.1.408
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from valanga.game import Color
|
|
4
|
+
from valanga.over_event import HowOver, OverEvent, OverTags, Winner
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@pytest.mark.parametrize(
|
|
8
|
+
"who, expected",
|
|
9
|
+
[
|
|
10
|
+
(Winner.WHITE, OverTags.TAG_WIN_WHITE),
|
|
11
|
+
(Winner.BLACK, OverTags.TAG_WIN_BLACK),
|
|
12
|
+
],
|
|
13
|
+
)
|
|
14
|
+
def test_get_over_tag_win_outcomes(who, expected):
|
|
15
|
+
event = OverEvent(how_over=HowOver.WIN, who_is_winner=who)
|
|
16
|
+
|
|
17
|
+
assert event.get_over_tag() == expected
|
|
18
|
+
assert event.is_over() is True
|
|
19
|
+
assert event.is_win() is True
|
|
20
|
+
assert event.is_draw() is False
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@pytest.mark.parametrize("winner", [Winner.WHITE, Winner.BLACK])
|
|
24
|
+
def test_is_winner_matches_color(winner):
|
|
25
|
+
event = OverEvent(how_over=HowOver.WIN, who_is_winner=winner)
|
|
26
|
+
|
|
27
|
+
assert event.is_winner(Color.WHITE) is (winner == Winner.WHITE)
|
|
28
|
+
assert event.is_winner(Color.BLACK) is (winner == Winner.BLACK)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@pytest.mark.parametrize(
|
|
32
|
+
"how_over, winner, expected",
|
|
33
|
+
[
|
|
34
|
+
(HowOver.DRAW, Winner.NO_KNOWN_WINNER, OverTags.TAG_DRAW),
|
|
35
|
+
(HowOver.DO_NOT_KNOW_OVER, Winner.NO_KNOWN_WINNER, OverTags.TAG_DO_NOT_KNOW),
|
|
36
|
+
],
|
|
37
|
+
)
|
|
38
|
+
def test_get_over_tag_draw_and_unknown(how_over, winner, expected):
|
|
39
|
+
event = OverEvent(how_over=how_over, who_is_winner=winner)
|
|
40
|
+
|
|
41
|
+
assert event.get_over_tag() == expected
|
|
42
|
+
assert event.is_over() is (how_over == HowOver.DRAW)
|
|
43
|
+
assert event.is_win() is False
|
|
44
|
+
assert event.is_draw() is (how_over == HowOver.DRAW)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@pytest.mark.parametrize(
|
|
48
|
+
"how_over, who_is_winner",
|
|
49
|
+
[
|
|
50
|
+
(HowOver.WIN, Winner.NO_KNOWN_WINNER),
|
|
51
|
+
(HowOver.DRAW, Winner.WHITE),
|
|
52
|
+
],
|
|
53
|
+
)
|
|
54
|
+
def test_post_init_validates_winner_configuration(how_over, who_is_winner):
|
|
55
|
+
with pytest.raises(AssertionError):
|
|
56
|
+
OverEvent(how_over=how_over, who_is_winner=who_is_winner)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@pytest.mark.parametrize("player", [Color.WHITE, Color.BLACK])
|
|
60
|
+
def test_is_winner_requires_win(player):
|
|
61
|
+
event = OverEvent(how_over=HowOver.DRAW, who_is_winner=Winner.NO_KNOWN_WINNER)
|
|
62
|
+
|
|
63
|
+
assert event.is_winner(player) is False
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@pytest.mark.parametrize(
|
|
67
|
+
"how_over, expected_exception",
|
|
68
|
+
[
|
|
69
|
+
(HowOver.WIN, ValueError),
|
|
70
|
+
(None, ValueError),
|
|
71
|
+
],
|
|
72
|
+
)
|
|
73
|
+
def test_get_over_tag_invalid_configurations(how_over, expected_exception):
|
|
74
|
+
event = OverEvent(how_over=HowOver.WIN, who_is_winner=Winner.WHITE)
|
|
75
|
+
event.how_over = how_over # mutate to bypass post-init validation
|
|
76
|
+
event.who_is_winner = Winner.NO_KNOWN_WINNER
|
|
77
|
+
|
|
78
|
+
with pytest.raises(expected_exception):
|
|
79
|
+
event.get_over_tag()
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@pytest.mark.parametrize(
|
|
83
|
+
"how_over, who_is_winner",
|
|
84
|
+
[
|
|
85
|
+
(HowOver.WIN, Winner.WHITE),
|
|
86
|
+
(HowOver.WIN, Winner.BLACK),
|
|
87
|
+
],
|
|
88
|
+
)
|
|
89
|
+
def test_test_method_for_wins(how_over, who_is_winner):
|
|
90
|
+
event = OverEvent(how_over=how_over, who_is_winner=who_is_winner)
|
|
91
|
+
|
|
92
|
+
event.test()
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def test_test_method_invalid_draw_configuration():
|
|
96
|
+
event = OverEvent(how_over=HowOver.DRAW, who_is_winner=Winner.NO_KNOWN_WINNER)
|
|
97
|
+
|
|
98
|
+
with pytest.raises(AssertionError):
|
|
99
|
+
event.test()
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def test_bool_raises():
|
|
103
|
+
event = OverEvent()
|
|
104
|
+
|
|
105
|
+
with pytest.raises(ValueError):
|
|
106
|
+
bool(event)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from collections import Counter
|
|
2
|
+
|
|
3
|
+
from valanga.representation_factory import RepresentationFactory
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class DummyRepresentation:
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_create_from_transition_root_uses_full_creator():
|
|
11
|
+
calls = Counter()
|
|
12
|
+
|
|
13
|
+
def create_from_state(state):
|
|
14
|
+
calls["create_from_state"] += 1
|
|
15
|
+
return ("state", state)
|
|
16
|
+
|
|
17
|
+
factory = RepresentationFactory(
|
|
18
|
+
create_from_state=create_from_state, create_from_state_and_modifications=None
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
result = factory.create_from_transition(
|
|
22
|
+
state="root", previous_state_representation=None, modifications=None
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
assert result == ("state", "root")
|
|
26
|
+
assert calls["create_from_state"] == 1
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_create_from_transition_no_modifications_falls_back_to_state():
|
|
30
|
+
calls = Counter()
|
|
31
|
+
|
|
32
|
+
def create_from_state(state):
|
|
33
|
+
calls["create_from_state"] += 1
|
|
34
|
+
return ("state", state)
|
|
35
|
+
|
|
36
|
+
factory = RepresentationFactory(
|
|
37
|
+
create_from_state=create_from_state, create_from_state_and_modifications=None
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
result = factory.create_from_transition(
|
|
41
|
+
state="child",
|
|
42
|
+
previous_state_representation=DummyRepresentation(),
|
|
43
|
+
modifications=None,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
assert result == ("state", "child")
|
|
47
|
+
assert calls["create_from_state"] == 1
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_create_from_transition_with_modifications():
|
|
51
|
+
calls = Counter()
|
|
52
|
+
|
|
53
|
+
def create_from_state_and_modifications(
|
|
54
|
+
state, state_modifications, previous_state_representation
|
|
55
|
+
):
|
|
56
|
+
calls["create_from_state_and_modifications"] += 1
|
|
57
|
+
return (state, state_modifications, previous_state_representation)
|
|
58
|
+
|
|
59
|
+
factory = RepresentationFactory(
|
|
60
|
+
create_from_state=lambda state: ("unused", state),
|
|
61
|
+
create_from_state_and_modifications=create_from_state_and_modifications,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
previous = DummyRepresentation()
|
|
65
|
+
result = factory.create_from_transition(
|
|
66
|
+
state="child", previous_state_representation=previous, modifications="delta"
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
assert result == ("child", "delta", previous)
|
|
70
|
+
assert calls["create_from_state_and_modifications"] == 1
|
valanga-0.1.1/README.md
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|