Skip to content

Commit 4dff15a

Browse files
committed
create new export() method in PageObjectRegistry
1 parent e256b96 commit 4dff15a

File tree

21 files changed

+224
-18
lines changed

21 files changed

+224
-18
lines changed

docs/intro/pop.rst

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ by simply importing them:
118118
page = FurnitureProductPage(response)
119119
item = page.to_item()
120120
121+
.. _`pop-recommended-requirements`:
122+
121123
Recommended Requirements
122124
~~~~~~~~~~~~~~~~~~~~~~~~
123125

@@ -141,45 +143,83 @@ all :class:`~.OverrideRule` by writing the following code inside of
141143

142144
.. code-block:: python
143145
144-
from web_poet import consume_modules
146+
from web_poet import default_registry
147+
148+
REGISTRY = default_registry.export(__package__)
145149
146-
# This allows all of the OverrideRules declared inside the package
147-
# using @handle_urls to be properly discovered and loaded.
148-
consume_modules(__package__)
150+
This does two things:
149151

150-
.. note::
152+
1. The :meth:`~.PageObjectRegistry.export` method returns a new instance of
153+
:class:`~.PageObjectRegistry` which contains only the :class:`~.OverrideRule`
154+
from the given package. This means that if there are other **POPs** using the
155+
recommended ``default_registry``, any :class:`~.OverrideRule` that are not part
156+
of the package are not included.
151157

152-
Remember, code in Python like annotations are only read and executed
158+
2. Remember that code in Python like annotations are only read and executed
153159
when the module it belongs to is imported. Thus, in order for all the
154160
``@handle_urls`` annotation to properly reflect its data, they need to
155-
be imported recursively via :func:`~.consume_modules`.
161+
be imported recursively via :func:`~.consume_modules`. Fortunately,
162+
:meth:`~.PageObjectRegistry.export` already consumes the ``__package__``
163+
for us.
156164

157165
This allows developers to properly access all of the :class:`~.OverrideRule`
158-
declared using the ``@handle_urls`` annotation inside the **POP**. In turn,
159-
this also allows **POPs** which use ``web_poet.default_registry`` to have all
160-
their rules discovered if they are adhering to using Convention **#3**
161-
(see :ref:`best-practices`).
166+
declared using the ``@handle_urls`` annotation inside the **POP**:
162167

163-
In other words, importing the ``ecommerce_page_objects`` **POP** to a
164-
project immediately loads all of the rules in **web-poet's**
165-
``default_registry``:
168+
.. code-block:: python
169+
170+
import ecommerce_page_objects
171+
172+
ecommerce_rules = ecommerce_page_objects.get_overrides()
173+
174+
At the same time, this also allows **POPs** which use ``web_poet.default_registry``
175+
to have all their rules discovered if they are adhering to using Convention **#3**
176+
(see :ref:`conventions-and-best-practices`). In other words, importing the
177+
``ecommerce_page_objects`` **POP** to a project immediately loads all of the rules
178+
in **web-poet's** ``default_registry``:
166179

