Skip to content

Instances

Eduard Dik edited this page Feb 4, 2026 · 2 revisions

Instances Overview

In standard Selenium, when you call find_element, you receive a native WebElement object. This object is inherently synchronous and blocking. To support the Trio-based asynchronous architecture and provide Human-like interaction methods, osn-selenium wraps every native Selenium object into a specialized instance wrapper.


Architectural Integrity

The primary goal of the instances package is to ensure that if you are using an asynchronous driver, every object returned by that driver is also asynchronous.

  • Consistency: A WebElement found by a TrioThread driver will always have await element.click().
  • Encapsulation: Raw Selenium objects are hidden inside the wrapper and accessed via the .legacy property when necessary.
  • Extension: Wrappers allow the library to inject new functionality (like human-like movements) directly into standard objects.

The Three-Layer Pattern

Similar to the WebDrivers, Instance Wrappers follow a strict inheritance structure:

  1. abstract/instances/: Defines the "Contract" (e.g., AbstractWebElement). It specifies which methods must exist.
  2. instances/unified/: Implements the internal blocking logic (e.g., _click_impl). This is the Single Source of Truth for how to interact with the underlying Selenium object.
  3. instances/[sync|trio_threads|trio_bidi]/: The public-facing classes.
    • sync classes call _impl methods directly.
    • trio_threads classes wrap _impl methods in threads using TrioThreadMixin.
    • trio_bidi Uses TrioBiDiMixin for synchronization and context management via BiDi Mapping.

Supported Instances

The framework provides wrappers for almost every component of the WebDriver ecosystem:

Object Class Responsibility
WebElement Standard interaction with HTML elements (click, send_keys, etc.).
ShadowRoot Access and search within encapsulated Shadow DOM trees.
Alert Management of JavaScript alert, confirm, and prompt dialogs.
Browser Control over user contexts (profiles) and client windows.
BrowsingContext High-level management of tabs and windows via BiDi protocol.
Network Advanced network interception and authentication handling.
Storage Cookie management with filter and partition support.
Script Execution of JavaScript with preload and console monitoring features.
Permissions Programmatic control over browser API permissions (camera, geo, etc.).
WebExtension Dynamic installation and uninstallation of browser extensions.
FedCM / Dialog Interface for Federated Credential Management interactions.
Mobile Management of mobile-specific contexts and network connection types.
SwitchTo Logic for switching focus between frames, windows, and alerts.
WebDriverWait Explicit wait implementation aware of the chosen architecture.
ActionChains Sequences of complex inputs (includes Human-like behaviors).

Usage Example

Notice how the interaction changes depending on the wrapper type:

# --- Synchronous Driver ---
element = driver.find_element(By.ID, "submit")
# 'element' is an instances.sync.web_element.WebElement
element.click() # Standard blocking call

# --- Trio (Asynchronous) Driver ---
element = await driver.find_element(By.ID, "submit")
# 'element' is an instances.trio_threads.web_element.WebElement
await element.click() # Non-blocking async call

Conversion Mechanism

The osn_selenium/instances/convert.py module is the "glue" of the framework. It handles the transformation between raw Selenium objects and framework wrappers.

get_legacy_instance(instance)

Returns the underlying Selenium object (legacy). If the input is already a legacy object or None, it is returned as-is. If it is an osn-selenium wrapper, it returns the .legacy property.

from osn_selenium.instances.convert import get_legacy_instance

# 'element' is an osn-selenium WebElement wrapper
raw_selenium_element = get_legacy_instance(element)

# Now you can use it with native Selenium features
print(type(raw_selenium_element)) 
# Output: <class 'selenium.webdriver.remote.webelement.WebElement'>

get_sync_instance_wrapper(wrapper_class, legacy_object)

The factory for the Synchronous architecture. It takes a raw Selenium object and wraps it in our specialized sync class.

from osn_selenium.instances.sync.web_element import WebElement
from osn_selenium.instances.convert import get_sync_instance_wrapper

# raw_el is a native selenium.webdriver.remote.webelement.WebElement
wrapped_el = get_sync_instance_wrapper(
    wrapper_class=WebElement, 
    legacy_object=raw_el
)
wrapped_el.click() # Now has our framework's features

get_trio_thread_instance_wrapper(wrapper_class, legacy_object, lock, limiter)

The factory for the Asynchronous architecture. In addition to the raw object, it requires Trio synchronization primitives (lock and limiter) to ensure thread-safe execution within the worker thread pool.

from osn_selenium.instances.trio_threads.web_element import WebElement
from osn_selenium.instances.convert import get_trio_thread_instance_wrapper

# Requires the lock and limiter from the parent driver
wrapped_el = get_trio_thread_instance_wrapper(
    wrapper_class=WebElement,
    legacy_object=raw_el,
    lock=driver.lock,
    limiter=driver.capacity_limiter
)
await wrapped_el.click() # Correct async execution

Internal "Unwrapping"

You don't have to worry about passing wrapped objects into other methods. The library handles it automatically:

# If you pass a wrapped element into a script
my_element = await driver.find_element(By.ID, "example")

# The 'execute_script' bridge will automatically call 
# get_legacy_instance(my_element) before sending it to the browser.
await driver.execute_script("arguments[0].scrollIntoView();", my_element)

Clone this wiki locally