Appium-Python-Client 5.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (324) hide show
  1. appium/__init__.py +17 -0
  2. appium/common/__init__.py +17 -0
  3. appium/common/exceptions.py +26 -0
  4. appium/common/helper.py +42 -0
  5. appium/common/logger.py +28 -0
  6. appium/options/__init__.py +0 -0
  7. appium/options/android/__init__.py +2 -0
  8. appium/options/android/common/__init__.py +0 -0
  9. appium/options/android/common/adb/__init__.py +0 -0
  10. appium/options/android/common/adb/adb_exec_timeout_option.py +41 -0
  11. appium/options/android/common/adb/adb_port_option.py +38 -0
  12. appium/options/android/common/adb/allow_delay_adb_option.py +39 -0
  13. appium/options/android/common/adb/build_tools_version_option.py +42 -0
  14. appium/options/android/common/adb/clear_device_logs_on_start_option.py +40 -0
  15. appium/options/android/common/adb/ignore_hidden_api_policy_error_option.py +40 -0
  16. appium/options/android/common/adb/logcat_filter_specs_option.py +42 -0
  17. appium/options/android/common/adb/logcat_format_option.py +39 -0
  18. appium/options/android/common/adb/mock_location_app_option.py +42 -0
  19. appium/options/android/common/adb/remote_adb_host_option.py +39 -0
  20. appium/options/android/common/adb/skip_logcat_capture_option.py +40 -0
  21. appium/options/android/common/adb/suppress_kill_server_option.py +39 -0
  22. appium/options/android/common/app/__init__.py +0 -0
  23. appium/options/android/common/app/allow_test_packages_option.py +40 -0
  24. appium/options/android/common/app/android_install_timeout_option.py +43 -0
  25. appium/options/android/common/app/app_activity_option.py +39 -0
  26. appium/options/android/common/app/app_package_option.py +39 -0
  27. appium/options/android/common/app/app_wait_activity_option.py +40 -0
  28. appium/options/android/common/app/app_wait_duration_option.py +41 -0
  29. appium/options/android/common/app/app_wait_for_launch_option.py +41 -0
  30. appium/options/android/common/app/app_wait_package_option.py +40 -0
  31. appium/options/android/common/app/auto_grant_premissions_option.py +40 -0
  32. appium/options/android/common/app/enforce_app_install_option.py +40 -0
  33. appium/options/android/common/app/intent_action_option.py +40 -0
  34. appium/options/android/common/app/intent_category_option.py +40 -0
  35. appium/options/android/common/app/intent_flags_option.py +40 -0
  36. appium/options/android/common/app/optional_intent_arguments_option.py +40 -0
  37. appium/options/android/common/app/remote_apps_cache_limit_option.py +42 -0
  38. appium/options/android/common/app/uninstall_other_packages_option.py +39 -0
  39. appium/options/android/common/avd/__init__.py +0 -0
  40. appium/options/android/common/avd/avd_args_option.py +38 -0
  41. appium/options/android/common/avd/avd_env_option.py +38 -0
  42. appium/options/android/common/avd/avd_launch_timeout_option.py +41 -0
  43. appium/options/android/common/avd/avd_option.py +41 -0
  44. appium/options/android/common/avd/avd_ready_timeout_option.py +41 -0
  45. appium/options/android/common/avd/gps_enabled_option.py +39 -0
  46. appium/options/android/common/avd/network_speed_option.py +41 -0
  47. appium/options/android/common/context/__init__.py +0 -0
  48. appium/options/android/common/context/auto_webview_timeout_option.py +41 -0
  49. appium/options/android/common/context/chrome_logging_prefs_option.py +41 -0
  50. appium/options/android/common/context/chrome_options_option.py +40 -0
  51. appium/options/android/common/context/chromedriver_args_option.py +41 -0
  52. appium/options/android/common/context/chromedriver_chrome_mapping_file_option.py +43 -0
  53. appium/options/android/common/context/chromedriver_disable_build_check_option.py +41 -0
  54. appium/options/android/common/context/chromedriver_executable_dir_option.py +43 -0
  55. appium/options/android/common/context/chromedriver_executable_option.py +38 -0
  56. appium/options/android/common/context/chromedriver_port_option.py +39 -0
  57. appium/options/android/common/context/chromedriver_ports_option.py +39 -0
  58. appium/options/android/common/context/chromedriver_use_system_executable_option.py +40 -0
  59. appium/options/android/common/context/ensure_webviews_have_pages_option.py +40 -0
  60. appium/options/android/common/context/extract_chrome_android_package_from_context_name_option.py +40 -0
  61. appium/options/android/common/context/native_web_screenshot_option.py +40 -0
  62. appium/options/android/common/context/recreate_chrome_driver_sessions_option.py +41 -0
  63. appium/options/android/common/context/show_chromedriver_log_option.py +39 -0
  64. appium/options/android/common/context/webview_devtools_port_option.py +40 -0
  65. appium/options/android/common/localization/__init__.py +0 -0
  66. appium/options/android/common/localization/locale_script_option.py +40 -0
  67. appium/options/android/common/locking/__init__.py +0 -0
  68. appium/options/android/common/locking/skip_unlock_option.py +42 -0
  69. appium/options/android/common/locking/unlock_key_option.py +40 -0
  70. appium/options/android/common/locking/unlock_strategy_option.py +40 -0
  71. appium/options/android/common/locking/unlock_success_timeout_option.py +43 -0
  72. appium/options/android/common/locking/unlock_type_option.py +40 -0
  73. appium/options/android/common/mjpeg/__init__.py +0 -0
  74. appium/options/android/common/mjpeg/mjpeg_screenshot_url_option.py +40 -0
  75. appium/options/android/common/other/__init__.py +0 -0
  76. appium/options/android/common/other/disable_suppress_accessibility_service_option.py +40 -0
  77. appium/options/android/common/other/user_profile_option.py +42 -0
  78. appium/options/android/common/signing/__init__.py +0 -0
  79. appium/options/android/common/signing/key_alias_option.py +40 -0
  80. appium/options/android/common/signing/key_password_option.py +40 -0
  81. appium/options/android/common/signing/keystore_password_option.py +40 -0
  82. appium/options/android/common/signing/keystore_path_option.py +40 -0
  83. appium/options/android/common/signing/no_sign_option.py +42 -0
  84. appium/options/android/common/signing/use_keystore_option.py +42 -0
  85. appium/options/android/espresso/__init__.py +0 -0
  86. appium/options/android/espresso/activity_options_option.py +41 -0
  87. appium/options/android/espresso/app_locale_option.py +44 -0
  88. appium/options/android/espresso/base.py +221 -0
  89. appium/options/android/espresso/espresso_build_config_option.py +46 -0
  90. appium/options/android/espresso/espresso_server_launch_timeout_option.py +43 -0
  91. appium/options/android/espresso/force_espresso_rebuild_option.py +41 -0
  92. appium/options/android/espresso/intent_options_option.py +41 -0
  93. appium/options/android/espresso/show_gradle_log_option.py +39 -0
  94. appium/options/android/uiautomator2/__init__.py +0 -0
  95. appium/options/android/uiautomator2/base.py +221 -0
  96. appium/options/android/uiautomator2/disable_window_animation_option.py +40 -0
  97. appium/options/android/uiautomator2/mjpeg_server_port_option.py +41 -0
  98. appium/options/android/uiautomator2/skip_device_initialization_option.py +40 -0
  99. appium/options/android/uiautomator2/skip_server_installation_option.py +44 -0
  100. appium/options/android/uiautomator2/uiautomator2_server_install_timeout_option.py +44 -0
  101. appium/options/android/uiautomator2/uiautomator2_server_launch_timeout_option.py +44 -0
  102. appium/options/android/uiautomator2/uiautomator2_server_read_timeout_option.py +46 -0
  103. appium/options/common/__init__.py +1 -0
  104. appium/options/common/app_option.py +41 -0
  105. appium/options/common/auto_web_view_option.py +40 -0
  106. appium/options/common/automation_name_option.py +38 -0
  107. appium/options/common/base.py +125 -0
  108. appium/options/common/browser_name_option.py +38 -0
  109. appium/options/common/bundle_id_option.py +38 -0
  110. appium/options/common/clear_system_files_option.py +38 -0
  111. appium/options/common/device_name_option.py +38 -0
  112. appium/options/common/enable_performance_logging_option.py +38 -0
  113. appium/options/common/event_timings_option.py +40 -0
  114. appium/options/common/full_reset_option.py +38 -0
  115. appium/options/common/is_headless_option.py +39 -0
  116. appium/options/common/language_option.py +38 -0
  117. appium/options/common/locale_option.py +38 -0
  118. appium/options/common/new_command_timeout_option.py +41 -0
  119. appium/options/common/no_reset_option.py +38 -0
  120. appium/options/common/orientation_option.py +40 -0
  121. appium/options/common/other_apps_option.py +39 -0
  122. appium/options/common/platform_version_option.py +40 -0
  123. appium/options/common/postrun_option.py +39 -0
  124. appium/options/common/prerun_option.py +40 -0
  125. appium/options/common/print_page_source_on_find_failure_option.py +40 -0
  126. appium/options/common/skip_log_capture_option.py +38 -0
  127. appium/options/common/supports_capabilities.py +26 -0
  128. appium/options/common/system_host_option.py +38 -0
  129. appium/options/common/system_port_option.py +38 -0
  130. appium/options/common/udid_option.py +38 -0
  131. appium/options/flutter_integration/__init__.py +15 -0
  132. appium/options/flutter_integration/base.py +39 -0
  133. appium/options/flutter_integration/flutter_element_wait_timeout_option.py +50 -0
  134. appium/options/flutter_integration/flutter_enable_mock_camera_option.py +44 -0
  135. appium/options/flutter_integration/flutter_server_launch_timeout_option.py +51 -0
  136. appium/options/flutter_integration/flutter_system_port_option.py +45 -0
  137. appium/options/gecko/__init__.py +1 -0
  138. appium/options/gecko/android_storage_option.py +39 -0
  139. appium/options/gecko/base.py +51 -0
  140. appium/options/gecko/firefox_options_option.py +38 -0
  141. appium/options/gecko/marionette_port_option.py +43 -0
  142. appium/options/gecko/verbosity_option.py +40 -0
  143. appium/options/ios/__init__.py +2 -0
  144. appium/options/ios/safari/__init__.py +0 -0
  145. appium/options/ios/safari/automatic_inspection_option.py +41 -0
  146. appium/options/ios/safari/automatic_profiling_option.py +41 -0
  147. appium/options/ios/safari/base.py +51 -0
  148. appium/options/ios/safari/device_name_option.py +43 -0
  149. appium/options/ios/safari/device_type_option.py +41 -0
  150. appium/options/ios/safari/device_udid_option.py +43 -0
  151. appium/options/ios/safari/platform_build_version_option.py +41 -0
  152. appium/options/ios/safari/platform_version_option.py +41 -0
  153. appium/options/ios/safari/use_simulator_option.py +41 -0
  154. appium/options/ios/safari/webkit_webrtc_option.py +52 -0
  155. appium/options/ios/xcuitest/__init__.py +0 -0
  156. appium/options/ios/xcuitest/app/__init__.py +0 -0
  157. appium/options/ios/xcuitest/app/app_install_strategy_option.py +46 -0
  158. appium/options/ios/xcuitest/app/app_push_timeout_option.py +42 -0
  159. appium/options/ios/xcuitest/app/localizable_strings_dir_option.py +39 -0
  160. appium/options/ios/xcuitest/base.py +223 -0
  161. appium/options/ios/xcuitest/general/__init__.py +0 -0
  162. appium/options/ios/xcuitest/general/include_device_caps_to_session_info_option.py +41 -0
  163. appium/options/ios/xcuitest/general/reset_location_service_option.py +39 -0
  164. appium/options/ios/xcuitest/other/__init__.py +0 -0
  165. appium/options/ios/xcuitest/other/command_timeouts_option.py +57 -0
  166. appium/options/ios/xcuitest/other/launch_with_idb_option.py +42 -0
  167. appium/options/ios/xcuitest/other/show_ios_log_option.py +39 -0
  168. appium/options/ios/xcuitest/other/use_json_source_option.py +39 -0
  169. appium/options/ios/xcuitest/simulator/__init__.py +0 -0
  170. appium/options/ios/xcuitest/simulator/calendar_access_authorized_option.py +41 -0
  171. appium/options/ios/xcuitest/simulator/calendar_format_option.py +38 -0
  172. appium/options/ios/xcuitest/simulator/connect_hardware_keyboard_option.py +43 -0
  173. appium/options/ios/xcuitest/simulator/custom_ssl_cert_option.py +39 -0
  174. appium/options/ios/xcuitest/simulator/enforce_fresh_simulator_creation_option.py +39 -0
  175. appium/options/ios/xcuitest/simulator/force_simulator_software_keyboard_presence_option.py +45 -0
  176. appium/options/ios/xcuitest/simulator/ios_simulator_logs_predicate_option.py +38 -0
  177. appium/options/ios/xcuitest/simulator/keep_key_chains_option.py +39 -0
  178. appium/options/ios/xcuitest/simulator/keychains_exclude_patterns_option.py +44 -0
  179. appium/options/ios/xcuitest/simulator/permissions_option.py +50 -0
  180. appium/options/ios/xcuitest/simulator/reduce_motion_option.py +40 -0
  181. appium/options/ios/xcuitest/simulator/reset_on_session_start_only_option.py +41 -0
  182. appium/options/ios/xcuitest/simulator/scale_factor_option.py +44 -0
  183. appium/options/ios/xcuitest/simulator/shutdown_other_simulators_option.py +44 -0
  184. appium/options/ios/xcuitest/simulator/simulator_devices_set_path_option.py +41 -0
  185. appium/options/ios/xcuitest/simulator/simulator_pasteboard_automatic_sync_option.py +42 -0
  186. appium/options/ios/xcuitest/simulator/simulator_startup_timeout_option.py +46 -0
  187. appium/options/ios/xcuitest/simulator/simulator_trace_pointer_option.py +41 -0
  188. appium/options/ios/xcuitest/simulator/simulator_window_center_option.py +41 -0
  189. appium/options/ios/xcuitest/wda/__init__.py +0 -0
  190. appium/options/ios/xcuitest/wda/allow_provisioning_device_regitration_option.py +40 -0
  191. appium/options/ios/xcuitest/wda/auto_accept_alerts_option.py +39 -0
  192. appium/options/ios/xcuitest/wda/auto_disimiss_alerts_option.py +39 -0
  193. appium/options/ios/xcuitest/wda/derived_data_path_option.py +41 -0
  194. appium/options/ios/xcuitest/wda/disable_automatic_screenshots_option.py +40 -0
  195. appium/options/ios/xcuitest/wda/force_app_launch_option.py +42 -0
  196. appium/options/ios/xcuitest/wda/keychain_password_option.py +39 -0
  197. appium/options/ios/xcuitest/wda/keychain_path_option.py +39 -0
  198. appium/options/ios/xcuitest/wda/max_typing_frequency_option.py +40 -0
  199. appium/options/ios/xcuitest/wda/mjpeg_server_port_option.py +42 -0
  200. appium/options/ios/xcuitest/wda/process_arguments_option.py +42 -0
  201. appium/options/ios/xcuitest/wda/result_bundle_path_option.py +42 -0
  202. appium/options/ios/xcuitest/wda/screenshot_quality_option.py +42 -0
  203. appium/options/ios/xcuitest/wda/should_terminate_app_option.py +42 -0
  204. appium/options/ios/xcuitest/wda/should_use_singleton_test_manager_option.py +39 -0
  205. appium/options/ios/xcuitest/wda/show_xcode_log_option.py +40 -0
  206. appium/options/ios/xcuitest/wda/simple_is_visible_check_option.py +42 -0
  207. appium/options/ios/xcuitest/wda/updated_wda_bundle_id_option.py +39 -0
  208. appium/options/ios/xcuitest/wda/use_native_caching_strategy_option.py +41 -0
  209. appium/options/ios/xcuitest/wda/use_new_wda_option.py +51 -0
  210. appium/options/ios/xcuitest/wda/use_prebuilt_wda_option.py +39 -0
  211. appium/options/ios/xcuitest/wda/use_simple_build_test_option.py +40 -0
  212. appium/options/ios/xcuitest/wda/use_xctestrun_file_option.py +49 -0
  213. appium/options/ios/xcuitest/wda/wait_for_idle_timeout_option.py +45 -0
  214. appium/options/ios/xcuitest/wda/wait_for_quiescence_option.py +42 -0
  215. appium/options/ios/xcuitest/wda/wda_base_url_option.py +41 -0
  216. appium/options/ios/xcuitest/wda/wda_connection_timeout_option.py +43 -0
  217. appium/options/ios/xcuitest/wda/wda_eventloop_idle_delay_option.py +46 -0
  218. appium/options/ios/xcuitest/wda/wda_launch_timeout_option.py +41 -0
  219. appium/options/ios/xcuitest/wda/wda_local_port_option.py +41 -0
  220. appium/options/ios/xcuitest/wda/wda_startup_retries_option.py +39 -0
  221. appium/options/ios/xcuitest/wda/wda_startup_retry_interval_option.py +43 -0
  222. appium/options/ios/xcuitest/wda/web_driver_agent_url_option.py +39 -0
  223. appium/options/ios/xcuitest/wda/xcode_org_id_option.py +39 -0
  224. appium/options/ios/xcuitest/wda/xcode_signing_id_option.py +39 -0
  225. appium/options/ios/xcuitest/webview/__init__.py +0 -0
  226. appium/options/ios/xcuitest/webview/absolute_web_locations_option.py +42 -0
  227. appium/options/ios/xcuitest/webview/additional_webview_bundle_ids_option.py +40 -0
  228. appium/options/ios/xcuitest/webview/enable_async_execute_from_https_option.py +39 -0
  229. appium/options/ios/xcuitest/webview/full_context_list_option.py +42 -0
  230. appium/options/ios/xcuitest/webview/include_safari_in_webviews_option.py +41 -0
  231. appium/options/ios/xcuitest/webview/native_web_tap_option.py +40 -0
  232. appium/options/ios/xcuitest/webview/safari_garbage_collect_option.py +39 -0
  233. appium/options/ios/xcuitest/webview/safari_ignore_fraud_warning_option.py +39 -0
  234. appium/options/ios/xcuitest/webview/safari_ignore_web_hostnames_option.py +42 -0
  235. appium/options/ios/xcuitest/webview/safari_initial_url_option.py +38 -0
  236. appium/options/ios/xcuitest/webview/safari_log_all_communication_hex_dump_option.py +43 -0
  237. appium/options/ios/xcuitest/webview/safari_log_all_communication_option.py +40 -0
  238. appium/options/ios/xcuitest/webview/safari_open_links_in_background_option.py +39 -0
  239. appium/options/ios/xcuitest/webview/safari_socket_chunk_size_option.py +41 -0
  240. appium/options/ios/xcuitest/webview/safari_web_inspector_max_frame_length_option.py +41 -0
  241. appium/options/ios/xcuitest/webview/webkit_response_timeout_option.py +43 -0
  242. appium/options/ios/xcuitest/webview/webview_connect_retries_option.py +40 -0
  243. appium/options/ios/xcuitest/webview/webview_connect_timeout_option.py +43 -0
  244. appium/options/mac/__init__.py +1 -0
  245. appium/options/mac/mac2/__init__.py +0 -0
  246. appium/options/mac/mac2/app_path_option.py +39 -0
  247. appium/options/mac/mac2/arguments_option.py +39 -0
  248. appium/options/mac/mac2/base.py +113 -0
  249. appium/options/mac/mac2/bootstrap_root_option.py +41 -0
  250. appium/options/mac/mac2/environment_option.py +41 -0
  251. appium/options/mac/mac2/server_startup_timeout_option.py +44 -0
  252. appium/options/mac/mac2/show_server_logs_option.py +39 -0
  253. appium/options/mac/mac2/skip_app_kill_option.py +40 -0
  254. appium/options/mac/mac2/web_driver_agent_mac_url_option.py +39 -0
  255. appium/options/windows/__init__.py +1 -0
  256. appium/options/windows/windows/__init__.py +0 -0
  257. appium/options/windows/windows/app_arguments_option.py +40 -0
  258. appium/options/windows/windows/app_top_level_window_option.py +40 -0
  259. appium/options/windows/windows/app_working_dir_option.py +40 -0
  260. appium/options/windows/windows/base.py +97 -0
  261. appium/options/windows/windows/create_session_timeout_option.py +45 -0
  262. appium/options/windows/windows/expreimental_web_driver_option.py +39 -0
  263. appium/options/windows/windows/wait_for_app_launch_option.py +43 -0
  264. appium/protocols/__init__.py +13 -0
  265. appium/protocols/webdriver/__init__.py +13 -0
  266. appium/protocols/webdriver/can_execute_commands.py +23 -0
  267. appium/protocols/webdriver/can_execute_scripts.py +27 -0
  268. appium/protocols/webdriver/can_find_elements.py +32 -0
  269. appium/protocols/webdriver/can_remember_extension_presence.py +23 -0
  270. appium/py.typed +0 -0
  271. appium/version.py +22 -0
  272. appium/webdriver/__init__.py +20 -0
  273. appium/webdriver/appium_connection.py +65 -0
  274. appium/webdriver/appium_service.py +330 -0
  275. appium/webdriver/applicationstate.py +21 -0
  276. appium/webdriver/client_config.py +38 -0
  277. appium/webdriver/clipboard_content_type.py +19 -0
  278. appium/webdriver/command_method.py +27 -0
  279. appium/webdriver/common/__init__.py +17 -0
  280. appium/webdriver/common/appiumby.py +54 -0
  281. appium/webdriver/connectiontype.py +42 -0
  282. appium/webdriver/errorhandler.py +125 -0
  283. appium/webdriver/extensions/__init__.py +13 -0
  284. appium/webdriver/extensions/action_helpers.py +188 -0
  285. appium/webdriver/extensions/android/__init__.py +0 -0
  286. appium/webdriver/extensions/android/activities.py +65 -0
  287. appium/webdriver/extensions/android/common.py +59 -0
  288. appium/webdriver/extensions/android/display.py +48 -0
  289. appium/webdriver/extensions/android/gsm.py +147 -0
  290. appium/webdriver/extensions/android/nativekey.py +1119 -0
  291. appium/webdriver/extensions/android/network.py +175 -0
  292. appium/webdriver/extensions/android/performance.py +85 -0
  293. appium/webdriver/extensions/android/power.py +80 -0
  294. appium/webdriver/extensions/android/sms.py +50 -0
  295. appium/webdriver/extensions/android/system_bars.py +58 -0
  296. appium/webdriver/extensions/applications.py +274 -0
  297. appium/webdriver/extensions/clipboard.py +107 -0
  298. appium/webdriver/extensions/context.py +63 -0
  299. appium/webdriver/extensions/device_time.py +75 -0
  300. appium/webdriver/extensions/execute_driver.py +60 -0
  301. appium/webdriver/extensions/execute_mobile_command.py +62 -0
  302. appium/webdriver/extensions/flutter_integration/__init__.py +13 -0
  303. appium/webdriver/extensions/flutter_integration/flutter_commands.py +296 -0
  304. appium/webdriver/extensions/flutter_integration/flutter_finder.py +55 -0
  305. appium/webdriver/extensions/flutter_integration/scroll_directions.py +6 -0
  306. appium/webdriver/extensions/hw_actions.py +149 -0
  307. appium/webdriver/extensions/images_comparison.py +132 -0
  308. appium/webdriver/extensions/keyboard.py +168 -0
  309. appium/webdriver/extensions/location.py +98 -0
  310. appium/webdriver/extensions/log_event.py +68 -0
  311. appium/webdriver/extensions/logs.py +53 -0
  312. appium/webdriver/extensions/remote_fs.py +110 -0
  313. appium/webdriver/extensions/screen_record.py +207 -0
  314. appium/webdriver/extensions/session.py +41 -0
  315. appium/webdriver/extensions/settings.py +49 -0
  316. appium/webdriver/locator_converter.py +29 -0
  317. appium/webdriver/mobilecommand.py +104 -0
  318. appium/webdriver/switch_to.py +35 -0
  319. appium/webdriver/webdriver.py +495 -0
  320. appium/webdriver/webelement.py +130 -0
  321. appium_python_client-5.2.0.dist-info/METADATA +573 -0
  322. appium_python_client-5.2.0.dist-info/RECORD +324 -0
  323. appium_python_client-5.2.0.dist-info/WHEEL +4 -0
  324. appium_python_client-5.2.0.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,495 @@