167180
.. code-block:: python
168181
169182
from web_poet import default_registry
170183
184+
ecommerce_rules = ecommerce_page_objects.get_overrides()
185+
171186
import ecommerce_page_objects
172187
173-
# All the rules are now available.
174-
rules = default_registry.get_overrides()
188+
# All the rules are also available once ecommerce_page_objects is imported.
189+
all_rules = default_registry.get_overrides()
175190
176191
If this recommended requirement is followed properly, there's no need to
177192
call ``consume_modules("ecommerce_page_objects")`` before performing the
178193
:meth:`~.PageObjectRegistry.get_overrides`, since all the :class:`~.OverrideRule`
179-
were already discovered upon **POP** importation.
194+
were already discovered upon **POP** importation.
195+
196+
Lastly, when trying to repackage multiple **POPs** into a single unifying **POP**
197+
which contains all of the :class:`~.OverrideRule`, it can easily be packaged
198+
as:
199+
200+
.. code-block:: python
201+
202+
from web_poet import PageObjectRegistry
203+
204+
import base_A_package
205+
import base_B_package
206+
207+
# If on Python 3.9+
208+
combined_reg = base_A_package.REGISTRY | base_B_package.REGISTRY
209+
210+
# If on lower Python versions
211+
combined_reg = {**base_A_package.REGISTRY, **base_B_package.REGISTRY}
212+
213+
REGISTRY = PageObjectRegistry(combined_reg)
180214
181-
.. _`best-practices`:
215+
Note that you can also opt to use only a subset of the :class:`~.OverrideRule`
216+
by selecting the specific ones in ``combined_reg`` before creating a new
217+
:class:`~.PageObjectRegistry` instance. An **inclusion** rule is preferred than
218+
an **exclusion** rule (see **Tip #4** in the :ref:`conventions-and-best-practices`).
219+
You can use :meth:`~.PageObjectRegistry.search_overrides` when selecting the
220+
rules.
182221

222+
.. _`conventions-and-best-practices`:
183223

184224
Conventions and Best Practices
185225
------------------------------

tests/test_pop.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
"""This tests the expected behavior of importing multiple different POPs such
2+
that they don't leak the OverrideRules from other POPs that use the same
3+
``default_registry``.
4+
5+
Packacking and exporting a given POP should be resilient from such cases.
6+
7+
In particular, this tests the :meth:`PageObjectRegistry.export` functionality.
8+
"""
9+
10+
def test_base_A():
11+
from tests_pop import base_A_package
12+
13+
reg = base_A_package.REGISTRY
14+
15+
assert len(reg) == 2
16+
assert base_A_package.site_1.A_Site1 in reg
17+
assert base_A_package.site_2.A_Site2 in reg
18+
19+
20+
def test_base_B():
21+
from tests_pop import base_B_package
22+
23+
reg = base_B_package.REGISTRY
24+
25+
assert len(reg) == 2
26+
assert base_B_package.site_2.B_Site2 in reg
27+
assert base_B_package.site_3.B_Site3 in reg
28+
29+
30+
def test_improved_A():
31+
from tests_pop import improved_A_package, base_A_package
32+
33+
reg = improved_A_package.REGISTRY
34+
35+
assert len(reg) == 3
36+
assert improved_A_package.site_1.A_Improved_Site1 in reg
37+
assert improved_A_package.base_A_package.site_1.A_Site1 in reg
38+
assert improved_A_package.base_A_package.site_2.A_Site2 in reg
39+
40+
41+
def test_combine_A_B():
42+
from tests_pop import combine_A_B_package, base_A_package, base_B_package
43+
44+
reg = combine_A_B_package.REGISTRY
45+
46+
assert len(reg) == 4
47+
assert combine_A_B_package.base_A_package.site_1.A_Site1 in reg
48+
assert combine_A_B_package.base_A_package.site_2.A_Site2 in reg
49+
assert combine_A_B_package.base_B_package.site_2.B_Site2 in reg
50+
assert combine_A_B_package.base_B_package.site_3.B_Site3 in reg
51+
52+
53+
def test_combine_A_B_subset():
54+
from tests_pop import combine_A_B_subset_package, improved_A_package, base_B_package
55+
56+
reg = combine_A_B_subset_package.REGISTRY
57+
58+
assert len(reg) == 2
59+
assert combine_A_B_subset_package.improved_A_package.site_1.A_Improved_Site1 in reg
60+
assert combine_A_B_subset_package.base_B_package.site_3.B_Site3 in reg

tests_pop/__init__.py

Whitespace-only changes.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from web_poet import default_registry
2+
3+
REGISTRY = default_registry.export(__package__)

tests_pop/base_A_package/base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
class BasePage:
2+
...

tests_pop/base_A_package/site_1.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from web_poet import handle_urls
2+
3+
from .base import BasePage
4+
5+
6+
@handle_urls("site_1.com", overrides=BasePage)
7+
class A_Site1:
8+
...

tests_pop/base_A_package/site_2.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from web_poet import handle_urls
2+
3+
from .base import BasePage
4+
5+
6+
@handle_urls("site_2.com", overrides=BasePage)
7+
class A_Site2:
8+
...
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from web_poet import default_registry
2+
3+
REGISTRY = default_registry.export(__package__)

tests_pop/base_B_package/base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
class BasePage:
2+
...

tests_pop/base_B_package/site_2.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from web_poet import handle_urls
2+
3+
from .base import BasePage
4+
5+
6+
@handle_urls("site_2.com", overrides=BasePage)
7+
class B_Site2:
8+
...

0 commit comments

Comments
 (0)