How to keep browser opening by the end of the code running with playwright-python? - playwright-python

I want to use playwright-python to fill some forms automatically. And then double check the filling before submit. But it always close the browser by the end of the code running. Even if I used the handleSIGHUP=False, handleSIGINT=False, handleSIGTERM=False launch arguments, and didn't use any page.close() or browser.close() in my code, it still close the browser after the code finished.
Does anyone know how to do it?

The browser is started by the python script, so it will end, when the script ends.
So you need to keep the script alive.
For the async part it is a bit tricky.
I assume you have same kind of:
asyncio.get_event_loop().run_until_complete(main())
so in the async main routine you need to keep the async loop running:
e.g. waiting for the keyboard:
import asyncio
from playwright.async_api import async_playwright
from playwright.async_api import Page
async with async_playwright() as p:
async def main(run_forever: bool):
browser = await p.__getattribute__(C.BROWSER.browser).launch(headless=False, timeout=10000)
page = await browser.new_page()
if run_forever:
print('Press CTRL-D to stop')
reader = asyncio.StreamReader()
pipe = sys.stdin
loop = asyncio.get_event_loop()
await loop.connect_read_pipe(lambda: asyncio.StreamReaderProtocol(reader), pipe)
async for line in reader:
print(f'Got: {line.decode()!r}')
else:
browser.close()

get see worked link
Context:
Playwright Version: 1.16
Operating System: Windows
Node.js version: 14.18.1
Browser: All
Overview
There are multiple ways to turn on the Inspector, as explained in https://playwright.dev/docs/inspector
As per docs, when we set "PWDEBUG", it also disables the timeout, by setting it to 0. This is a good idea, as it allows the user to click around the inspector without a time limit.
However, this is not the case with page.pause(). This option also opens the inspector, but the timeout is not set to 0, thus the inspector will force exit after 30s with e.g.
Slow test: tests\my_test.test.js (30s)
The same behavior is mentioned in a Feature request here: #10132
And I believe it should be fixed to match the default behaviour of other options, at least for consistency reasons. For example, in Java binding, page.pause() does not require timeOut to be explicitly disabled.

Related

DiscordPy clear hybrid command - Only works properly with prefix, not as slash command

Good day folks. I have the following clear command:
#clear command
#commands.hybrid_command(name = "clear", with_app_command = True, description = "Need to clear?",ephemeral = True)
#commands.has_permissions(manage_messages=True)
async def clear(self,ctx: commands.Context, limit:int = None):
if limit == None:
limit = 5
await ctx.channel.purge(limit=limit+1)
#await ctx.reply(f'Successfully cleared {limit} messages.')
The command works properly deleting messages. However when I call it as a slash command, it will clear the messages but return a "The application did not respond" message.
I've tried using ctx.reply and ctx.send on the commented line but none of them do the trick.
I also get a "In message_reference: Unknown message".
Any help is appreciated.
"The application did not respond" message.
For application commands, you have to respond within 3 seconds. As you are clearing messages beforehand (which is an API call that may take some time to complete) you're probably exceeding this deadline.
If what you're doing is slow, you must first defer and then followup afterwards. The library can handle this automatically for you in hybrid commands using Context.typing().

Timeout with EvaluateExpressionAsync<>?

I'm using Puppeteer sharp to render reports and part of that is executing user provided javascript to prepare the data for the report.
I use AddScriptTagAsync to add the scripts to the page then call the user provided script before rendering the report.
If the user provided javascript has an issue that causes an infinite loop (for example) then my call to EvaluateExpressionAsync could await forever:
await page.EvaluateExpressionAsync<dynamic>($"Prepare({DataObject});")
I can't pass a cancellation token to EvaluateExpressionAsync so I can't control it and there appear to be no timeouts available for this method.
I would like to limit it to a controllable number of seconds and then have it timeout.
Any suggestions on how to do this would be very much appreciated.
You would use WaitForExpressionAsync.
The idea of this method is executing the expression over a period of time until the result is truthy.
But if you make sure that your expression will always return a truthy value, WaitForExpressionAsync will timeout using the timeout you pass as an option.

Gathering coin volumes - Is my code running asynchronously?

