How do i select value from dropdown of a hybrid app using appium? - spinner

I am relatively new to appium, and is actively involved in a poc. The requirement is to select a value from the drop down, however i am able to click the spinner element but anything below that is not getting recognized my uiautomator. as a result i am not able to select any values from the spinner element.
I am attaching the code block of the script and also the element tree snapshot.
//trying to click the dropdown list
try{
WebElement parentElement1 = driver.findElement(By.id("retProdOp0"));
WebElement childElement1 = parentElement1.findElement(By
.xpath("//android.view.View[#index='1']"));
childElement1.click();
driver.label("dropdown list 2nd element clicked");
}catch(Exception e){
driver.label("Failed to click dropdown list on prodexchg screen");
System.out.println(e.getMessage());
}
Snapshot1
Snapshot2
I want to select the values from the drop down of the spinner in Snapshot2. However i am not able to locate them in uiautomator. Looking for some help. Thanks in advance.

The below solution will help you. Let me know if it doesn't.
From your object properties it seems that you are in the Native context right now. So before selecting the drop down item please change to Web Context.
driver.Context = "WebContext"; Or
driver.Context = "CHROMIUM";
The name of your webcontext can be different
2. Now select the element just as you would do in web using selenium webdriver
Select dropdown = new Select(driver.findElement(By.id("mySelect")));
dropdown.selectByVisibleText("Text");
Now you can switch back to native context of your hybrid application if you want.
Note: To find the properties of webcontext you can fetch the source code or go to the web URL in your browser.

