Search code examples
pythonseleniumautomated-testsui-automationpageobjects

Page Object Pattern Circular import problem in Python


I'm writing my automation framework in Page Object Pattern and I've came across this error when implementing view classes. I've placed this classes in separate modules and I want them to stay separated. The problem is that I want my instance methods in both classes to return an object of another class when performing certain UI actions.

Is there a way to fix circular error while having this classes in separate modules?

cart_page.py

from pages.base_page import BasePage
from utils.locators import CartLocators
from pages.main_page import MainPage

class CartPage(BasePage):
    def __init__(self, driver):
        self.locators = CartLocators()
        super().__init__(driver, 'https://www.saucedemo.com/cart.html')

    def click_continue_shopping(self):
        self.find_element(*self.locators.CONTINUE_SHOPPING_BTN).click()
        return MainPage(self.driver)

main_page.py

from pages.base_page import BasePage
from utils.locators import MainPageHeaderLocators, MainPageItemListLocators, InventoryItemLocators
from pages.cart_page import CartPage

class MainPage(BasePage):
    def __init__(self, driver):
        super().__init__(driver, "https://www.saucedemo.com/invetory.html")
        self.header = MainPageHeader(self.driver)
        self.item_list = MainPageItemList(self.driver)
        self.inventory_item = InventoryItemPage(self.driver)

    def open_cart(self):
        self.header.open_cart()
        return CartPage(self.driver)
E   ImportError: cannot import name 'MainPage' from partially initialized module 'pages.main_page' (most likely due to a circular import) (/Users/marcin94/PycharmProjects/sauce_demo_ui_tests/pages/main_page.py)

Solution

  • Do not use from. Import the module directly:

    cart_page.py

    from pages.base_page import BasePage
    from utils.locators import CartLocators
    import pages.main_page
    
    class CartPage(BasePage):
        def __init__(self, driver):
            self.locators = CartLocators()
            super().__init__(driver, 'https://www.saucedemo.com/cart.html')
    
        def click_continue_shopping(self):
            self.find_element(*self.locators.CONTINUE_SHOPPING_BTN).click()
            return pages.main_page.MainPage(self.driver)
    

    main_page.py

    from pages.base_page import BasePage
    from utils.locators import MainPageHeaderLocators, MainPageItemListLocators, InventoryItemLocators
    import pages.cart_page
    
    class MainPage(BasePage):
        def __init__(self, driver):
            super().__init__(driver, "https://www.saucedemo.com/invetory.html")
            self.header = MainPageHeader(self.driver)
            self.item_list = MainPageItemList(self.driver)
            self.inventory_item = InventoryItemPage(self.driver)
    
        def open_cart(self):
            self.header.open_cart()
            return pages.cart_page.CartPage(self.driver)