I'm fairly new to programming in python, I've been programming for about half a year. I've decided to try to build a functional trading bot. While trying to code this bot, I stumbled upon the asyncio module. I would really like to understand the module better but it's hard finding any simple tutorials or documentation about asyncio.
For my script I'm gathering per coin the volume. This works perfectly, but it takes a really long time to gather all the volumes. I would like to ask if my script is running synchronously, and if so how do I fix this? I'm using an API wrapper to communicate with the Binance Exchange.
import binance
import asyncio
import time
s = time.time()
names = [name for name in binance.ticker_prices()] #Gathering all the coin names
loop = asyncio.get_event_loop()
async def get_volume(name):
async def get_data():
return binance.ticker_24hr(name) #Returns per coin a dict of the data of the last 24hr
data = await get_data()
return (name, data['volume'])
tasks = [asyncio.ensure_future(get_volume(name)) for name in names]
results = loop.run_until_complete(asyncio.gather(*tasks))
print('Total time:', time.time() - s)
Since binance.ticker_24hr does not look like it's a coroutine, it is almost certainly blocking the event loop and therefore preventing asyncio.gather to do its job. As a quick fix, you can use run_in_executor to run the blocking function in a separate thread:
async def get_volume(name):
loop = asyncio.get_event_loop()
data = await loop.run_in_executor(None, binance.ticker_24hr, name)
return name, data['volume']
This will work just fine for a reasonable number of parallel tasks. The downside is that it uses threads, so it might not scale to a huge number of parallel requests (or it would require unnecessary waiting). The correct solution in the long run is to use a library that natively supports asyncio.
Maarten firstly you are calling get_ticker for every symbol which means you're making many unnecessary requests. If you call it without a symbol value, you get all tickers in one request. This removes any loops or async as well if you aren't performing other tasks. It looks like the binance library you're using doesn't support this. You can use python-binance to do it
return client.get_ticker()
That said I've been testing an asyncio version of python-binance. It's currently in a feature branch now if you want to try it.
pip install git+https://github.com/sammchardy/python-binance#feature/asyncio
Include the asyncio version of the client and initialise the client
from binance.client_async import AsyncClient as Client
client = Client("<api_key>", "<api_secret>")
Then you can await the calls to get the ticker for a particular symbol
return await client.get_ticker(symbol=name)
Or for all symbol tickers don't pass the symbol parameter
return await client.get_ticker()
Hope that helps

XMaskEvent not returning

I am following this tutorial here: http://www.sbin.org/doc/Xlib/chapt_16.html
Here is the image of the tutorial:
Here is my code: (it is in another thread from which I called XInitThreads - I know using threads and X is bad, I know I should be on the main thread, but just wondering if possible)
var ev = XEvent();
var rez_XMaskEvent = XMaskEvent(cachedXOpenDisplay(), ButtonPressMask | ButtonReleaseMask, ev.address());
console.log('rez_XMaskEvent:', rez_XMaskEvent);
console.log('ev:', ev);
ButtonPressMask is 4
ButtonReleaseMask is 8
So XMaskEvent is blocking, but whenever I press my mouse button it is not catching it. Shouldn't it unblock and get to the console.log line?
Do I need to run an event loop somehow in this thread?
Thanks
I'm not 100% sure here but I feel this could be your problem:
You probably can't do this from JavaScript without some extra precautions. JavaScript in the browser is single-threaded. That means you're holding a lock and no other JavaScript can run. Your problem is a) you're using threads and b) "If the event you requested is not in the queue, XMaskEvent flushes the output buffer and blocks until one is received." (see the man page)
That means XMaskEvent blocks since the button hasn't been pressed, yet. And your browser can't execute JavaScript anymore. If there is an event in the queue which would trigger some JavaScript, the browser will lock up.

How can I implement wait_for_page_to_load in Selenium 2?

I am new to automated web testing and I am currently migrating from an old Selenium RC implementation to Selenium 2 in Ruby. Is there a way to halt the execution of commands until the page gets loaded, similar to "wait_for_page_to_load" in Selenium RC?
I fixed a lot of issues I was having in that department adding this line after starting my driver
driver.manage.timeouts.implicit_wait = 20
This basically makes every failed driver call you make retry for maximum 20 seconds before throwing an exception, which is usually enough time for your AJAX to finish.
Try using Javascript to inform you!
I created a couple methods that checks via our javascript libraries and waits to see if the page has finished loading the DOM and that all ajax requests are complete. Here's a sample snippet. The javascript you will need to use is just going to depend on your library.
Selenium::WebDriver::Wait.new(:timeout => 30).until { #driver.execute_script("[use javascript to return true once loaded, false if not]"}
I then wrapped these methods in a clickAndWait method that clicks the element and calls the waitForDomLoad and waitForAjaxComplete. Just for good measure, the very next command after a clickAndWait is usually a waitForVisble element command to ensure that we are on the right page.
# Click element and wait for page elements, ajax to complete, and then run whatever else
def clickElementAndWait(type, selector)
#url = #driver.current_url
clickElement(type, selector)
# If the page changed to a different URL, wait for DOM to complete loading
if #driver.current_url != #url
waitForDomLoad
end
waitForAjaxComplete
if block_given?
yield
end
end
If you are using capybara, whenever you are testing for page.should have_content("foo"), capybara will not fail instantly if the page doesn't have the content (yet) but will wait for a while to see if an ajax call will change that.
So basically: after you click, you want to check right away for have_content("some content that is a consequence of that click").

Resources