From aecdae1127efa18b2bfad3c49add38e5a5151848 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Moreno Date: Thu, 23 Nov 2023 20:24:12 +0100 Subject: [PATCH 1/4] rename test to make it compatible with pytest --- .github/workflows/pylint.yml | 2 +- README.md | 2 +- tests/{story_tests.py => test_story.py} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename tests/{story_tests.py => test_story.py} (100%) diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index bb65a9c..95196eb 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -24,4 +24,4 @@ jobs: pylint $(git ls-files 'bink/*.py') - name: Run tests run: | - python -m unittest -v tests/story_tests.py + python -m unittest discover diff --git a/README.md b/README.md index b4a290a..e45e48e 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,6 @@ print("Story ended ok.") We can execute Python tests in the `tests` folder using the next command: ```bash -$ python -m unittest -v tests/story_tests.py +$ python -m unittest discover ``` diff --git a/tests/story_tests.py b/tests/test_story.py similarity index 100% rename from tests/story_tests.py rename to tests/test_story.py From b0dd292fb7b634909d57d7131a911f499e72013d Mon Sep 17 00:00:00 2001 From: Daniel Garcia Moreno Date: Thu, 23 Nov 2023 20:43:01 +0100 Subject: [PATCH 2/4] choices: Make Choices class more pythonic This patch implements the __len__, __bool__, __getitem__ and __iter__ magic methods in the Choices class to make it possible to write more pythonic code and just use it like a python list. --- README.md | 7 +++---- bink/choices.py | 33 ++++++++++++++++++++++++++++++++- tests/test_story.py | 7 +++---- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e45e48e..624329d 100644 --- a/README.md +++ b/README.md @@ -30,11 +30,10 @@ while not end: # Obtain and print choices choices = story.get_current_choices() - print(f"Num. choices: {choices.len()}\n") + print(f"Num. choices: {len(choices)}\n") - if choices.len() != 0: - for i in range(choices.len()): - text = choices.get_text(i) + if choices: + for i, text in enumerate(choices): print(f"{i + 1}. {text}") # read_input() is a method that you should implement diff --git a/bink/choices.py b/bink/choices.py index 36d0e5a..2ee6a22 100644 --- a/bink/choices.py +++ b/bink/choices.py @@ -3,16 +3,47 @@ import ctypes from bink import LIB, BINK_OK + +class ChoicesIterator: + def __init__(self, choices): + self._choices = choices + self._index = 0 + + def __next__(self): + if self._index >= len(self._choices): + raise StopIteration + + self._index += 1 + return self._choices[self._index - 1] + + class Choices: """List of story choices.""" def __init__(self, choices, c_len: int): self._choices = choices self._len = c_len - def len(self) -> int: + def __len__(self) -> int: """Returns the number of choices.""" return self._len + def __bool__(self) -> bool: + return self._len != 0 + + def __iter__(self): + return ChoicesIterator(self) + + def __getitem__(self, idx: int) -> str: + """Returns the choice text""" + + if not isinstance(idx, int): + raise TypeError + + if idx < 0 or idx > self._len: + raise IndexError + + return self.get_text(idx) + def get_text(self, idx) -> str: """Returns the choice text.""" text = ctypes.c_char_p() diff --git a/tests/test_story.py b/tests/test_story.py index 5cc18b1..b5da156 100644 --- a/tests/test_story.py +++ b/tests/test_story.py @@ -22,11 +22,10 @@ def test_the_intercept(self): # Obtain and print choices choices = story.get_current_choices() - print(f"Num. choices: {choices.len()}\n") + print(f"Num. choices: {len(choices)}\n") - if choices.len() != 0: - for i in range(choices.len()): - text = choices.get_text(i) + if choices: + for i, text in enumerate(choices): print(f"{i + 1}. {text}") # Always choose the first option From 2be1c12b3c5008ab6a5fafe043520b2b133410a0 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Moreno Date: Thu, 23 Nov 2023 20:49:26 +0100 Subject: [PATCH 3/4] tags: Make Tags class more pythonic --- bink/tags.py | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/bink/tags.py b/bink/tags.py index b0f0723..a305dff 100644 --- a/bink/tags.py +++ b/bink/tags.py @@ -4,16 +4,47 @@ import ctypes from bink import LIB, BINK_OK + +class TagsIterator: + def __init__(self, tags): + self._tags = tags + self._index = 0 + + def __next__(self): + if self._index >= len(self._tags): + raise StopIteration + + self._index += 1 + return self._tags[self._index - 1] + + class Tags: """Contains a list of tags.""" def __init__(self, tags, c_len): self._tags = tags self._len = c_len - def len(self) -> int: - """Returns the number of choices.""" + def __len__(self) -> int: + """Returns the number of tags.""" return self._len + def __bool__(self) -> bool: + return self._len != 0 + + def __iter__(self): + return TagsIterator(self) + + def __getitem__(self, idx: int) -> str: + """Returns the tag text""" + + if not isinstance(idx, int): + raise TypeError + + if idx < 0 or idx > self._len: + raise IndexError + + return self.get(idx) + def get(self, idx) -> str: """Returns the tag text.""" tag = ctypes.c_char_p() From a1a423e65d3d7b24d0fa7d23e56291a5239caa93 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Moreno Date: Thu, 23 Nov 2023 21:04:25 +0100 Subject: [PATCH 4/4] story: Add iterator and properties for Story class --- bink/story.py | 18 ++++++++++++++++++ tests/test_story.py | 6 ++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/bink/story.py b/bink/story.py index d08062f..434e374 100644 --- a/bink/story.py +++ b/bink/story.py @@ -6,6 +6,7 @@ from bink.tags import Tags from bink import LIB, BINK_OK + class Story: """Story is the entry point of the Blade Ink lib.""" def __init__(self, story_string: str): @@ -22,6 +23,23 @@ def __init__(self, story_string: str): self._story = story + def __next__(self): + if not self.can_continue(): + raise StopIteration + + return self.cont() + + def __iter__(self): + return self + + @property + def choices(self): + return self.get_current_choices() + + @property + def tags(self): + return self.get_current_tags() + def can_continue(self): can_continue = ctypes.c_bool() ret = LIB.bink_story_can_continue( diff --git a/tests/test_story.py b/tests/test_story.py index b5da156..cedc4e6 100644 --- a/tests/test_story.py +++ b/tests/test_story.py @@ -15,13 +15,11 @@ def test_the_intercept(self): end = False while not end: - while story.can_continue(): - line = story.cont() + for line in story: print(line) # Assuming 'line' is a byte-like object # Obtain and print choices - choices = story.get_current_choices() - + choices = story.choices print(f"Num. choices: {len(choices)}\n") if choices: