Skip to main content

Selenium CORE for Python

Latest Version License Supported Python versions Supported Python implementations Tests codecov

Introduction

It's a library with core functions simplifying work with Selenium-controlled applications.

This package is based on Aquality Selenium CORE for .NET and provides a set of methods related to the most common actions performed with elements. So you shouldn't have a lot of difficulties with this solution if you interacted with Aquality Selenium CORE.

To simplify overriding of implementations this solution uses Dependency Injection.

Supported Python Versions

  • Python 3.7-3.12

Installation

If you have pip on your system, you can simply install or upgrade the Python bindings:

pip install py-selenium-auto-core

Alternately, you can download the source distribution from PyPI, unarchive it, and run:

python setup.py install

Quick start

  1. Setup Dependency Injection container using Startup

The solution offers a ServiceProvider implementation using Dependency Injection container as a single point for interacting with various services and their dependencies:

class ServiceProvider(containers.DeclarativeContainer):
    """Container that allows to resolve dependencies for all services in the library"""
    
    settings_file: Singleton[JsonSettingsFile] = Singleton(JsonSettingsFile({}))
    application: Factory[Application] = Factory(Application)
    logger: Singleton[Logger] = Singleton(Logger)
    logger_configuration: Singleton[LoggerConfiguration] = Singleton(LoggerConfiguration, settings_file)
    timeout_configuration: Singleton[TimeoutConfiguration] = Singleton(TimeoutConfiguration, settings_file)
    localization_manager: Singleton[LocalizationManager] = Singleton(LocalizationManager, logger_configuration, logger)
    ...

This allows you to control dependencies between packages and cause the creation of the objects themselves at the time of accessing them. Example of working with ServiceProvider:

ServiceProvider.logger().info("Message")  # message logging
ServiceProvider.timeout_configuration().interval  # Getting the Timeout.interval value

For ease of use, the solution contains a Startup object that makes it easy to get a ServiceProvider object with redefined dependencies for settings_file and application:

class Startup:

    @staticmethod
    def configure_services(application_provider: Callable, settings: Optional[JsonSettingsFile] = None, service_provider: Optional[T] = None,
    ) -> T | ServiceProvider:
        service_provider: T = service_provider or ServiceProvider()
        settings = settings or Startup.get_settings()

        service_provider.settings_file.override(Singleton(lambda: settings))
        service_provider.application.override(Factory(application_provider))

        return service_provider

    @staticmethod
    def get_settings() -> JsonSettingsFile:
        profile_name = EnvironmentConfiguration.get_variable("profile")
        settings_profile = "settings.json" if not profile_name else f"settings.{profile_name}.json"
        if FileReader.is_resource_file_exist(settings_profile, root_path=RootPathHelper.calling_root_path()):
            return JsonSettingsFile(setting_name=settings_profile, root_path=RootPathHelper.calling_root_path())
        return JsonSettingsFile(setting_name=settings_profile, root_path=RootPathHelper.executing_root_path())

service_provider = Startup.configure_services(application_provider=lambda: YourApplication())
service_provider.application()
service_provider.logger().info("Message")

To use a different implementation between dependencies, you need to execute provider.override:

service_provider = ServiceProvider()
service_provider.timeout_configuration.override(Singleton(CustomTimeoutConfiguration, service_provider.settings_file))

If you want to have your own CustomServiceProvider implementation that complements the base container, you can use inheritance, as in the example below:

class CustomServiceProvider(ServiceProvider):
    timeout: Sigleton[CustomTimeoutConfiguration] = Singleton(CustomTimeoutConfiguration, ServiceProvider.settings_file)

Keep in mind that the internal dependencies of the ServiceProvider container will interact with ServiceProvider.timeout, and not with CustomServiceProvider.timeout. The solution is quite simple:

ServiceProvider.override(CustomServiceProvider)
service_provider = Startup.configure_services(application_provider=lambda: YourApplication(), service_provider=CustomServiceProvider())
ServiceProvider.reset_override()  # necessary because override overrides the base container

or add your implementation of Startup:

class CustomSPStartup(Startup):

    @staticmethod
    def configure_services(
            application_provider: Callable, settings: Optional[JsonSettingsFile] = None, service_provider: Optional[ServiceProvider] = None,
    ) -> CustomServiceProvider:
        ServiceProvider.override(CustomServiceProvider)

        settings = JsonSettingsFile("settings.special.json", RootPathHelper.calling_root_path())
        service_provider = Startup.configure_services(application_provider, settings, CustomServiceProvider())

        ServiceProvider.reset_override()
        return service_provider
  1. Setup BrowserService using CoreServices

