Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

using Self now that it's available in typing_extensions #124

Merged
merged 2 commits into from
Feb 14, 2024
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
15 changes: 15 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,17 @@ ignore = [
"ANN102", # missing cls annotation, we only annotate cls when we return it.
]

extend-safe-fixes = [
"EM101",
"EM102",
"TCH001", "TCH002", "TCH003", "TCH004",
"C419",
"D200", "D205", "D415",
"PT003", "PT006", "PT018",
"RET504",
"UP006", "UP007",
]

[tool.ruff.lint.per-file-ignores]
"tests/**" = [
"D", # we don't need public-API-polished docstrings in tests.
Expand Down Expand Up @@ -206,6 +217,10 @@ ignore-overlong-task-comments = true
convention = "google"


[tool.ruff.lint.flake8-type-checking]
strict = true


[build-system]
requires = ["poetry-core>=1.2.0"]
build-backend = "poetry.core.masonry.api"
6 changes: 4 additions & 2 deletions screenpy/actions/either.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from screenpy.speech_tools import get_additive_description

if TYPE_CHECKING:
from typing_extensions import Self

from screenpy import Actor
from screenpy.protocols import Performable

Expand Down Expand Up @@ -62,7 +64,7 @@ def perform_as(self, the_actor: Actor) -> None:
the_actor.will(*self.except_performables)
return

def or_(self, *except_performables: Performable) -> Either:
def or_(self, *except_performables: Performable) -> Self:
"""Provide the alternative routine to perform.

Aliases:
Expand All @@ -77,7 +79,7 @@ def or_(self, *except_performables: Performable) -> Either:

except_ = else_ = otherwise = alternatively = failing_that = or_

def ignoring(self, *ignored_exceptions: type[BaseException]) -> Either:
def ignoring(self, *ignored_exceptions: type[BaseException]) -> Self:
"""Set the expception classes to ignore."""
self.ignore_exceptions = ignored_exceptions
return self
Expand Down
9 changes: 4 additions & 5 deletions screenpy/actions/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,20 @@

from __future__ import annotations

from typing import TYPE_CHECKING, TypeVar
from typing import TYPE_CHECKING

from screenpy.pacing import aside, beat
from screenpy.protocols import Answerable
from screenpy.speech_tools import get_additive_description, represent_prop

if TYPE_CHECKING:
from typing_extensions import Self

from screenpy.actor import Actor

from .see import T_Q


SelfLog = TypeVar("SelfLog", bound="Log")


class Log:
"""Log the answer to a Question, or anything.

Expand All @@ -30,7 +29,7 @@ class Log:
"""

@classmethod
def the(cls: type[SelfLog], question: T_Q) -> SelfLog:
def the(cls, question: T_Q) -> Self:
"""Supply the Question to answer."""
return cls(question)

Expand Down
17 changes: 9 additions & 8 deletions screenpy/actions/make_note.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
from screenpy.speech_tools import represent_prop

if TYPE_CHECKING:
from typing import TypeVar, Union
from typing import Union

from typing_extensions import Self

from screenpy.actor import Actor

SelfMakeNote = TypeVar("SelfMakeNote", bound="MakeNote")
T_Q = Union[Answerable, object]


Expand All @@ -39,7 +40,7 @@ class MakeNote:
question: T_Q

@classmethod
def of(cls: type[SelfMakeNote], question: T_Q) -> SelfMakeNote:
def of(cls, question: T_Q) -> Self:
"""Supply the Question to answer and its arguments.

Aliases:
Expand All @@ -48,21 +49,21 @@ def of(cls: type[SelfMakeNote], question: T_Q) -> SelfMakeNote:
return cls(question)

@classmethod
def of_the(cls: type[SelfMakeNote], question: T_Q) -> SelfMakeNote:
def of_the(cls, question: T_Q) -> Self:
"""Alias for :meth:`~screenpy.actions.MakeNote.of`."""
return cls.of(question)

def as_(self: SelfMakeNote, key: str) -> SelfMakeNote:
def as_(self, key: str) -> Self:
"""Set the key to use to recall this noted value."""
self.key = key
return self

def describe(self: SelfMakeNote) -> str:
def describe(self) -> str:
"""Describe the Action in present tense."""
return f"Make a note under {represent_prop(self.key)}."

@beat("{} jots something down under {key_to_log}.")
def perform_as(self: SelfMakeNote, the_actor: Actor) -> None:
def perform_as(self, the_actor: Actor) -> None:
"""Direct the Actor to take a note."""
if self.key is None:
msg = "No key was provided to name this note."
Expand All @@ -81,7 +82,7 @@ def perform_as(self: SelfMakeNote, the_actor: Actor) -> None:
Director().notes(self.key, value)

def __init__(
self: SelfMakeNote,
self,
question: T_Q,
key: str | None = None,
) -> None:
Expand Down
21 changes: 10 additions & 11 deletions screenpy/actions/pause.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@
from screenpy.pacing import beat

if TYPE_CHECKING:
from typing import TypeVar

from screenpy.actor import Actor
from typing_extensions import Self

SelfPause = TypeVar("SelfPause", bound="Pause")
from screenpy.actor import Actor


class Pause:
Expand Down Expand Up @@ -43,11 +42,11 @@ class Pause:
reason: str

@classmethod
def for_(cls: type[SelfPause], number: float) -> SelfPause:
def for_(cls, number: float) -> Self:
"""Specify how many seconds or milliseconds to wait for."""
return cls(number)

def seconds_because(self: SelfPause, reason: str) -> SelfPause:
def seconds_because(self, reason: str) -> Self:
"""Use seconds and provide a reason for the pause.

Aliases:
Expand All @@ -57,23 +56,23 @@ def seconds_because(self: SelfPause, reason: str) -> SelfPause:
self.reason = self._massage_reason(reason)
return self

def second_because(self: SelfPause, reason: str) -> SelfPause:
def second_because(self, reason: str) -> Self:
"""Alias for :meth:`~screenpy.actions.Pause.seconds_because`."""
return self.seconds_because(reason)

def milliseconds_because(self: SelfPause, reason: str) -> SelfPause:
def milliseconds_because(self, reason: str) -> Self:
"""Use milliseconds and provide a reason for the pause."""
self.unit = f"millisecond{'s' if self.number != 1 else ''}"
self.time = self.time / 1000.0
self.reason = self._massage_reason(reason)
return self

def describe(self: SelfPause) -> str:
def describe(self) -> str:
"""Describe the Action in present tense."""
return f"Pause for {self.number} {self.unit} {self.reason}."

@beat("{} pauses for {number} {unit} {reason}.")
def perform_as(self: SelfPause, _: Actor) -> None:
def perform_as(self, _: Actor) -> None:
"""Direct the Actor to take their union-mandated break."""
if not self.reason:
msg = (
Expand All @@ -84,14 +83,14 @@ def perform_as(self: SelfPause, _: Actor) -> None:

sleep(self.time)

def _massage_reason(self: SelfPause, reason: str) -> str:
def _massage_reason(self, reason: str) -> str:
"""Apply some gentle massaging to the reason string."""
if not reason.startswith("because"):
reason = f"because {reason}"

return re.sub(r"\W*$", "", reason)

def __init__(self: SelfPause, number: float) -> None:
def __init__(self, number: float) -> None:
self.number = number
self.time = number
self.unit = f"second{'s' if self.number != 1 else ''}"
Expand Down
16 changes: 9 additions & 7 deletions screenpy/actions/see.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@
from hamcrest import assert_that

from screenpy.pacing import aside, beat
from screenpy.protocols import Answerable, ErrorKeeper, Resolvable
from screenpy.protocols import Answerable, ErrorKeeper
from screenpy.speech_tools import get_additive_description, represent_prop

if TYPE_CHECKING:
from typing import TypeVar, Union
from typing import Union

from typing_extensions import Self

from screenpy.actor import Actor
from screenpy.protocols import Resolvable

SelfSee = TypeVar("SelfSee", bound="See")
T_Q = Union[Answerable, object]
T_R = Resolvable

Expand Down Expand Up @@ -44,16 +46,16 @@ class See:
resolution_to_log: str

@classmethod
def the(cls: type[SelfSee], question: T_Q, resolution: T_R) -> SelfSee:
def the(cls, question: T_Q, resolution: T_R) -> Self:
"""Supply the Question (or value) and Resolution to test."""
return cls(question, resolution)

def describe(self: SelfSee) -> str:
def describe(self) -> str:
"""Describe the Action in present tense."""
return f"See if {self.question_to_log} is {self.resolution_to_log}."

@beat("{} sees if {question_to_log} is {resolution_to_log}.")
def perform_as(self: SelfSee, the_actor: Actor) -> None:
def perform_as(self, the_actor: Actor) -> None:
"""Direct the Actor to make an observation."""
if isinstance(self.question, Answerable):
value: object = self.question.answered_by(the_actor)
Expand All @@ -68,7 +70,7 @@ def perform_as(self: SelfSee, the_actor: Actor) -> None:

assert_that(value, self.resolution.resolve(), reason)

def __init__(self: SelfSee, question: T_Q, resolution: T_R) -> None:
def __init__(self, question: T_Q, resolution: T_R) -> None:
self.question = question
self.question_to_log = get_additive_description(question)
self.resolution = resolution
Expand Down
13 changes: 7 additions & 6 deletions screenpy/actions/see_all_of.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@

from __future__ import annotations

from typing import TYPE_CHECKING, Tuple, TypeVar
from typing import TYPE_CHECKING, Tuple

from screenpy.exceptions import UnableToAct
from screenpy.pacing import beat

from .see import See

if TYPE_CHECKING:
from typing_extensions import Self

from screenpy.actor import Actor

from .see import T_Q, T_R

SelfSeeAllOf = TypeVar("SelfSeeAllOf", bound="SeeAllOf")
T_T = Tuple[T_Q, T_R]


Expand Down Expand Up @@ -43,21 +44,21 @@ class SeeAllOf:
tests: tuple[T_T, ...]

@classmethod
def the(cls: type[SelfSeeAllOf], *tests: T_T) -> SelfSeeAllOf:
def the(cls, *tests: T_T) -> Self:
"""Supply any number of Question/value + Resolution tuples to test."""
return cls(*tests)

def describe(self: SelfSeeAllOf) -> str:
def describe(self) -> str:
"""Describe the Action in present tense."""
return f"See if {self.log_message}."

@beat("{} sees if {log_message}:")
def perform_as(self: SelfSeeAllOf, the_actor: Actor) -> None:
def perform_as(self, the_actor: Actor) -> None:
"""Direct the Actor to make a series of observations."""
for question, resolution in self.tests:
the_actor.should(See.the(question, resolution))

def __init__(self: SelfSeeAllOf, *tests: T_T) -> None:
def __init__(self, *tests: T_T) -> None:
for tup in tests:
if isinstance(tup, tuple):
if len(tup) != 2: # noqa: PLR2004
Expand Down
13 changes: 7 additions & 6 deletions screenpy/actions/see_any_of.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@
from .see import See

if TYPE_CHECKING:
from typing import Tuple, TypeVar
from typing import Tuple

from typing_extensions import Self

from screenpy.actor import Actor

from .see import T_Q, T_R

SelfSeeAnyOf = TypeVar("SelfSeeAnyOf", bound="SeeAnyOf")
T_T = Tuple[T_Q, T_R]


Expand Down Expand Up @@ -46,16 +47,16 @@ class SeeAnyOf:
tests: tuple[T_T, ...]

@classmethod
def the(cls: type[SelfSeeAnyOf], *tests: T_T) -> SelfSeeAnyOf:
def the(cls, *tests: T_T) -> Self:
"""Supply any number of Question/value + Resolution tuples to test."""
return cls(*tests)

def describe(self: SelfSeeAnyOf) -> str:
def describe(self) -> str:
"""Describe the Action in present tense."""
return f"See if {self.log_message}."

@beat("{} sees if {log_message}:")
def perform_as(self: SelfSeeAnyOf, the_actor: Actor) -> None:
def perform_as(self, the_actor: Actor) -> None:
"""Direct the Actor to make a series of observations."""
if not self.tests:
# No tests is OK!
Expand All @@ -72,7 +73,7 @@ def perform_as(self: SelfSeeAnyOf, the_actor: Actor) -> None:
msg = f"{the_actor} did not find any expected answers!"
raise AssertionError(msg)

def __init__(self: SelfSeeAnyOf, *tests: T_T) -> None:
def __init__(self, *tests: T_T) -> None:
for tup in tests:
if isinstance(tup, tuple):
if len(tup) != 2: # noqa: PLR2004
Expand Down
Loading
Loading