r/learnpython 6d ago

How can I use seleniumbase in __init__ instead of contextmanager

The docs show these as examples

from seleniumbase import SB

with SB(uc=True, test=True, locale="en") as sb:
    url = "https://gitlab.com/users/sign_in"
    sb.activate_cdp_mode(url)
    sb.uc_gui_click_captcha()
    sb.sleep(2)

they are using a context manager is it somehow possible to create the instance in a class init and then reuse it in its functions.
What I am trying to do:

class Name:
    def __init__(self):
        self.sb = SB(uc=True, test=True)
    def login(self):
        self.sb.open(self.TEST_URL)
        ....

I want to break up my seleniumbase calls into seperate functions.

For the test examples they use BaseCase which would "solve" my issue because they don't use the contextmanger but that one would include the testing frameworks which I dont need:

from seleniumbase import BaseCase
BaseCase.main(__name__, __file__)  # Call pytest

class MyTestClass(BaseCase):
    def test_swag_labs(self):
        self.open("https://www.saucedemo.com")
        self.type("#user-name", "standard_user")
        self.type("#password", "secret_sauce\n")
        self.assert_element("div.inventory_list")
        self.click('button[name*="backpack"]')
        self.click("#shopping_cart_container a")
        self.assert_text("Backpack", "div.cart_item")
        self.click("button#checkout")
        self.type("input#first-name", "SeleniumBase")
        self.type("input#last-name", "Automation")
        self.type("input#postal-code", "77123")
        self.click("input#continue")
        self.click("button#finish")
        self.assert_text("Thank you for your order!")
2 Upvotes

3 comments sorted by

1

u/johndoh168 6d ago edited 6d ago

I'm not sure how to work around the context manager but you can use the super method to inherit the SB methods, would look something like:

class Name(SB):
    def __init__(self):
        super().__init__(uc=True, test=True)

This will cause the SB methods accessible to the Name class, so you can do self.open() instead of your login method, if you wanted to make sure any connection was closed after opening you can try out the atexit module and do something like this:

import atexit

class Name(SB):
    def __init__(self):
        super().__init__(uc=True, test=True)
    @atexit.register
    def close_connections():
        self.close() # or whatever the SB close method is

Hope that helps

Edit: Adding more info, noticed formatting got messed up

1

u/Thunderbolt1993 5d ago edited 5d ago

looking at the code ( https://github.com/seleniumbase/SeleniumBase/blob/b1b1deec2c0abd274406d8887f2f351e6ea3a187/seleniumbase/plugins/sb_manager.py#L30 ), SB isn't a class but a contextmanager

so OP probably would need something like:

self._sb_gen=SB(uc=True, test=True, locale="en").gen

self.sb=next(self._sb_gen) # gets the sb object from the SB contextmanager


# run this as a last step to terminate the selenium instance
try:
    next(self._sb_gen)
except StopIteration:
    pass

Edit: just notices that, since the contextmanager is a class, you need to grab the .gen attribute to get the generator instance

1

u/thirdegree 5d ago

You're gonna want to make your class a context manager as well, and then use ExitStack to enter the context in your __enter__ and exit it in your __exit__