How to use __set__ and __get__ in Python Selenium PageObjects

Viewed 267

I am a beginner in Python and I'm trying to understand Python Selenium's documentation on page objects: https://selenium-python.readthedocs.io/page-objects.html

What does the set and get methods do in element.py? And how should we call them and use search_text_element in page.MainPage? Given this file structure, how can I find a search text field in a website, enter a string and send By.RETURN?

2 Answers

You usually won't call these directly. When objects that have these methods are used as attributes in another class (for example, in a class representing a web page), they will be called automatically when the attribute is retrieved (__get__) or written with the =assignment operator.

Generally, Python just gets and sets values on attributes without any special processing just like a basic storage. But if you are implementing Page Objects where Base page class is initialized on accessing every page object class, you might need to validate the Page Object's value that's was being assigned. You may want to retrieve a value and cache it for later use.

In short, a descriptor is an attribute value that has any of the following methods:

  • __get__(self, instance, owner): This will be called when the attribute is retrieved (value = obj.attr), and whatever it returns is what will be given to the code that requested the attribute’s value.
  • __set__(): This gets called when a value is set to the attribute (obj.attr = 'value'), and shouldn’t return anything at all.
  • __delete__(): This is called when the attribute is deleted from an object (del obj.attr)

in the descriptor protocol. If any of those methods are defined for an attribute, it is said to be a descriptor.


get

Called to get the attribute of the owner class (class attribute access) or of an instance of that class (instance attribute access). An example:

class Ten:
    def __get__(self, obj, objtype=None):
    return 10

class A:
    x = 5                       # Regular class attribute
    y = Ten()                   # Descriptor instance

a = A()             # Make an instance of class A
print(a.x)          # Normal attribute lookup
print(a.y)          # Descriptor lookup

Prints:

5
10

Explanation: In the a.x attribute lookup, the dot operator finds 'x': 5 in the class dictionary. In the a.y lookup, the dot operator finds a descriptor instance, recognized by its get method. Calling that method returns 10. Note that the value 10 is not stored in either the class dictionary or the instance dictionary. Instead, the value 10 is computed on demand.


This usecase

As per the code in element.py

from selenium.webdriver.support.ui import WebDriverWait


class BasePageElement(object):
    """Base page class that is initialized on every page object class."""

    def __set__(self, obj, value):
    """Sets the text to the value supplied"""

    driver = obj.driver
    WebDriverWait(driver, 100).until(lambda driver: driver.find_element_by_name(self.locator))
    driver.find_element_by_name(self.locator).clear()
    driver.find_element_by_name(self.locator).send_keys(value)

    def __get__(self, obj, owner):
    """Gets the text of the specified object"""

    driver = obj.driver
    WebDriverWait(driver, 100).until(lambda driver: driver.find_element_by_name(self.locator))
    element = driver.find_element_by_name(self.locator)
    return element.get_attribute("value")
    
class Pages:

    element = BasePageElement()

    def __init__(self, element, value):
          self.element = element              # Calls __set__()
      self.value = value                  

    
login_page = Pages(username, 'Henry')  # Sets the username field with text Henry
Related