Skip to content
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
43 changes: 43 additions & 0 deletions tests/data/storyformat.st.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
movie: Good Format (2000)
=========================

:: Title
Good Format

:: Date
2000-01-01

:: Description
A story with a recognized story format.

:: Story Format
film


movie: Bad Format (2001)
========================

:: Title
Bad Format

:: Date
2001-01-01

:: Description
A story with an unrecognized story format.

:: Story Format
graphic novel


movie: No Format (2002)
=======================

:: Title
No Format

:: Date
2002-01-01

:: Description
A story that omits the story format field entirely.
10 changes: 10 additions & 0 deletions tests/test_totolo.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,16 @@ def test_multiple_entries(self):
warnings = list(ontology._impl.validate_entries())
assert any("Multiple TOStory with name" in x for x in warnings)

def test_storyformat_warning(self):
ontology = totolo.files("tests/data/storyformat.st.txt")
warnings = list(ontology._impl.validate_storyformat())
assert any("Bad Format" in x and "graphic novel" in x for x in warnings)
assert not any("Good Format" in x for x in warnings)
assert not any("No Format" in x for x in warnings)
# surfaces through the public validate() entry point as well
assert any(
"Unrecognized 'story format'" in x for x in ontology.validate()
)
def test_component_warning(self):
ontology = totolo.files("tests/data/dangling-component.st.txt")
warnings = list(ontology._impl.validate_components())
Expand Down
2 changes: 1 addition & 1 deletion totolo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@


remote = TORemote()
__version__ = "2.1.4"
__version__ = "2.2.0"
__ALL__ = [
empty,
files,
Expand Down
21 changes: 21 additions & 0 deletions totolo/impl/to_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@
from .to_containers import TODict


#: Permitted values for the optional "Story Format" field on a story. This is a
#: high-level, objective classification of the medium (not genre). The field may
#: be omitted entirely; if present it must be one of these values.
STORY_FORMATS = frozenset({
"film",
"tv",
"stage",
"prose",
"game",
})


class TOBase(TOObject):
story = a(TODict)
theme = a(TODict)
Expand Down Expand Up @@ -159,6 +171,7 @@ def organize_collections(self):
def validate(self):
yield from self._impl.validate_entries()
yield from self._impl.validate_storythemes()
yield from self._impl.validate_storyformat()
yield from self._impl.validate_components()
yield from self._impl.validate_cycles()

Expand Down Expand Up @@ -300,6 +313,14 @@ def validate_storythemes(self):
yield (f"{story.name}: Undefined '{weight} theme' with "
f"name '{kwfield.keyword}'")

def validate_storyformat(self):
"""Detect stories whose 'Story Format' is set to an unrecognized value."""
for story in self.o.stories():
value = str(story.get("Story Format")).strip()
if value and value not in STORY_FORMATS:
allowed = ", ".join(sorted(STORY_FORMATS))
yield (f"{story.name}: Unrecognized 'story format' "
f"'{value}' (expected one of: {allowed})")
def validate_components(self):
"""Detect component stories of collections that reference undefined stories."""
for story in self.o.stories():
Expand Down
1 change: 1 addition & 0 deletions totolo/story.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class TOStory(TOEntry):
Collections = sa("list")
Component_Stories = sa("list")
Related_Stories = sa("list")
Story_Format = sa("text")
Choice_Themes = sa("kwlist")
Major_Themes = sa("kwlist")
Minor_Themes = sa("kwlist")
Expand Down
Loading