Skip to content

Commit 8e805a7

Browse files
committed
update POP docs after PageObjectRegistry became a dict subclass
1 parent e44e399 commit 8e805a7

2 files changed

Lines changed: 49 additions & 28 deletions

File tree

docs/intro/overrides.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,13 +217,17 @@ This can be done something like:
217217

218218
If you're using External Packages which conform to the **POP**
219219
standards as described in the :ref:`intro-pop` section, then retrieving
220-
the rules should be as easy as:
220+
the rules could also be done as:
221221

222222
.. code-block:: python
223223
224224
import ecommerce_page_objects, gadget_sites_page_objects
225225
226-
rules = ecommerce_page_objects.RULES + gadget_sites_page_objects.RULES
226+
# If on Python 3.9+
227+
rules = ecommerce_page_objects.REGISTRY | gadget_sites_page_objects.REGISTRY
228+
229+
# If on lower Python versions
230+
rules = {**ecommerce_page_objects.REGISTRY, **gadget_sites_page_objects.REGISTRY}
227231
228232
.. _`intro-rule-subset`:
229233

docs/intro/pop.rst

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,16 @@
33
Page Object Projects (POP)
44
==========================
55

6-
**POPs** are way to package up a group of Page Objects together so they
7-
can be used in other projects as well. This improves code reusability since
8-
the extraction logic in some web pages are easily shareable. More importantly,
6+
**POPs** are a way to standardize how a group of Page Objects are packaged
7+
together so they can be uniformly used in other projects. More importantly,
98
**POPs** could be built using other **POPs**. This allows for continuous
109
improvements by building **POPs** on top of one another.
1110

1211
Organizing POP
1312
--------------
1413

1514
Developers have complete freedom on how to organize their Page Objects
16-
in their project. Here are some options that developers could use.
15+
in their projects. Here are some of the options that developers could use.
1716

1817
Flat Hierarchy
1918
~~~~~~~~~~~~~~
@@ -61,10 +60,11 @@ domains. This could easily be grouped as something like:
6160
| | | ├── products.py
6261
| | | └── product_listings.py
6362
| | └── __init__.py
64-
| └── furniture_shop
65-
| ├── __init__.py
66-
| ├── products.py
67-
| └── product_listings.py
63+
| ├── furniture_shop
64+
| | ├── __init__.py
65+
| | ├── products.py
66+
| | └── product_listings.py
67+
| └── __init__.py
6868
└── setup.py
6969
7070
Requirements for POP
@@ -85,7 +85,7 @@ This covers the basic use case:
8585
- Importing the Page Objects directly from the installed package in a project.
8686

8787

88-
This translates into **POPs** needing to have:
88+
This means that **POPs** need to have:
8989

9090
- The ``setup.py`` script which is the standard way of distributing Python packages.
9191

@@ -114,32 +114,32 @@ by simply importing them:
114114
115115
from ecommerce_page_objects.furniture_shop.products import FurnitureProductPage
116116
117-
response_data = download_response("https://www.furnitureshop.com/product/xyz")
118-
page = FurnitureProductPage()
117+
response = download_response("https://www.furnitureshop.com/product/xyz")
118+
page = FurnitureProductPage(response)
119119
item = page.to_item()
120120
121121
Recommended Requirements
122122
~~~~~~~~~~~~~~~~~~~~~~~~
123123

124-
This covers these use use cases:
124+
This covers these use cases:
125125

126-
- The minimum requirements and use cases stated above
126+
- The minimum requirements and its use cases
127127
- The ability to retrieve the declared :class:`~.OverrideRule`
128128
inside the **POP**
129129

130-
This means that a list of :class:`~.OverrideRule` must be explicitly
130+
This means that a collection of :class:`~.OverrideRule` must be explicitly
131131
declared in the **POP**. This enables projects using the **POP** to know:
132132

133133
- which URL Patterns a given Page Object is expected to work
134134
- what it's trying to override `(or replace)`
135135

136-
This could be done by declaring a ``RULES`` variable that can be
136+
This could be done by declaring a ``REGISTRY`` variable that can be
137137
imported as a top-level variable from the package.
138138

139139
For example, suppose our project is named **ecommerce_page_objects**
140-
and is using either of the project structure options discussed in the
141-
previous sections, then we can define the ``RULES`` as the following
142-
inside ``ecommerce_page_objects/ecommerce_page_objects/__init__.py``.
140+
and is using any of the project structure options discussed in the
141+
previous sections, we can then define the ``REGISTRY`` variable as the following
142+
inside of ``ecommerce-page-objects/ecommerce_page_objects/__init__.py``:
143143

144144
.. code-block:: python
145145
@@ -148,19 +148,32 @@ inside ``ecommerce_page_objects/ecommerce_page_objects/__init__.py``.
148148
# This allows all of the OverrideRules declared inside the package
149149
# using @handle_urls to be properly discovered and loaded.
150150
consume_modules(__package__)
151-
RULES = default_registry.get_overrides()
152151
153-
This allows any developer using a **POP** to easily get the list of
152+
REGISTRY = default_registry
153+
154+
This allows any developer using a **POP** to easily access all of the
154155
:class:`~.OverrideRule` using the convention of accessing it via the
155-
``RULES`` variable as a top-level variable:
156+
``REGISTRY`` variable. For example:
156157

157158
.. code-block:: python
158159
159-
from ecommerce_page_objects import RULES
160+
from ecommerce_page_objects import REGISTRY
161+
162+
.. tip::
163+
164+
The ``default_registry`` is an instance of :class:`~.PageObjectRegistry`,
165+
which in turn is simply a subclass of a ``dict``. This means that you don't
166+
necessarily have to use an instance of :class:`~.PageObjectRegistry` as long
167+
as it has a ``dict``-like interface.
160168

161-
There may be some circumstances that needs other ways of declaring this.
162-
For such cases, developers/maintainers of **POPs** must reflect that
163-
clearly in the documentation.
169+
The :class:`~.PageObjectRegistry` is simply a mapping where the **key** is
170+
the Page Object to use and the **value** is the :class:`~.OverrideRule` it
171+
operates on. This means you can simply use a plain ``dict`` for the
172+
``REGISTRY`` variable.
173+
174+
However, it is **recommended** to use the instances of
175+
:class:`~.PageObjectRegistry` to leverage the validation logic for its
176+
contents.
164177

165178

166179
Conventions and Best Practices
@@ -170,7 +183,7 @@ Conventions and Best Practices
170183
This allows for easy identification when used by other developers.
171184

172185
2. The list of :class:`~.OverrideRule` must be declared as a top-level
173-
variable from the package named ``RULES``. This enables other developers
186+
variable from the package named ``REGISTRY``. This enables other developers
174187
to easily retrieve the list of :class:`~.OverrideRule` to be used in
175188
their own projects.
176189

@@ -179,6 +192,10 @@ Conventions and Best Practices
179192
:class:`~.PageObjectRegistry`. This provides a default expectation
180193
for developers on which registry to use right from the start.
181194

195+
* However, there will be some cases where creating a new instance of
196+
:class:`~.PageObjectRegistry` is inevitably needed. Here's an
197+
:ref:`example <overrides-custom-registry>` in the tutorial section.
198+
182199
4. When building a new **POP** based of on existing **POPs**, it is
183200
recommended to use an **inclusion** strategy rather than **exclusion**
184201
when selecting the list of :class:`~.OverrideRule` to export.

0 commit comments

Comments
 (0)