Package: py-selenium-auto-core
Selenium CORE for PythonIntroductionIt's a library with core functions simplifying work with Selenium-controlled applications.This package is based onAquality Selenium CORE for .NETand 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 withAquality Selenium CORE.To simplify overriding of implementations this solution uses Dependency Injection.Supported Python VersionsPython 3.7-3.9InstallationIf you havepipon your system, you can simply install or upgrade the Python bindings:pipinstallpy-selenium-auto-coreAlternately, you can download the source distribution fromPyPI, unarchive it, and run:pythonsetup.pyinstallQuick startSetup Dependency Injection container using StartupThe solution offers a ServiceProvider implementation using Dependency Injection container as a single point for interacting with various services and their dependencies:classServiceProvider(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 loggingServiceProvider.timeout_configuration().interval# Getting the Timeout.interval valueFor 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:classStartup:@staticmethoddefconfigure_services(application_provider:Callable,settings:Optional[JsonSettingsFile]=None,service_provider:Optional[T]=None,)->T|ServiceProvider:service_provider:T=service_providerorServiceProvider()settings=settingsorStartup.get_settings()service_provider.settings_file.override(Singleton(lambda:settings))service_provider.application.override(Factory(application_provider))returnservice_provider@staticmethoddefget_settings()->JsonSettingsFile:profile_name=EnvironmentConfiguration.get_variable("profile")settings_profile="settings.json"ifnotprofile_nameelsef"settings.{profile_name}.json"ifFileReader.is_resource_file_exist(settings_profile,root_path=RootPathHelper.calling_root_path()):returnJsonSettingsFile(setting_name=settings_profile,root_path=RootPathHelper.calling_root_path())returnJsonSettingsFile(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:classCustomServiceProvider(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 containeror add your implementation of Startup:classCustomSPStartup(Startup):@staticmethoddefconfigure_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()returnservice_providerSetup BrowserService using CoreServicesThe 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:classBrowserServices(CoreServices):@classmethoddefis_application_started(cls)->bool:returncls._is_application_started()@classmethoddefapplication(cls)->YourApplication:returncls._get_application(lambdaservice:cls._start_application(service))@classmethoddefservice_provider(cls)->ServiceProvider:returncls._get_service_provider(lambdaservice:cls.application())@classmethoddef_start_application(cls,service_provider:ServiceProvider):...# your implementationIf you need to register your own services / rewrite the implementation, you need override Startup and implement BrowserServices like in example below:classTestStartup(Startup):@staticmethoddefconfigure_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))returnservice_providerclassBrowserServices:class_BrowserService(CoreServices):startup:TestStartup=TestStartup()def__init__(self):Logger.info("Create")@propertydefapplication(self)->Application:returnself._get_application(self._start_function,lambda:self.startup.configure_services(lambdaservice:self.application),)@propertydefservice_provider(self)->ServiceProvider:returnself._get_service_provider(lambdaservice:self.application,lambda:self.startup.configure_services(lambdaservice:self.application),)defset_startup(self,startup:Startup):ifstartupisnotNone:self.startup=startup@propertydef_start_function(self):returnlambdaserive:Application()Instance:_BrowserService=_BrowserService()classCustomStartup(Startup):@staticmethoddefconfigure_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))returnservice_providerWork with Application via the implemented BrowserServices or via element servicesAll the services could be resolved from the Dependency Injection container via ServiceProviderBrowserServices.application().driver.find_element(ELEMENT).click()BrowserServices.service_provider().conditional_wait().wait_for_driver(lambdadriver: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(lambdadriver:len(driver.find_elements(Locator(By.XPATH,"//*")))>0)LicenseLibrary's source code is made available under theApache 2.0 license.