Skip to content

Commit

Permalink
Beat None handling (#105)
Browse files Browse the repository at this point in the history
* Adding test to show what should happen for #101
* Adding ability to differentiate between certain types of functions.
* removing inheritance from test example question
  • Loading branch information
bandophahita authored Oct 12, 2023
1 parent 789b11c commit bb4ea34
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 3 deletions.
15 changes: 13 additions & 2 deletions screenpy/pacing.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
(cases), and provide the gravitas (severity) of those groupings; or markers
for moments the Narrator should narrate.
"""

import re
from functools import wraps
from typing import Any, Callable, Optional
Expand All @@ -13,9 +12,21 @@
from screenpy.speech_tools import represent_prop

Function = Callable[..., Any]

the_narrator: Narrator = Narrator(adapters=[StdOutAdapter()])


def function_should_log_none(func: Function) -> bool:
"""Helper function to decide when to log return values.
Determine if function is attached to one of the protocols that allow for anything
to return.
"""
if func.__annotations__ and "return" in func.__annotations__:
return func.__annotations__["return"] is not None
return False


def act(title: str, gravitas: Optional[str] = None) -> Callable[[Function], Function]:
"""Decorator to mark an "act".
Expand Down Expand Up @@ -89,7 +100,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any:
completed_line = f"{line.format(actor, **cues)}"
with the_narrator.stating_a_beat(func, completed_line, gravitas) as n_func:
retval = n_func(*args, **kwargs)
if retval is not None:
if retval is not None or function_should_log_none(func):
aside(f"=> {represent_prop(retval)}")
return retval

Expand Down
81 changes: 80 additions & 1 deletion tests/test_pacing.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from screenpy import act, aside, beat, scene
import logging
from typing import Optional

from screenpy import Actor, IsEqualTo, See, act, aside, beat, scene


def prop():
Expand All @@ -18,6 +21,52 @@ def use(self):
pass


class NonesyQuestion:
@beat("{} examines NonesyQuestion")
def answered_by(self, _: Actor) -> object:
return None

def describe(self) -> str:
return "NonesyQuestion"


class CornerCase:
@beat("{} examines CornerCase")
def answered_by(self, _: Actor) -> object:
self.do_not_log_me_man()
self.does_return_something()
self.no_annotations_rt_none(False)
self.no_annotations_rt_int(True)
return None

@beat("Blah!")
def do_not_log_me_man(self) -> None:
return None

@beat("Foobar...")
def does_return_something(self, toggle: bool = False) -> Optional[int]:
if toggle:
return 1
return None

# purposfully not annotated
@beat("Baz?")
def no_annotations_rt_none(self, toggle=False):
if toggle:
return 1
return None

# purposfully not annotated
@beat("Bazinga!!")
def no_annotations_rt_int(self, toggle=False):
if toggle:
return 1
return None

def describe(self) -> str:
return "CornerCase"


class TestAct:
def test_calls_narrators_method(self, mocked_narrator) -> None:
test_act = "Test Act"
Expand Down Expand Up @@ -55,6 +104,36 @@ def test_interpolations(self, mocked_narrator) -> None:
completed_line = mocked_narrator.stating_a_beat.call_args_list[0][0][1]
assert completed_line == f"The {test_weapon} in the {test_room}!"

def test_beat_logging_none(self, Tester, caplog):
caplog.set_level(logging.INFO)
See(NonesyQuestion(), IsEqualTo(None)).perform_as(Tester)

assert [r.msg for r in caplog.records] == [
"Tester sees if nonesyQuestion is equal to <None>.",
" Tester examines NonesyQuestion",
" => <None>",
" ... hoping it's equal to <None>.",
" => <None>",
]

def test_beat_logging_none_corner(self, Tester, caplog):
caplog.set_level(logging.INFO)
See(CornerCase(), IsEqualTo(None)).perform_as(Tester)

assert [r.msg for r in caplog.records] == [
"Tester sees if cornerCase is equal to <None>.",
" Tester examines CornerCase",
" Blah!",
" Foobar...",
" => <None>",
" Baz?",
" Bazinga!!",
" => <1>",
" => <None>",
" ... hoping it's equal to <None>.",
" => <None>",
]


class TestAside:
def test_calls_narrators_method(self, mocked_narrator) -> None:
Expand Down

0 comments on commit bb4ea34

Please sign in to comment.