You are using incorrect XPath locator to select item in dropdown.
On your screenshot of uiautomator it is clear that before you click dropdown, items in it are not yet in DOM. So search in parent is not correct, as it does not contain elements at that moment.
Use appium-desktop instead of UIAutomator for elements inspection, it works better
Click dropdown to expand it
To click one of items do it like:
List<WebElement> items = driver.findElements(By.xpath("//android.view.View"));
items.get(0).click();
or
driver.findElement(By.xpath("(//android.view.View)[1])

Tried appium-desktop, but facing the same issues.
Appium-desktop screenshot 1
Appium-desktop screenshot 2
Please refer to the second screenshot. Thanks

If I understand correctly you have an application with a WebView showing a drop-down in HTML/JS.
I loaded https://www.w3schools.com/howto/howto_js_dropdown.asp as an example and generated a test using CulebraTester clicking on the button and then on "Link 3" item.
The generated script is
#! /usr/bin/env python
# -*- coding: utf-8 -*-
'''
Copyright (C) 2013-2018 Diego Torres Milano
Created on 2018-04-11 by CulebraTester
__ __ __ __
/ \ / \ / \ / \
____________________/ __\/ __\/ __\/ __\_____________________________
___________________/ /__/ /__/ /__/ /________________________________
| / \ / \ / \ / \ \___
|/ \_/ \_/ \_/ \ o \
\_____/--<
#author: Diego Torres Milano
#author: Jennifer E. Swofford (ascii art snake)
'''
import re
import sys
import os
import unittest
try:
sys.path.insert(0, os.path.join(os.environ['ANDROID_VIEW_CLIENT_HOME'], 'src'))
except:
pass
import pkg_resources
pkg_resources.require('androidviewclient>=12.4.0')
from com.dtmilano.android.viewclient import ViewClient, CulebraTestCase
from com.dtmilano.android.uiautomator.uiautomatorhelper import UiAutomatorHelper, UiScrollable, UiObject, UiObject2
TAG = 'CULEBRA'
class CulebraTests(CulebraTestCase):
#classmethod
def setUpClass(cls):
cls.kwargs1 = {'ignoreversioncheck': False, 'verbose': False, 'ignoresecuredevice': False}
cls.kwargs2 = {'forceviewserveruse': False, 'useuiautomatorhelper': True, 'ignoreuiautomatorkilled': True, 'autodump': False, 'startviewserver': True, 'compresseddump': True}
cls.options = {'start-activity': None, 'concertina': False, 'device-art': None, 'use-jar': False, 'multi-device': False, 'unit-test-class': True, 'save-screenshot': None, 'use-dictionary': False, 'glare': False, 'dictionary-keys-from': 'id', 'scale': 1, 'find-views-with-content-description': True, 'window': -1, 'orientation-locked': None, 'save-view-screenshots': None, 'find-views-by-id': True, 'log-actions': False, 'use-regexps': False, 'null-back-end': False, 'auto-regexps': None, 'do-not-verify-screen-dump': True, 'verbose-comments': False, 'gui': False, 'find-views-with-text': True, 'prepend-to-sys-path': False, 'install-apk': None, 'drop-shadow': False, 'output': None, 'unit-test-method': None, 'interactive': False}
cls.sleep = 5
def setUp(self):
super(CulebraTests, self).setUp()
def tearDown(self):
super(CulebraTests, self).tearDown()
def preconditions(self):
if not super(CulebraTests, self).preconditions():
return False
return True
def testSomething(self):
if not self.preconditions():
self.fail('Preconditions failed')
_s = CulebraTests.sleep
_v = CulebraTests.verbose
UiScrollable(self.vc.uiAutomatorHelper, uiSelector='clazz#android.webkit.WebView,index#0,parentIndex#0,package#com.android.chrome').getChildByText(uiSelector='text#Click Me', text="Click Me", allowScrollSearch=True).click()
UiScrollable(self.vc.uiAutomatorHelper, uiSelector='clazz#android.webkit.WebView,index#0,parentIndex#0,package#com.android.chrome').getChildByText(uiSelector='text#Link 3', text="Link 3", allowScrollSearch=True).click()
if __name__ == '__main__':
CulebraTests.main()
which seems to work correctly.
You can give it a try if you can't find other solution using appium.

Related

How can I get a Windows 11 Context Menu item to work with my PyQt6 application

I have a python script that I would like to run from the Windows 11/10 Right Click Context Menu in my documents folder
"C:\\Users\\me\\Documents\\PythonScripts\\main.py"
from PyQt6.QtWidgets import QApplication, QWidget
app = QApplication([])
window = QWidget()
window.setWindowTitle('My PyQt6 Application')
window.resize(400, 300)
window.move(100, 100)
window.show()
app.exec()
I created a python script that adds an item to the Right Click Context Menu in Windows 11 via registry.
But, The problem I am having is that when I try to click on "My Python Script" in the context menu, a pyqt6 window should pop up.
I tried running the exact command in terminal window
C:\Users\me\AppData\Local\Programs\Python\Python311\python.exe C:\Users\me\Documents\PythonScripts\main.py "%V"which works with no issues.
import winreg
menu_name = "My Python Script"
icon_path = "%SystemRoot%\\system32\\imageres.dll,3"
python = "C:\\Users\\me\\AppData\\Local\\Programs\\Python\\Python311\\python.exe"
command = f"{python} C:\\Users\\me\\Documents\\PythonScripts\\main.py \"%V\""
key = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT,
r"Directory\Background\shell",
0, winreg.KEY_WRITE)
menu_key = winreg.CreateKey(key, menu_name)
winreg.SetValueEx(menu_key, "Icon", 0, winreg.REG_SZ, icon_path)
winreg.SetValueEx(menu_key, "command", 0, winreg.REG_SZ, command)
winreg.CloseKey(menu_key)
winreg.CloseKey(key)
I found where the issue resided. I was adding the command key incorrectly. I needed to use command_key = winreg.CreateKey(menu_key, "command") for the command. Then add the value winreg.SetValueEx(command_key, "", 0, winreg.REG_SZ, command).
import winreg
# Name that will appear in the context menu
menu_name = "My Python Script"
# Path to the icon file
icon_path = "%SystemRoot%\\system32\\imageres.dll,3"
python = "C:\\Users\\me\\AppData\\Local\\Programs\\Python\\Python311\\python.exe"
# Path to the Python script and any command-line arguments
command = f"{python} C:\\Users\\me\\Documents\\PythonScripts\\main.py \"%V\""
# Open the registry key
key = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT,
r"Directory\Background\shell",
0, winreg.KEY_WRITE)
# Create a new key for our menu item
menu_key = winreg.CreateKey(key, menu_name)
command_key = winreg.CreateKey(menu_key, "command")
# Set the menu item's icon
winreg.SetValueEx(menu_key, "Icon", 0, winreg.REG_SZ, icon_path)
# Create a new key for our menu item
winreg.SetValueEx(command_key, "", 0, winreg.REG_SZ, command)
# Close the keys
winreg.CloseKey(menu_key)
winreg.CloseKey(command_key)
winreg.CloseKey(key)

