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

[WIP] Minimize provider calls #153

Closed
wants to merge 2 commits into from
Closed
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
57 changes: 57 additions & 0 deletions tests/test_injection.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
NonCallableProviderError,
UndeclaredProvidedTypeError,
)
from scrapy_poet.page_input_providers import ItemProvider


def get_provider(classes, content=None):
Expand Down Expand Up @@ -270,6 +271,62 @@ def callback(
"d": ClsNoProviderRequired,
}

@inlineCallbacks
def test_build_callback_dependencies_minimize_provider_calls(self):
"""Test that build_callback_dependencies does not call any given
provider more times than it needs when one provided class is requested
directly while another is a page object dependency requested through
an item."""

class ExpensiveDependency1:
pass

class ExpensiveDependency2:
pass

class ExpensiveProvider(PageObjectInputProvider):
provided_classes = {ExpensiveDependency1, ExpensiveDependency2}

def __call__(self, to_provide):
if to_provide != self.provided_classes:
raise RuntimeError(
"The expensive dependency provider has been called "
"with a subset of the classes that it provides and "
"that are required for the callback in this test."
)
return [cls() for cls in to_provide]

@attr.define
class MyItem:
pass

@attr.define
class MyPage(ItemPage[MyItem]):
expensive: ExpensiveDependency2

def callback(
expensive: ExpensiveDependency1,
item: MyItem,
):
pass

providers = {
ItemProvider: 1,
ExpensiveProvider: 2,
}
injector = get_injector_for_testing(providers)
injector.registry.add_rule(ApplyRule("", use=MyPage, to_return=MyItem))
response = get_response_for_testing(callback)

# This would raise RuntimeError if expectations are not met.
kwargs = yield from injector.build_callback_dependencies(
response.request, response
)

# Make sure the test does not simply pass because some dependencies were
# not injected at all.
assert set(kwargs.keys()) == {"expensive", "item"}


class Html(Injectable):
url = "http://example.com"
Expand Down