function for switching frames in python, selenium - python

I'm looking for a function that makes it easier to switch between two frames. Right now, every time I need to switch between frames, I'm doing this by the following code:
driver.switch_to.frame(driver.find_element_by_css_selector("frame[name='nav']"))
driver.switch_to.frame(driver.find_element_by_css_selector("frame[name='content']"))
My goal is to get a function that takes an argument just to change nav or content since the rest is basically the same.
What I've already tried is:
def frame_switch(content_or_nav):
x = str(frame[name=str(content_or_nav)] #"frame[name='content_or_nav']"
driver.switch_to.frame(driver.find_element_by_css_selector(x))
But it gives me an error
x = str(frame[name=str(content_or_nav)]
^
SyntaxError: invalid syntax

The way this is written, it's trying to parse CSS code as Python code. You don't want that.
This function is suitable:
def frame_switch(css_selector):
driver.switch_to.frame(driver.find_element_by_css_selector(css_selector))
If you are just trying to switch to the frame based on the name attribute, then you can use this:
def frame_switch(name):
driver.switch_to.frame(driver.find_element_by_name(name))
To switch back to the main window, you can use
driver.switch_to.default_content()

Related

Python Jupyter/Notebook: How to display a variable as text on a cell without copy/paste

It happens to me that when reading/reviewing the code, I becomes easier if I can see the 'look' of the variable a function is processing.
For that, I'd like to display a 'static' version of an instance of that variable (as a visual aid).
That variable may not be there on another run of the notebook, that's why it has to be text, not output.
This is also useful when creating documentation within the notebook.
With this little function
#----------------------------------
def vdisplay(var):
"""Converts the var to a pretty string and inserts
it on a new cell just below the present one.
Then you have to change that 'next cell' type to Markdown and execute it.
"""
# To print the var nicely.
from pprint import pformat as pf
string_to_insert=f"""
This is how it looks like:
```
{pf(var)}
```
"""
# Create a code cell and insert a string in it
get_ipython().set_next_input(string_to_insert)
return
#----------------------------------
You can do this
# This is the data we want to show
x={i:str(i)*i for i in range(10)}
# Show it!
vdisplay(x)
Visually:
I use the mouse intentionally so you can see the steps. Using keyboard shortcuts is much quicker.
Story: I explored several venues. The last one was a combination of
%store var f.txt and %load f.txt but that involved some manual
work. The evolution of that method is the one above.

Top 5 moves using chess.engine.SimpleEngine

I'm having trouble with the engine encapsulation of python-chess, I would like to use the Stockfish function top = stockfish.get_top_moves(5) but it seems like there is no way to do it using chess.engine.simpleEngine, do you have any advices?
I already tried getting all the result and then keeping just the top 5 move of the last evaluation using this piece of code:
self.engine.analysis(self.board, chess.engine.Limit(depth=18), multipv=5, root_moves = move_actions)
but it's tricky since the function is asyncronous and I'm integrating with other function that are not changeable I cannot make it asynchronous.
I'm going crazy trying to make it work, thanks to everybody.
The async object returned by that function is empty at first; you can wait until it is done by calling its .wait() method. Instead, if you don't want the async parts of engine.analysis, you can call engine.analyse which blocks until done and returns the result more directly. Both functions work to get the top 5 moves as you requested. Here is an example script:
import chess
import chess.engine
stockfish = chess.engine.SimpleEngine.popen_uci("<file path to engine>")
# Using engine.analysis
analysis_result = stockfish.analysis(chess.Board(), limit=chess.engine.Limit(depth=18), multipv=5)
analysis_result.wait() # This is the missing step
analysed_variations = analysis_result.multipv
# Or instead using engine.analyse
analysed_variations = stockfish.analyse(chess.Board(), limit=chess.engine.Limit(depth=18), multipv=5)
# Either way you now have a dict of results, with moves under "pv"
top_five_moves = [variation["pv"][0] for variation in analysed_variations]

Unsure how to manage my variables/data using tkinter and openpyxl: fstring issue

I am creating an app on a Raspberry Pi (if its at all relevent) which needs to access data from specific cells from a spreadsheet in order to display the settings as button text. There are multiple 'modes', settings and buttons. The button that may need to update varies and I have specified this with a Boolean variable. The text that needs to be displayed on the specified button can also vary by time and worksheet. I was able to create a variable to hold the time and then using a nested f-string was able to display data from the correct cell:
current_time = datetime.now().strftime('%H')
cell_number = int(current_time)+2
bool = True
def update_button():
if bool == True:
button.config(text=f"{ws_sheet[f'A{cell_number}'].value}")
else:
button1.config(text=f"{ws_sheet[f'B{cell_number}'].value}")
This worked fine but I also need to alter the sheet now as well based on a different variable. I tried this but it produces an fstring syntax error.
current_time = datetime.now().strftime('%H')
cell_number = int(current_time)+2
bool = True
worksheet = some_worksheet
def update_button():
if bool == True:
button.config(text=f"{{worksheet}[f'A{cell_number}'].value}")
else:
button1.config(text=f"{{worksheet}[f'B{cell_number}'].value}")
The syntax error produced:
button.config(text=f"{{worksheet}[f'A{cell_number}'].value}")
^
SyntaxError: f-string: single '}' is not allowed
This seems like a counter-intuitive error to me as well.
I am open to the fact I am probably going about this totally the wrong way and for my own ego I feel compelled to mention that I haven't been doing this very long. I know I could achieve what I want with a ton of if/else statements but I was hoping to do something a bit more elegant.
Any help is greatly appreciated.
You can pass work sheet when calling your function.
def update_button(ws_sheet):
if bool == True:
button.config(text=f"{ws_sheet[f'A{cell_number}'].value}"
else:
button1.config(text=f"{ws_sheet[f'B{cell_number}'].value}"

return Point(int(firstArg), int(secondArg)) # firstArg and secondArg are just x and y number values

I am trying to have pyautogui move the mouse whenever it detects a color but for some reason whenever I try running it keeps on prompting this error, I have run this code before and it worked perfectly fine. pls help
Code
Output
You are getting that error because "locateAllOnScreen" returns a "generator" which can be looped through which contains all instances of the image. You may be looking for "locateOnScreen".
Here are some example on how to use the two different functions:
# Will loop through all instances of 'img.png'
for pos in pyautogui.locateAllOnScreen('img.png')
# Code here...
# Will find one instance and return the position
pyautogui.locateOnScreen('img.png')
This link has some good information on the different methods

Cursor Grabbing while using drag_and_drop_by_offset (Python/Selenium)

I need to drag this scale and when I run this code:
HandScale = browser.find_element_by_xpath('//*[#data-xform="scale"]')
GridLineX = browser.find_element_by_class_name('outlined')
bottomLeft = browser.find_element_by_class_name('bottomLeft')
print GridLineX.size
action_chains = ActionChains(browser)
action_chains.drag_and_drop_by_offset(HandScale, 30, 30).click_and_hold(HandScale).perform()
It still has the grabbing effect Shown here:
Is there anyway to remove this effect before running the other part of my script?
I think you just need the release() function in action_chains which is designed to do exactly that. The line to add at the end of your current file would be:
action_chains.release().perform()
Edit after feedback that this didn't work: what if you do the release() inside your existing action_chains, and simply add a pause() after your click_and_hold(HandScale) so that the click is actually held and not immediately released. Finally, since you use a webelement argument in click_and_hold(HandScale) I would try to release on that element with release(HandScale). So, your action_chains might do what you want if you use the following:
action_chains.drag_and_drop_by_offset(HandScale, 30, 30).click_and_hold(HandScale).pause(5).release(HandScale).perform()
If THAT doesn't work, the WebDriver API has a method called reset_actions() that, according to the documentation "Clears actions that are already stored locally and on the remote end". I would add this under your current action_chains, but you could try inserting it before perform() in your current code. The line to add would just look like this:
action_chains.reset_actions().perform()
If none of this works for you, you could try
driver.execute_script("arguments[0].removeAttribute('cursor')", element")
If you need I think can help you figure out what to execute if none of the above works.

Categories