st_aggrid nested grids don't display changed data after DF is altered

Using ...
streamlit==1.9.0
streamlit-aggrid==0.2.3.post2
Python 3
I'm attempting to use nested AgGrid Grids as described here
The end goal is to show a list of instruments and, (only) when checked, the subgrid below the instrument updates with data about the instrument.
The problem is; the updated Grid (updated after selecting a checkbox, which alters the underlying DataFrame) does not actually show the new DF data (it still shows the old data.)
DETAILS:
When I first load the page, it creates a DataFrame st.session_state["instruments_and_injections_df"] correctly using build_initial_instruments_df()
The Grid appears correctly, with the nested data, and checkboxes next to each line in both the outer grid, and the nested grid.
Selecting a checkbox does trigger _get_injection(instrument_name) and _update_instruments_and_injections_df(...)
These functions have been validated as working (it does query the database and update the DF with the new data.) If I dump the updated DF st.session_state["instruments_and_injections_df"] we can see the JSON data has been correctly added to the instrumentData column on the correct row.
After selecting a checkbox, however, the data in the main grid does not change (still shows the "instrumentData": {"sample_name":"test"}, not the new data)
Selecting a second checkbox, also queries the database, and updates the Df - but then the grid is completely goofy.
I have tried changing the update_mode in AgGrid() call to "MANUAL", "VALUE_CHANGED", "SELECTION_CHANGED", and "MODEL_CHANGED". The behavior does not change.
def build_initial_instruments_df():
""" This works to build initial grid. Grid behaves correctly at this point"""
st.session_state["raw_json"] = json.dumps([
{ "instrument_name":"Inst1", "instrumentData": {"sample_name":"test"},
{ "instrument_name":"Inst2", "instrumentData": {"sample_name":"test"}
])
st.session_state["instruments_and_injections_df"] = pd.read_json(st.session_state["raw_json"])
st.session_state["instruments_and_injections_df"]["instrumentData"] = st.session_state["instruments_and_injections_df"]["instrumentData"].apply(lambda x: pd.json_normalize(x))
def _update_instruments_and_injections_df(selected = [], always_update = False):
""" This works to query database, and update the field "instrumentData" with JSON.
Verified by dumping updated st.session_state["instruments_and_injections_df"] to screen which shows the updated JSON cell"""
_instruments = st.session_state["instruments_and_injections_df"]["instrument_name"].to_list()
for _instrument in _instruments:
if _instrument in selected:
_injection_json = _get_injection(_instrument)
_instrument_index = st.session_state["instruments_and_injections_df"].index[st.session_state["instruments_and_injections_df"]['instrument_name']==_instrument].tolist()[0]
st.session_state["instruments_and_injections_df"].at[_instrument_index, "instrumentData"] = _injection_json
def _get_injection(instrument_name):
""" This works to obtain the data from the DB and convert it to JSON"""
with st.spinner("Displaying results..."):
_sql = "SELECT sample_name, sample_orderno, sample_amount FROM injections WHERE instrument_name = '{}';".format(instrument_name)
injection_df = pd.read_sql(_sql, st.session_state["conn"])
injection_df_json = injection_df.to_json(orient = "records")
injection_df_json = json.loads(injection_df_json)
return injection_df_json
#===============================================================================
# MAIN
#===============================================================================
try:
st.session_state["instruments_and_injections_df"] # Will error if has never been loaded
except (KeyError, NameError):
build_initial_instruments_df()
gridOptions = {
# enable Master / Detail
"masterDetail": True,
"rowSelection": "multiple",
"pagination": st.session_state["enable_pagination"],
"paginationAutoPageSize": st.session_state["paginationAutoSize"],
"groupSelectsChildren":st.session_state["groupSelectsChildren"],
"groupSelectsFiltered":st.session_state["groupSelectsFiltered"],
# the first Column is configured to use agGroupCellRenderer
"columnDefs": [
{
"field": "instrument_name",
"cellRenderer": "agGroupCellRenderer",
"checkboxSelection": True,
},
],
"defaultColDef": {
# "flex": 1,
},
# provide Detail Cell Renderer Params
"detailCellRendererParams": {
# provide the Grid Options to use on the Detail Grid
"detailGridOptions": {
"rowSelection": "multiple",
"suppressRowClickSelection": True,
"enableRangeSelection": True,
"pagination": st.session_state["enable_pagination"],
"paginationAutoPageSize": st.session_state["paginationAutoSize"],
"groupSelectsChildren":st.session_state["groupSelectsChildren"],
"groupSelectsFiltered":st.session_state["groupSelectsFiltered"],
"columnDefs": [
{"field": "sample_name", "checkboxSelection": True},
],
"defaultColDef": {
"sortable": True,
# "flex": 1, # This sets the columns to fit to the window (bad)
},
},
"getDetailRowData": JsCode(
"""function (params) {
console.log(params);
params.successCallback(JSON.parse(params.data.instrumentData));
}"""
).js_code,
},
}
st.session_state["instruments_grid_response"] = AgGrid(
st.session_state["instruments_and_injections_df"],
gridOptions=gridOptions,
height=st.session_state["grid_height"],
allow_unsafe_jscode=True,
enable_enterprise_modules=True,
# update_mode=GridUpdateMode.SELECTION_CHANGED,
data_return_mode=st.session_state["return_mode_value"],
update_mode=st.session_state["update_mode_value"],
)
#===============================================================================
# Discover any data selected from grid
#===============================================================================
if st.session_state["instruments_grid_response"]['selected_rows'] != []:
_selected_instruments = pd.DataFrame(st.session_state["instruments_grid_response"]['selected_rows'])["instrument_name"].to_list()
_update_instruments_and_injections_df(selected = _selected_instruments)
else:
st.write("No instruments selected")

Python3 YoutubeDL shows output even with quiet option

Say I have a script, such as follows
import youtube_dl
options = {
"quiet": True,
"skip_download": True,
"forcetitle": True,
"forceurl": True,
"format": "bestaudio[ext=m4a]/best[ext=mp4]/best[ext=webm]/best"}
with youtube_dl.YoutubeDL(options) as ydl:
metadata = ydl.extract_info(f"ytsearch1: Never gonna give you up Rick Astley")
title = metadata["entries"][0]["title"]
url = metadata["entries"][0]["formats"][0]["url"]
watch_id = metadata["entries"][0]["display_id"]
extension = metadata["entries"][0]["ext"]
print("\n")
print("Results")
print(f"title: {title}")
print(f"url: {url}")
# do other stuff
The output of this shows the following
Rick Astley - Never Gonna Give You Up (Video)
https://r2---sn-nqojvhh-4nql.googlevideo.com/videoplayback?expire=1615178090&ei=ClVFYLXAB_Wmir4P4OmvsAc&ip=142.0.14.91&id=o-AI7PyUbW58VrMxM9IFNqTlw2BbD8mwMoV53-wSMcs_mb&itag=140&source=youtube&requiressl=yes&mh=7c&mm=31%2C29&mn=sn-nqojvhh-4nql%2Csn-qxoedn7z&ms=au%2Crdu&mv=m&mvi=2&pcm2cms=yes&pl=20&gcr=us&initcwndbps=1832500&vprv=1&mime=audio%2Fmp4&ns=1H8LUy6hbPlWLg1PHgmu0xUF&gir=yes&clen=3433514&dur=212.091&lmt=1608803698687376&mt=1615156117&fvip=4&keepalive=yes&fexp=24001374%2C24007246&c=WEB&txp=5411222&n=Bh0GIV8cVRIBUneuBU&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cgcr%2Cvprv%2Cmime%2Cns%2Cgir%2Cclen%2Cdur%2Clmt&lsparams=mh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpcm2cms%2Cpl%2Cinitcwndbps&lsig=AG3C_xAwRQIgYpoaNgPdxLh4inaXa9CrRiDglT_DKUS3uEn4Qku-uVwCIQD6nELqExsGMNZQoRqEpnU669WCHXqCfM35K-TfQtrqHw%3D%3D&sig=AOq0QJ8wRgIhAOtlhCnk7UdstxOQBiTZ29aK4EYyjKwXcf4hmGwxiBBOAiEA0bTm2mBy5Z41KKdYXCgWZbZ0S-S8jUaxyA4JXwYjG6g=
Results
title: Rick Astley - Never Gonna Give You Up (Video)
url: https://r2---sn-nqojvhh-4nql.googlevideo.com/videoplayback?expire=1615178090&ei=ClVFYLXAB_Wmir4P4OmvsAc&ip=142.0.14.91&id=o-AI7PyUbW58VrMxM9IFNqTlw2BbD8mwMoV53-wSMcs_mb&itag=249&source=youtube&requiressl=yes&mh=7c&mm=31%2C29&mn=sn-nqojvhh-4nql%2Csn-qxoedn7z&ms=au%2Crdu&mv=m&mvi=2&pcm2cms=yes&pl=20&gcr=us&initcwndbps=1832500&vprv=1&mime=audio%2Fwebm&ns=1H8LUy6hbPlWLg1PHgmu0xUF&gir=yes&clen=1232526&dur=212.061&lmt=1578935068173432&mt=1615156117&fvip=4&keepalive=yes&fexp=24001374%2C24007246&c=WEB&txp=5531432&n=Bh0GIV8cVRIBUneuBU&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cgcr%2Cvprv%2Cmime%2Cns%2Cgir%2Cclen%2Cdur%2Clmt&lsparams=mh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpcm2cms%2Cpl%2Cinitcwndbps&lsig=AG3C_xAwRAIgbLq604Q9G-SMe7ukgbbvLk3Fnml4eSYmuTxC37fCNUoCIHWnPYA70q5nZiDY0OgDbZHqTFIkjtLZBPJqV4i5bFXa&sig=AOq0QJ8wRQIgP1Nj9IqPpv4qVbPGf6edCJMipGq3pralKXL7ypBANGICIQDAjnJ8QTio0kl11edjg4Pk1ZzLfm-YOE2hJFPnQiUnbQ==
By passing "quiet": True into ydl.extract_info, I thought I could supress all output. While this does suppress most output, I would like to not show any at all.
How can I suppress all output from ydl.extract_info?
Thanks for any help!
This is a small makeshift just import os and in the last put a line that states os.sys(“cls”) or os.system(“cls”)

How to set active downloads in session with libtorrent/Python

I'm trying to made a script to download files in python. So far so good with the default settings for the session. but when i'm trying to set 'active downloads' it just doesn't download. I'm sure i'm doing it wrong but i dont know where. The default for active downloads in libtorrent is 3. How am I suposse to change session settings? I'm really newbie in python.
Heres the code:
import libtorrent as lt
sett = lt.session_settings()
sett = {'allow_multiple_connections_per_ip': True,
'active_downloads': -1,
'active_checking': -1,
'active_seeds': 7,
'active_limit': -1}
ses = lt.session()
ses.listen_on(6881, 6891)
ses.set_settings(sett)
downloads = []
Here's where i suposse to put the torrent. The documentation says that I have to set auto_managed to false in order to change the active downloads.
source = 'downloads/torrents/'
params = {
"save_path": "/download/",
"ti": lt.torrent_info(list(source.keys())[0]),
'auto_managed': False,
}
downloads.append(ses.add_torrent(params))
and here the code is executed.
import time
from IPython.display import display
import ipywidgets as widgets
state_str = [
"queued",
"checking",
"downloading metadata",
"downloading",
"finished",
"seeding",
"allocating",
"checking fastresume",
]
layout = widgets.Layout(width="auto")
style = {"description_width": "initial"}
download_bars = [
widgets.FloatSlider(
step=0.01, disabled=True, layout=layout, style=style
)
for _ in downloads
]
display(*download_bars)
while downloads:
next_shift = 0
for index, download in enumerate(downloads[:]):
bar = download_bars[index + next_shift]
if not download.is_seed():
s = download.status()
bar.description = " ".join(
[
download.name(),
str(s.download_rate / 1000),
"kB/s down,",
str(s.upload_rate / 1000),
"kB/s Up,",
str(s.num_peers),
"Peers",
state_str[s.state],
]
)
bar.value = s.progress * 100
else:
next_shift -= 1
ses.remove_torrent(download)
downloads.remove(download)
bar.close()
download_bars.remove(bar)
print(download.name(), "done")
time.sleep(5)
It was working great Before I tried to change settings in the first part and changing auto_managed.
So i supposse maybe that's not the way. I've readt like all the documentation but I dont know how to apply it. can someone help me?
I'm sorry for my bad englisg
the torrent limit settings, as the documentation states, only apply to torrents that are "auto managed". setting auto_managed to false for a torrent, is a way to opt-out of the automatic start/stop/queue logic built-into libtorrent. By default it's true and by default libtorrent will limit the number of simultaneous downloading torrents.
So here's how the session should beggin in order to download multiple torrents. Set the session, set the settings and aply those settings to sessions.
ses = lt.session()
ses.listen_on(6881, 6891)
sett = lt.session_settings()
sett = {'allow_multiple_connections_per_ip': True,
'dont_count_slow_torrents': True,
'active_downloads': -1,
'active_seeds': 7,
'active_checking': 3,}
ses.set_settings(sett)
downloads = []
And yeah. auto_managed didn't need to be set as False. Thanks for the help-.

pyside qdialog box or qaction icon is closing app

The issue is a combination of setting an icon on the action in the toolbar (or qpushbutton) and showing a qmessagebox when triggered. If I remove the icon, the message box displays. And if I remove the message box but keep the icon, the app stays open. The other odd thing is, if I add the icon to the push button but not the action, and click on the action, it still closes the app. The doubly odd thing is if I add main.qpush_button_clicked before qapplication.exec_(), the message box is displayed. However, the next time I click on either, it closes the app.
I have looked at multiple posts and some of the ideas were to use setQuitOnLastWindowClosed, but that did not fix the issue. I also implemented event to see what was happening. When I click on either of the items, it triggers a ChildAdded event, then closes.
Also, this only does not work when I use cx_Freeze on a Mac. I have not tried on Win. It works properly when run using Eclipse or from CLI.
Does anyone have any ideas on what might be causing this, or how to fix it besides not using icons.
The icon I used is from Android icon pack.
I can add the crash log if you need it.
class Main(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.qicon = QIcon('../ic_add_black_24dp_1x.png')
self.tool_bar = self.addToolBar('main')
qaction = QAction(self)
self.tool_bar.addAction(qaction)
qaction.setText('add')
qaction.setIcon(self.qicon)
qaction.triggered.connect(self.qpush_button_clicked)
qpush_button = QPushButton('add')
self.setCentralWidget(qpush_button)
qpush_button.setIcon(self.qicon)
qpush_button.clicked.connect(self.qpush_button_clicked)
def qpush_button_clicked(self, *args, **kwargs):
QMessageBox.critical(self, 'test', 'testing')
if __name__ == '__main__':
qapplication = QApplication(sys.argv)
main = Main()
main.show()
main.raise_()
qapplication.exec_()
And here is the setup file
name = 'dialog'
version = '0.1'
description = 'description'
packages = ('os',)
excludes = ('tkinter',)
include_files = ('ic_add_black_24dp_1x.png',)
build_exe = dict(packages=packages,
excludes=excludes,
include_files=include_files)
options = dict(build_exe=build_exe)
base = 'Win32GUI' if sys.platform == 'win32' else None
script = 'dialog.py'
executables = (Executable(script, base=base),)
setup(name=name,
version=version,
description=description,
options=options,
executables=executables)
PySide Version : 1.2.2
PySide Component: : (1, 2, 2, 'final', 0)
PySide Compiled Qt : 4.8.7
PySide Qt Component: (4, 8, 7)
Running Qt Version : 4.8.7

Resources