The solution also contains a CoreService, which helps to register your container and application, with which you can interact in the future:

The simplest way is to create your own Services class extended from abstract CoreServices with the following simple signature:

class BrowserServices(CoreServices):

    @classmethod
    def is_application_started(cls) -> bool:
        return cls._is_application_started()

    @classmethod
    def application(cls) -> YourApplication:
        return cls._get_application(lambda service: cls._start_application(service))

    @classmethod
    def service_provider(cls) -> ServiceProvider:
        return cls._get_service_provider(lambda service: cls.application())

    @classmethod
    def _start_application(cls, service_provider: ServiceProvider):
        ...  # your implementation

If you need to register your own services / rewrite the implementation, you need override Startup and implement BrowserServices like in example below:

class TestStartup(Startup):

    @staticmethod
    def configure_services(
            application_provider: Callable,
            settings: Optional[JsonSettingsFile] = None,
            service_provider: Optional[ServiceProvider] = None,
    ) -> ServiceProvider:
        settings = JsonSettingsFile("settings.special.json", RootPathHelper.calling_root_path())
        service_provider = Startup.configure_services(application_provider, settings)
        service_provider.timeout_configuration.override(
            Singleton(TestTimeoutConfiguration, service_provider.settings_file)
        )
        return service_provider

class BrowserServices:

    class _BrowserService(CoreServices):

        startup: TestStartup = TestStartup()

        def __init__(self):
            Logger.info("Create")

        @property
        def application(self) -> Application:
            return self._get_application(
                self._start_function,
                lambda: self.startup.configure_services(lambda service: self.application),
            )

        @property
        def service_provider(self) -> ServiceProvider:
            return self._get_service_provider(
                lambda service: self.application,
                lambda: self.startup.configure_services(lambda service: self.application),
            )

        def set_startup(self, startup: Startup):
            if startup is not None:
                self.startup = startup

        @property
        def _start_function(self):
            return lambda serive: Application()

    Instance: _BrowserService = _BrowserService()


class CustomStartup(Startup):

    @staticmethod
    def configure_services(application_provider: Callable, settings: JsonSettingsFile = None) -> ServiceProvider:
        service_provider = Startup.configure_services(application_provider, settings)
        # your implementation service_provider.timeout_configuration.override(Singleton(TimeoutConfiguration, service_provider.settings_file))
        return service_provider
  1. Work with Application via the implemented BrowserServices or via element services

All the services could be resolved from the Dependency Injection container via ServiceProvider

BrowserServices.application().driver.find_element(ELEMENT).click()
BrowserServices.service_provider().conditional_wait().wait_for_driver(
    lambda driver: len(driver.find_elements(Locator(By.XPATH, "//*"))) > 0
)

or with Instance:

BrowserServices.Instance.application.driver.find_element(ELEMENT).click()
BrowserServices.Instance.service_provider.conditional_wait().wait_for_driver(
    lambda driver: len(driver.find_elements(Locator(By.XPATH, "//*"))) > 0
)

License

Library's source code is made available under the Apache 2.0 license.

Metadata

Release files for py-selenium-auto-core 0.5.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for py-selenium-auto-core 0.5.6
File Size Uploaded
py_selenium_auto_core-0.5.6.tar.gz 28.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for py-selenium-auto-core 0.5.6
File Interpreter ABI Platform
py_selenium_auto_core-0.5.6-py3-none-any.whl Python 3 none any Details

Total release size: 67.9 kB

Release files / py_selenium_auto_core-0.5.6.tar.gz

Download URL py_selenium_auto_core-0.5.6.tar.gz
Size 28.8 kB
Tags Source
SHA-256 checksum
How to use checksums
9394df636aafac48ed66616bd859b2256b4f500e5bd423888f27d7bb237e191b
BLAKE2b-256 checksum
How to use checksums
f928328dfe3b63595f03b590dd5b2dab394fe41c477e807f5fbc10bc65f5859b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.1.1 CPython/3.12.6

Release files / py_selenium_auto_core-0.5.6-py3-none-any.whl

Download URL py_selenium_auto_core-0.5.6-py3-none-any.whl
Size 39.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
90583471ec5780583da0b610f261dbeed1fdb75234b4dc5b3421c29a20bb3060
BLAKE2b-256 checksum
How to use checksums
bc2ad745f348ff1898df69568f0a357651501d1b2434ae146dcefd8365bae90a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.1.1 CPython/3.12.6

Release history Release notifications | RSS feed

This release

0.5.6 This release

2 release files

0.5.5

2 release files

0.5.4

2 release files

0.5.3

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.4

2 release files

0.4.3

2 release files

0.4.1

2 release files

0.4.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page