Skip to content
Merged
Prev Previous commit
Next Next commit
Types
  • Loading branch information
FabioRosado committed Nov 4, 2022
commit 84dc20cec5f5ed5c9b0b11d0ae444ec65808425a
9 changes: 5 additions & 4 deletions src/psc/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import builtins
from collections.abc import Callable
from collections.abc import Generator
from collections.abc import Iterable
from dataclasses import dataclass
from dataclasses import field
from mimetypes import guess_type
Expand Down Expand Up @@ -192,7 +193,7 @@ class FakeDocument:


@pytest.fixture
def fake_document() -> FakeDocument:
def fake_document() -> Iterable[FakeDocument]:
"""Yield a document that cleans up."""
yield FakeDocument()

Expand All @@ -208,7 +209,7 @@ def write(self, value: str) -> None:
"""Collect anything that is written to the node."""
self.document.log.append(value)

def removeAttribute(self, name) -> None: # noqa
def removeAttribute(self, name: str) -> None: # noqa
"""Pretend to remove an attribute from this node."""
pass

Expand All @@ -227,10 +228,10 @@ def __call__(self, key: str) -> ElementNode:


@pytest.fixture
def fake_element(fake_document) -> None:
def fake_element(fake_document: FakeDocument) -> None: # type: ignore [misc]
"""Install the stateful Element into builtins."""
try:
builtins.Element = ElementCallable(fake_document)
builtins.Element = ElementCallable(fake_document) #type: ignore [attr-defined]
yield
finally:
delattr(builtins, "Element")
2 changes: 1 addition & 1 deletion src/psc/gallery/examples/hello_world_py/hello_world.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Say Hello."""
output = Element("output")
output = Element("output") #type: ignore
output.write("From Python...")
19 changes: 11 additions & 8 deletions tests/test_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@
from psc.fixtures import DummyRequest
from psc.fixtures import DummyResponse
from psc.fixtures import DummyRoute
from psc.fixtures import FakeDocument
from psc.fixtures import MockTestClient
from psc.fixtures import PageT
from psc.fixtures import mocked_client_page
from psc.fixtures import route_handler
from psc.here import STATIC


Element = cast("Unknown", "Element")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The addition of this line causes some tests to fail, as Element should only exist in tests that ask for the fake_element fixture.


def test_test_client(test_client: TestClient) -> None:
"""Ensure fixture returns an initialized TestClient."""
assert test_client.app
Expand Down Expand Up @@ -138,32 +141,32 @@ def test_route_handler_fake_bad_path() -> None:
def test_fake_element_not_installed() -> None:
"""We don't request the fixture so it isn't available."""
with pytest.raises(NameError):
Element # noqa
Element # noqa


def test_fake_element_installed(fake_element) -> None:
def test_fake_element_installed(fake_element: function) -> None:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You annotated with function. Perhaps you meant Callable with the right params?

"""Element is available as ``fake_element`` installed it."""
Element # noqa
Element # noqa


def test_fake_element_find_element(fake_document, fake_element) -> None:
def test_fake_element_find_element(fake_document: FakeDocument, fake_element: function) -> None:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's your feeling on my commitment to typing? Too much?

My plan is: actual examples don't have to use typing. Perhaps even - never use typing. But the PSC itself does aim for good typing coverage.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the type of issues I still need to see if I can make mypy happy.
In general I am in favor of typing, but I think in a lot of cases we will have mypy break for examples when we do Element it complains that its not defined.

Your idea is great, keeping the examples easy to follow for new folks is great and enforcing typing there will make things more complicated 😄

"""The Element can get a value from the fake document."""
fake_document.values["btn1"] = "value1"
button = Element("btn1") # noqa
assert button.value == "value1"


def test_fake_element_write(fake_document, fake_element) -> None:
def test_fake_element_write(fake_document: FakeDocument, fake_element: function) -> None:
"""The Element can write a value that is captured."""
fake_document.values["btn1"] = "value1"
button = Element("btn1") # noqa
button = Element("btn1") # noqa
button.write("Some Value")
assert fake_document.log[0] == "Some Value"


def test_fake_element_remove_attribute(fake_document, fake_element) -> None:
def test_fake_element_remove_attribute(fake_document: FakeDocument, fake_element: function) -> None:
"""The Element can pretend to remove an attribute."""
fake_document.values["btn1"] = "value1"
button = Element("btn1") # noqa
button = Element("btn1") # noqa
button.removeAttribute("disabled")
assert fake_document.log == []