1
+ #!/usr/bin/env python
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Set, Tuple, Type, Union
16
+
17
+ from selenium import webdriver
18
+ from selenium.common.exceptions import (
19
+ InvalidArgumentException,
20
+ SessionNotCreatedException,
21
+ UnknownMethodException,
22
+ WebDriverException,
23
+ )
24
+ from selenium.webdriver.remote.command import Command as RemoteCommand
25
+ from selenium.webdriver.remote.remote_connection import RemoteConnection
26
+ from typing_extensions import Self
27
+
28
+ from appium.common.logger import logger
29
+ from appium.options.common.base import AppiumOptions
30
+
31
+ from .appium_connection import AppiumConnection
32
+ from .client_config import AppiumClientConfig
33
+ from .errorhandler import MobileErrorHandler
34
+ from .extensions.action_helpers import ActionHelpers
35
+ from .extensions.android.activities import Activities
36
+ from .extensions.android.common import Common
37
+ from .extensions.android.display import Display
38
+ from .extensions.android.gsm import Gsm
39
+ from .extensions.android.network import Network
40
+ from .extensions.android.performance import Performance
41
+ from .extensions.android.power import Power
42
+ from .extensions.android.sms import Sms
43
+ from .extensions.android.system_bars import SystemBars
44
+ from .extensions.applications import Applications
45
+ from .extensions.clipboard import Clipboard
46
+ from .extensions.context import Context
47
+ from .extensions.device_time import DeviceTime
48
+ from .extensions.execute_driver import ExecuteDriver
49
+ from .extensions.execute_mobile_command import ExecuteMobileCommand
50
+ from .extensions.hw_actions import HardwareActions
51
+ from .extensions.images_comparison import ImagesComparison
52
+ from .extensions.keyboard import Keyboard
53
+ from .extensions.location import Location
54
+ from .extensions.log_event import LogEvent
55
+ from .extensions.logs import Logs
56
+ from .extensions.remote_fs import RemoteFS
57
+ from .extensions.screen_record import ScreenRecord
58
+ from .extensions.session import Session
59
+ from .extensions.settings import Settings
60
+ from .locator_converter import AppiumLocatorConverter
61
+ from .mobilecommand import MobileCommand as Command
62
+ from .switch_to import MobileSwitchTo
63
+ from .webelement import WebElement as MobileWebElement
64
+
65
+
66
+ class ExtensionBase:
67
+ """
68
+ Used to define an extension command as driver's methods.
69
+
70
+ Example:
71
+ When you want to add `example_command` which calls a get request to
72
+ `session/$sessionId/path/to/your/custom/url`.
73
+
74
+ #. Defines an extension as a subclass of `ExtensionBase`
75
+ .. code-block:: python
76
+
77
+ class YourCustomCommand(ExtensionBase):
78
+ def method_name(self):
79
+ return 'custom_method_name'
80
+
81
+ # Define a method with the name of `method_name`
82
+ def custom_method_name(self):
83
+ # Generally the response of Appium follows `{ 'value': { data } }`
84
+ # format.
85
+ return self.execute()['value']
86
+
87
+ # Used to register the command pair as "Appium command" in this driver.
88
+ def add_command(self):
89
+ return ('GET', 'session/$sessionId/path/to/your/custom/url')
90
+
91
+ #. Creates a session with the extension.
92
+ .. code-block:: python
93
+
94
+ # Appium capabilities
95
+ options = AppiumOptions()
96
+ driver = webdriver.Remote('http://localhost:4723/wd/hub', options=options,
97
+ extensions=[YourCustomCommand])
98
+
99
+ #. Calls the custom command
100
+ .. code-block:: python
101
+
102
+ # Then, the driver calls a get request against
103
+ # `session/$sessionId/path/to/your/custom/url`. `$sessionId` will be
104
+ # replaced properly in the driver. Then, the method returns
105
+ # the `value` part of the response.
106
+ driver.custom_method_name()
107
+
108
+ #. Remove added commands (if needed)
109
+ .. code-block:: python
110
+
111
+ # New commands are added by `setattr`. They remain in the module,
112
+ # so you should explicitly delete them to define the same name method
113
+ # with different arguments or process in the method.
114
+ driver.delete_extensions()
115
+
116
+
117
+ You can give arbitrary arguments for the command like the below.
118
+
119
+ .. code-block:: python
120
+
121
+ class YourCustomCommand(ExtensionBase):
122
+ def method_name(self):
123
+ return 'custom_method_name'
124
+
125
+ def test_command(self, argument):
126
+ return self.execute(argument)['value']
127
+
128
+ def add_command(self):
129
+ return ('post', 'session/$sessionId/path/to/your/custom/url')
130
+
131
+ driver = webdriver.Remote('http://localhost:4723/wd/hub', options=options,
132
+ extensions=[YourCustomCommand])
133
+
134
+ # Then, the driver sends a post request to `session/$sessionId/path/to/your/custom/url`
135
+ # with `{'dummy_arg': 'as a value'}` JSON body.
136
+ driver.custom_method_name({'dummy_arg': 'as a value'})
137
+
138
+
139
+ When you customize the URL dynamically with element id.
140
+
141
+ .. code-block:: python
142
+
143
+ class CustomURLCommand(ExtensionBase):
144
+ def method_name(self):
145
+ return 'custom_method_name'
146
+
147
+ def custom_method_name(self, element_id):
148
+ return self.execute({'id': element_id})['value']
149
+
150
+ def add_command(self):
151
+ return ('GET', 'session/$sessionId/path/to/your/custom/$id/url')
152
+
153
+ driver = webdriver.Remote('http://localhost:4723/wd/hub', options=options,
154
+ extensions=[YourCustomCommand])
155
+ element = driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value='id')
156
+
157
+ # Then, the driver calls a get request to `session/$sessionId/path/to/your/custom/$id/url`
158
+ # with replacing the `$id` with the given `element.id`
159
+ driver.custom_method_name(element.id)
160
+
161
+ """
162
+
163
+ def __init__(self, execute: Callable[[str, Dict], Dict[str, Any]]):
164
+ self._execute = execute
165
+
166
+ def execute(self, parameters: Union[Dict[str, Any], None] = None) -> Any:
167
+ param = {}
168
+ if parameters:
169
+ param = parameters
170
+ return self._execute(self.method_name(), param)
171
+
172
+ def method_name(self) -> str:
173
+ """
174
+ Expected to return a method name.
175
+ This name will be available as a driver method.
176
+
177
+ Returns:
178
+ 'str' The method name.
179
+ """
180
+ raise NotImplementedError()
181
+
182
+ def add_command(self) -> Tuple[str, str]:
183
+ """
184
+ Expected to define the pair of HTTP method and its URL.
185
+ """
186
+ raise NotImplementedError()
187
+
188
+
189
+ def _get_remote_connection_and_client_config(
190
+ command_executor: Union[str, AppiumConnection], client_config: Optional[AppiumClientConfig] = None
191
+ ) -> tuple[AppiumConnection, Optional[AppiumClientConfig]]:
192
+ """Return the pair of command executor and client config.
193
+ If the given command executor is a custom one, returned client config will
194
+ be None since the custom command executor has its own client config already.
195
+ The custom command executor's one will be prior than the given client config.
196
+ """
197
+ if not isinstance(command_executor, str):
198
+ # client config already defined in the custom command executor
199
+ # will be prior than the given one.
200
+ return (command_executor, None)
201
+
202
+ # command_executor is str
203
+
204
+ # Do not keep None to avoid warnings in Selenium
205
+ # which can prevent with ClientConfig instance usage.
206
+ new_client_config = AppiumClientConfig(remote_server_addr=command_executor) if client_config is None else client_config
207
+ return (AppiumConnection(client_config=new_client_config), new_client_config)
208
+
209
+
210
+ class WebDriver(
211
+ webdriver.Remote,
212
+ ActionHelpers,
213
+ Activities,
214
+ Applications,
215
+ Clipboard,
216
+ Context,
217
+ Common,
218
+ DeviceTime,
219
+ Display,
220
+ ExecuteDriver,
221
+ ExecuteMobileCommand,
222
+ Gsm,
223
+ HardwareActions,
224
+ ImagesComparison,
225
+ Keyboard,
226
+ Location,
227
+ LogEvent,
228
+ Logs,
229
+ Network,
230
+ Performance,
231
+ Power,
232
+ RemoteFS,
233
+ ScreenRecord,
234
+ Session,
235
+ Settings,
236
+ Sms,
237
+ SystemBars,
238
+ ):
239
+ def __init__(
240
+ self,
241
+ command_executor: Union[str, AppiumConnection] = 'http://127.0.0.1:4723',
242
+ extensions: Optional[List[Type['ExtensionBase']]] = None,
243
+ options: Union[AppiumOptions, List[AppiumOptions], None] = None,
244
+ client_config: Optional[AppiumClientConfig] = None,
245
+ ):
246
+ command_executor, client_config = _get_remote_connection_and_client_config(
247
+ command_executor=command_executor, client_config=client_config
248
+ )
249
+ super().__init__(
250
+ command_executor=command_executor,
251
+ options=options, # type: ignore[arg-type]
252
+ locator_converter=AppiumLocatorConverter(),
253
+ web_element_cls=MobileWebElement,
254
+ client_config=client_config,
255
+ )
256
+
257
+ # to explicitly set type after the initialization
258
+ self.command_executor: RemoteConnection
259
+
260
+ self._add_commands()
261
+
262
+ self.error_handler = MobileErrorHandler()
263
+
264
+ if client_config and client_config.direct_connection:
265
+ self._update_command_executor(keep_alive=client_config.keep_alive)
266
+
267
+ self._absent_extensions: Set[str] = set()
268
+
269
+ self._extensions = extensions or []
270
+ for extension in self._extensions:
271
+ instance = extension(self.execute)
272
+ method_name = instance.method_name()
273
+ if hasattr(WebDriver, method_name):
274
+ logger.debug(f"Overriding the method '{method_name}'")
275
+
276
+ # add a new method named 'instance.method_name()' and call it
277
+ setattr(WebDriver, method_name, getattr(instance, method_name))
278
+ method, url_cmd = instance.add_command()
279
+ self.command_executor.add_command(method_name, method.upper(), url_cmd)
280
+
281
+ if TYPE_CHECKING:
282
+
283
+ def find_element(self, by: str, value: Union[str, Dict, None] = None) -> 'MobileWebElement': # type: ignore[override]
284
+ ...
285
+
286
+ def find_elements(self, by: str, value: Union[str, Dict, None] = None) -> List['MobileWebElement']: # type: ignore[override]
287
+ ...
288
+
289
+ def delete_extensions(self) -> None:
290
+ """Delete extensions added in the class with 'setattr'"""
291
+ for extension in self._extensions:
292
+ instance = extension(self.execute)
293
+ method_name = instance.method_name()
294
+ if hasattr(WebDriver, method_name):
295
+ delattr(WebDriver, method_name)
296
+
297
+ def _update_command_executor(self, keep_alive: bool) -> None:
298
+ """Update command executor following directConnect feature"""
299
+ direct_protocol = 'directConnectProtocol'
300
+ direct_host = 'directConnectHost'
301
+ direct_port = 'directConnectPort'
302
+ direct_path = 'directConnectPath'
303
+
304
+ assert self.caps, 'Driver capabilities must be defined'
305
+ if not {direct_protocol, direct_host, direct_port, direct_path}.issubset(set(self.caps)):
306
+ message = 'Direct connect capabilities from server were:\n'
307
+ for key in [direct_protocol, direct_host, direct_port, direct_path]:
308
+ message += f"{key}: '{self.caps.get(key, '')}' "
309
+ logger.debug(message)
310
+ return
311
+
312
+ protocol = self.caps[direct_protocol]
313
+ hostname = self.caps[direct_host]
314
+ port = self.caps[direct_port]
315
+ path = self.caps[direct_path]
316
+ executor = f'{protocol}://{hostname}:{port}{path}'
317
+
318
+ logger.debug('Updated request endpoint to %s', executor)
319
+ # Override command executor.
320
+ if isinstance(self.command_executor, AppiumConnection): # type: ignore
321
+ self.command_executor = AppiumConnection(executor, keep_alive=keep_alive)
322
+ else:
323
+ self.command_executor = RemoteConnection(executor, keep_alive=keep_alive)
324
+ self._add_commands()
325
+
326
+ # https://github.com/SeleniumHQ/selenium/blob/06fdf2966df6bca47c0ae45e8201cd30db9b9a49/py/selenium/webdriver/remote/webdriver.py#L277
327
+ # noinspection PyAttributeOutsideInit
328
+ def start_session(self, capabilities: Union[Dict, AppiumOptions], browser_profile: Optional[str] = None) -> None:
329
+ """Creates a new session with the desired capabilities.
330
+
331
+ Override for Appium
332
+
333
+ Args:
334
+ capabilities: Read https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/caps.md
335
+ for more details.
336
+ browser_profile: Browser profile
337
+ """
338
+ if not isinstance(capabilities, (dict, AppiumOptions)):
339
+ raise InvalidArgumentException('Capabilities must be a dictionary or AppiumOptions instance')
340
+
341
+ w3c_caps = AppiumOptions.as_w3c(capabilities) if isinstance(capabilities, dict) else capabilities.to_w3c()
342
+ response = self.execute(RemoteCommand.NEW_SESSION, w3c_caps)
343
+ # https://w3c.github.io/webdriver/#new-session
344
+ if not isinstance(response, dict):
345
+ raise SessionNotCreatedException(
346
+ f'A valid W3C session creation response must be a dictionary. Got "{response}" instead'
347
+ )
348
+ # Due to a W3C spec parsing misconception some servers
349
+ # pack the createSession response stuff into 'value' dictionary and
350
+ # some other put it to the top level of the response JSON nesting hierarchy
351
+ get_response_value: Callable[[str], Optional[Any]] = lambda key: response.get(key) or (
352
+ response['value'].get(key) if isinstance(response.get('value'), dict) else None
353
+ )
354
+ session_id = get_response_value('sessionId')
355
+ if not session_id:
356
+ raise SessionNotCreatedException(
357
+ f'A valid W3C session creation response must contain a non-empty "sessionId" entry. Got "{response}" instead'
358
+ )
359
+ self.session_id = session_id
360
+ self.caps = get_response_value('capabilities') or {}
361
+
362
+ def get_status(self) -> Dict:
363
+ """
364
+ Get the Appium server status
365
+
366
+ Usage:
367
+ driver.get_status()
368
+
369
+ Returns:
370
+ dict: The status information
371
+
372
+ """
373
+ return self.execute(Command.GET_STATUS)['value']
374
+
375
+ def create_web_element(self, element_id: Union[int, str]) -> MobileWebElement:
376
+ """Creates a web element with the specified element_id.
377
+
378
+ Overrides method in Selenium WebDriver in order to always give them
379
+ Appium WebElement
380
+
381
+ Args:
382
+ element_id: The element id to create a web element
383
+
384
+ Returns:
385
+ `MobileWebElement`
386
+ """
387
+ return MobileWebElement(self, element_id)
388
+
389
+ @property
390
+ def switch_to(self) -> MobileSwitchTo:
391
+ """Returns an object containing all options to switch focus into
392
+
393
+ Override for appium
394
+
395
+ Returns:
396
+ `appium.webdriver.switch_to.MobileSwitchTo`
397
+
398
+ """
399
+
400
+ return MobileSwitchTo(self)
401
+
402
+ # MJSONWP for Selenium v4
403
+ @property
404
+ def orientation(self) -> str:
405
+ """
406
+ Gets the current orientation of the device
407
+
408
+ Example:
409
+
410
+ .. code-block:: python
411
+
412
+ orientation = driver.orientation
413
+ """
414
+ return self.execute(Command.GET_SCREEN_ORIENTATION)['value']
415
+
416
+ # MJSONWP for Selenium v4
417
+ @orientation.setter
418
+ def orientation(self, value: str) -> None:
419
+ """
420
+ Sets the current orientation of the device
421
+
422
+ Args:
423
+ - value: orientation to set it to.
424
+
425
+ Example:
426
+ .. code-block:: python
427
+
428
+ driver.orientation = 'landscape'
429
+ """
430
+ allowed_values = ['LANDSCAPE', 'PORTRAIT']
431
+ if value.upper() in allowed_values:
432
+ self.execute(Command.SET_SCREEN_ORIENTATION, {'orientation': value})
433
+ else:
434
+ raise WebDriverException("You can only set the orientation to 'LANDSCAPE' and 'PORTRAIT'")
435
+
436
+ def assert_extension_exists(self, ext_name: str) -> Self:
437
+ """
438
+ Verifies if the given extension is not present in the list of absent extensions
439
+ for the given driver instance.
440
+ This API is designed for private usage.
441
+
442
+ Args:
443
+ ext_name: extension name
444
+
445
+ Returns:
446
+ self instance for chaining
447
+
448
+ Raises:
449
+ UnknownMethodException: If the extension has been marked as absent once
450
+ """
451
+ if ext_name in self._absent_extensions:
452
+ raise UnknownMethodException()
453
+ return self
454
+
455
+ def mark_extension_absence(self, ext_name: str) -> Self:
456
+ """
457
+ Marks the given extension as absent for the given driver instance.
458
+ This API is designed for private usage.
459
+
460
+ Args:
461
+ ext_name: extension name
462
+
463
+ Returns:
464
+ self instance for chaining
465
+ """
466
+ logger.debug(f'Marking driver extension "{ext_name}" as absent for the current instance')
467
+ self._absent_extensions.add(ext_name)
468
+ return self
469
+
470
+ def _add_commands(self) -> None:
471
+ # call the overridden command binders from all mixin classes except for
472
+ # appium.webdriver.webdriver.WebDriver and its sub-classes
473
+ # https://github.com/appium/python-client/issues/342
474
+ for mixin_class in filter(lambda x: not issubclass(x, WebDriver), self.__class__.__mro__):
475
+ if hasattr(mixin_class, self._add_commands.__name__):
476
+ get_atter = getattr(mixin_class, self._add_commands.__name__, None)
477
+ if get_atter:
478
+ get_atter(self)
479
+
480
+ self.command_executor.add_command(Command.GET_STATUS, 'GET', '/status')
481
+
482
+ # TODO Move commands for element to webelement
483
+ self.command_executor.add_command(Command.CLEAR, 'POST', '/session/$sessionId/element/$id/clear')
484
+ self.command_executor.add_command(
485
+ Command.LOCATION_IN_VIEW,
486
+ 'GET',
487
+ '/session/$sessionId/element/$id/location_in_view',
488
+ )
489
+
490
+ # MJSONWP for Selenium v4
491
+ self.command_executor.add_command(Command.IS_ELEMENT_DISPLAYED, 'GET', '/session/$sessionId/element/$id/displayed')
492
+ self.command_executor.add_command(Command.GET_CAPABILITIES, 'GET', '/session/$sessionId')
493
+
494
+ self.command_executor.add_command(Command.GET_SCREEN_ORIENTATION, 'GET', '/session/$sessionId/orientation')
495
+ self.command_executor.add_command(Command.SET_SCREEN_ORIENTATION, 'POST', '/session/$sessionId/orientation')
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env python
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Union
16
+
17
+ from selenium.webdriver.common.utils import keys_to_typing
18
+ from selenium.webdriver.remote.command import Command as RemoteCommand
19
+ from selenium.webdriver.remote.webelement import WebElement as SeleniumWebElement
20
+ from typing_extensions import Self
21
+
22
+ from .mobilecommand import MobileCommand as Command
23
+
24
+
25
+ class WebElement(SeleniumWebElement):
26
+ _execute: Callable
27
+ _id: str
28
+
29
+ if TYPE_CHECKING:
30
+
31
+ def find_element(self, by: str, value: Union[str, Dict, None] = None) -> Self: # type: ignore[override]
32
+ ...
33
+
34
+ def find_elements(self, by: str, value: Union[str, Dict, None] = None) -> List[Self]: # type: ignore[override]
35
+ ...
36
+
37
+ def get_attribute(self, name: str) -> Optional[Union[str, Dict]]: # type: ignore[override]
38
+ """Gets the given attribute or property of the element.
39
+
40
+ Override for Appium
41
+
42
+ This method will first try to return the value of a property with the
43
+ given name. If a property with that name doesn't exist, it returns the
44
+ value of the attribute with the same name. If there's no attribute with
45
+ that name, ``None`` is returned.
46
+
47
+ Values which are considered truthy, that is equals "true" or "false",
48
+ are returned as booleans. All other non-``None`` values are returned
49
+ as strings. For attributes or properties which do not exist, ``None``
50
+ is returned.
51
+
52
+ Args:
53
+ name: Name of the attribute/property to retrieve.
54
+
55
+ Usage:
56
+ # Check if the "active" CSS class is applied to an element.
57
+
58
+ is_active = "active" in target_element.get_attribute("class")
59
+
60
+ Returns:
61
+ The given attribute or property of the element
62
+ """
63
+
64
+ resp = self._execute(RemoteCommand.GET_ELEMENT_ATTRIBUTE, {'name': name})
65
+ attribute_value = resp.get('value')
66
+
67
+ if attribute_value is None:
68
+ return None
69
+
70
+ if isinstance(attribute_value, dict):
71
+ return attribute_value
72
+
73
+ # Convert to str along to the spec
74
+ if not isinstance(attribute_value, str):
75
+ attribute_value = str(attribute_value)
76
+
77
+ if name != 'value' and attribute_value.lower() in ('true', 'false'):
78
+ return attribute_value.lower()
79
+
80
+ return attribute_value
81
+
82
+ def is_displayed(self) -> bool:
83
+ """Whether the element is visible to a user.
84
+
85
+ Override for Appium
86
+ """
87
+ return self._execute(Command.IS_ELEMENT_DISPLAYED)['value']
88
+
89
+ def clear(self) -> Self: # type: ignore[override]
90
+ """Clears text.
91
+
92
+ Override for Appium
93
+
94
+ Returns:
95
+ `appium.webdriver.webelement.WebElement`
96
+ """
97
+
98
+ # NOTE: this method is overridden because the selenium client returned None instead of self.
99
+ # Appium python client would like to allow users to chain methods.
100
+ data = {'id': self.id}
101
+ self._execute(Command.CLEAR, data)
102
+ return self
103
+
104
+ @property
105
+ def location_in_view(self) -> Dict[str, int]:
106
+ """Gets the location of an element relative to the view.
107
+
108
+ Usage:
109
+ | location = element.location_in_view
110
+ | x = location['x']
111
+ | y = location['y']
112
+
113
+ Returns:
114
+ dict: The location of an element relative to the view
115
+ """
116
+ return self._execute(Command.LOCATION_IN_VIEW)['value']
117
+
118
+ # Override
119
+ def send_keys(self, *value: str) -> Self: # type: ignore[override]
120
+ """Simulates typing into the element.
121
+
122
+ Args:
123
+ value: A string for typing.
124
+
125
+ Returns:
126
+ `appium.webdriver.webelement.WebElement`
127
+ """
128
+ keys = keys_to_typing(value)
129
+ self._execute(RemoteCommand.SEND_KEYS_TO_ELEMENT, {'text': ''.join(keys), 'value': keys})
130
+ return self