Debugging Selenium script with EventFiringWebDriver in PyCharm, cause exception to be logged:
'WebDriver' object has no attribute '__len__'
It slows down IDE but do not break (stop) the script.
Here is full code:
from selenium import webdriver
from selenium.webdriver.support.event_firing_webdriver import EventFiringWebDriver
from selenium.webdriver.support.events import AbstractEventListener
class ScreenshotListener(AbstractEventListener):
def on_exception(self, exception, driver):
print(exception)
driver = webdriver.Chrome('chromedriver.exe')
ef_driver = EventFiringWebDriver(driver, ScreenshotListener())
ef_driver.get('https://google.com/')
title = ef_driver.title
driver.quit()
assert "Google", title
When I run attached script in standard mode everything is OK.
But running with PyCharm Debug (here is output from beginning of Debug console):
C:\Pro\selenium-debug\venv\Scripts\python.exe "C:\Program Files\JetBrains\PyCharm Community Edition 2020.1.1\plugins\python-ce\helpers\pydev\pydevd.py" --multiproc --qt-support=auto --client 127.0.0.1 --port 59668 --file C:/Pro/selenium-debug/simple_test.py
I get those exceptions (every time when I call ef_driver):
'WebDriver' object has no attribute '__len__'
'WebDriver' object has no attribute '__len__'
It not stopping the script, it just cause debugger to be slow (it updates driver and focus is set to the browser).
Any idea why it is triggered and logged?
Bonus: Running debugging in console with pdb is OK, so this looks like strictly PyCharm Debug connected thing
Looks like PyCharm debug checks if an object has a __len__ attribute:
elif hasattr(v, "__len__")
and the object WebDriver has no __len__.
A solution could be (from the link below) to warp with try\catch:
try:
if is_numeric_container(type_qualifier, typeName, v):
xml_shape = ' shape="%s"' % make_valid_xml_value(str(v.shape))
elif hasattr(v, "__len__") and not is_string(v):
try:
xml_shape = ' shape="%s"' % make_valid_xml_value("%s" % str(len(v)))
except:
pass
except KeyError:
pass
Please check this track:
https://youtrack.jetbrains.com/issue/PY-39954
Related
I want to control whether my WebDriver quit but I can't find a method for that. (It seems that in Java there's a way to do it)
from selenium import webdriver
driver = webdriver.Firefox()
driver.quit()
driver # <selenium.webdriver.firefox.webdriver.WebDriver object at 0x108424850>
driver is None # False
I also explored the attributes of WebDriver but I can't locate any specific method to get information on the driver status. Also checking the session id:
driver.session_id # u'7c171019-b24d-5a4d-84ef-9612856af71b'
If you would explore the source code of the python-selenium driver, you would see what the quit() method of the firefox driver is doing:
def quit(self):
"""Quits the driver and close every associated window."""
try:
RemoteWebDriver.quit(self)
except (http_client.BadStatusLine, socket.error):
# Happens if Firefox shutsdown before we've read the response from
# the socket.
pass
self.binary.kill()
try:
shutil.rmtree(self.profile.path)
if self.profile.tempfolder is not None:
shutil.rmtree(self.profile.tempfolder)
except Exception as e:
print(str(e))
There are things you can rely on here: checking for the profile.path to exist or checking the binary.process status. It could work, but you can also see that there are only "external calls" and there is nothing changing on the python-side that would help you indicate that quit() was called.
In other words, you need to make an external call to check the status:
>>> from selenium.webdriver.remote.command import Command
>>> driver.execute(Command.STATUS)
{u'status': 0, u'name': u'getStatus', u'value': {u'os': {u'version': u'unknown', u'arch': u'x86_64', u'name': u'Darwin'}, u'build': {u'time': u'unknown', u'version': u'unknown', u'revision': u'unknown'}}}
>>> driver.quit()
>>> driver.execute(Command.STATUS)
Traceback (most recent call last):
...
socket.error: [Errno 61] Connection refused
You can put it under the try/except and make a reusable function:
import httplib
import socket
from selenium.webdriver.remote.command import Command
def get_status(driver):
try:
driver.execute(Command.STATUS)
return "Alive"
except (socket.error, httplib.CannotSendRequest):
return "Dead"
Usage:
>>> driver = webdriver.Firefox()
>>> get_status(driver)
'Alive'
>>> driver.quit()
>>> get_status(driver)
'Dead'
Another approach would be to make your custom Firefox webdriver and set the session_id to None in quit():
class MyFirefox(webdriver.Firefox):
def quit(self):
webdriver.Firefox.quit(self)
self.session_id = None
Then, you can simply check the session_id value:
>>> driver = MyFirefox()
>>> print driver.session_id
u'69fe0923-0ba1-ee46-8293-2f849c932f43'
>>> driver.quit()
>>> print driver.session_id
None
I ran into the same problem and tried returning the title - this worked for me using chromedriver...
from selenium.common.exceptions import WebDriverException
try:
driver.title
print(True)
except WebDriverException:
print(False)
suggested methods above didn't work for me on selenium version 3.141.0
dir(driver.service) found a few useful options
driver.session_id
driver.service.process
driver.service.assert_process_still_running()
driver.service.assert_process_still_running
I found this SO question when I had a problem with closing an already closed driver, in my case a try catch around the driver.close() worked for my purposes.
try:
driver.close()
print("driver successfully closed.")
except Exception as e:
print("driver already closed.")
also:
import selenium
help(selenium)
to check selenium version number
This work for me:
from selenium import webdriver
driver = webdriver.Chrome()
print( driver.service.is_connectable()) # print True
driver.quit()
print( driver.service.is_connectable()) # print False
How about executing a driver command and checking for an exception:
import httplib, socket
try:
driver.quit()
except httplib.CannotSendRequest:
print "Driver did not terminate"
except socket.error:
print "Driver did not terminate"
else:
print "Driver terminated"
it works in java, checked on FF
((RemoteWebDriver)driver).getSessionId() == null
There is this function:
if driver.service.isconnectible():
print('Good to go')
In my case, I needed to detect whether the browser interface was closed - regardless - chromedriver's status. As such, none of the answers here worked, and I just decided to go for the obvious:
from selenium.common.exceptions import WebDriverException
try:
driver.current_url
print('Selenium is running')
except WebDriverException:
print('Selenium was closed')
Even though it's a bit of a hack, it's served my purposes perfectly.
''''python
def closedriver():
global drivername
drivername.quit()
global driveron
driveron=False
''''
this function "closedriver" uses a global variable named "drivername" and global bool variable named "driveron",you may just pass a current driver as parameter but
NOTE: driveron must be global to store the state of driver being 'on' or 'off'.
''''python
def closedriver(drivername):
global driveron
try:
drivername.quit()
except:
pass
driveron=False
''''
and when you start a new driver, just use a check
global driveron
if not driveron:
driver=webdriver.Chrome()
THIS OCCURS IN FIREFOX ONLY: In a previous question, I had run into the issue where SST 0.2.4 is not compatible with Selenium 2.44.0. So I downgraded to Selenium 2.43.0. I now have a new issue that I'm confused about. I'm receiving the following error message:
_StringException: Traceback (most recent call last):
File "C:\Python27\lib\site-packages\sst\cases.py", line 75, in setUp
self.start_browser()
File "C:\Python27\lib\site-packages\sst\cases.py", line 107, in start_browser
logger.debug('Browser started: %s' % (self.browser.name))
AttributeError: 'NoneType' object has no attribute 'name'
The code that it is referencing in the cases.py file in the Lib/SST folder is below:
def start_browser(self):
max_attempts = 5
for nb_attempts in range(1, max_attempts):
try:
logger.debug('Starting browser (attempt: %d)' % (nb_attempts,))
self._start_browser()
break
except exceptions.WebDriverException:
if nb_attempts >= max_attempts:
raise
logger.debug('Browser started: %s' % (self.browser.name))
My code looks like the following:
import unittest
from sst.actions import *
from sst import cases, config, browsers
class TestMyTest(cases.SSTTestCase):
def test_mytestcase_home_page(self):
config.results_directory = "C:/Users/Brenda/test/SST-Test-Project/results"
go_to('http://www.myhomepage.com')
assert_title_contains('My Home Page')
take_screenshot(filename='home_page.png',add_timestamp=True)
assert_element(tag='a', text='Log in')
I keep thinking that the solution to this is fairly simple, but I can't seem to wrap my head around it.
I'll also add the note that when running sst-run MySSTTest in the command line, it looks like it is attempting to start the browser without success. My code was working prior to the holiday break at which time it seems to have broken.
EDITED 3-Dec-2014: I wanted to add that I can successfully execute the test in Chrome and IE. This issue is with Firefox ONLY in a Windows 7 environment. It was successfully executed on a Mac OS in all 3 browsers.
I think cases.py codes has possibility cannot get browser object when it runs _start_browser
method
def _start_browser(self):
self.browser_factory.setup_for_test(self)
self.browser = self.browser_factory.browser()
def start_browser(self):
max_attempts = 5
for nb_attempts in range(1, max_attempts):
try:
logger.debug('Starting browser (attempt: %d)' % (nb_attempts,))
self._start_browser()
break
except exceptions.WebDriverException:
if nb_attempts >= max_attempts:
raise
logger.debug('Browser started: %s' % (self.browser.name))
The main problem: if nb_attempts >= max_attempts: has no effect. nb_attempts only goes up to max_attempts-1. I would use continue and re-raise the exception in an else clause instead:
logger.debug('Starting browser')
e = None
for _ in range(max_attempts):
try:
self._start_browser()
break
except exceptions.WebDriverException,e:
continue
else:
raise e
("_" is an idiom for an unused variable)
Even with that fix, self.browser can still be None if browser_factory.browser() returns None.
I'm experimenting with creating a basic library extension for Robot Framework using Python, and I'm using PyCharm as the editor. For libraries imported directly code completion is working fine, but in this case I'm importing the Selenium2Library indirectly via a method:
def get_current_browser():
browser = BuiltIn().get_library_instance('Selenium2Library')._current_browser()
return browser
Which I call from other methods with something like
driver = get_current_browser()
This successfully grabs the webdriver browser instance from Robot Framework and lets me do as I please, but I don't get code hints when I go to edit a 'driver' variable. Is there way I can get hints in this scenario?
Here's the code in full:
from robot.libraries.BuiltIn import BuiltIn
from Selenium2Library.keywords.keywordgroup import KeywordGroup
import logging
def get_current_browser():
browser = BuiltIn().get_library_instance('Selenium2Library')._current_browser()
return browser
class MyLibrary(KeywordGroup):
def get_title_via_python(self):
driver = get_current_browser()
title = driver.title
logging.warn("checking title %s" % title)
return title
Try adding a docstring to your function to help PyCharm.
from selenium.webdriver import Remote # Remote imported only for code completion
def get_current_browser():
"""
:rtype: Remote
"""
browser = BuiltIn().get_library_instance('Selenium2Library')._current_browser()
return browser
More at http://www.jetbrains.com/pycharm/webhelp/type-hinting-in-pycharm.html
I have a little script that runs every day by cron and has been working for the last 3 months.
On 30th September it stopped working with the following error:
File "NumberChecker.py", line 32, in start_server
os.startfile(startfile[0])
AttributeError: 'module' object has no attribute 'startfile'
here is the code for that bit:
def start_server(xml):
startfile = xml.xpath('/config/files/startfile/text()')
try:
driver = webdriver.Remote(desired_capabilities=webdriver.DesiredCapabilities.HTMLUNIT)
driver.get('http://www.google.com')
except:
print('no server')
server_status = 'down'
os.startfile(startfile[0])
while server_status == 'down':
try :
driver = webdriver.Remote(desired_capabilities=webdriver.DesiredCapabilities.HTMLUNIT)
driver.get('http://www.google.com')
server_status = 'running'
except :
pass
It just tests to see if the selenium server is up or not by requesting google and if not calls a bash script that starts it.
Why would os.startfile suddenly stop working?
I have tried at the command line this:
import os
os.startfile(home/adam/file/start_server.sh)
and I get
File "< stdin >", line 1, in
AttributeError: 'module' object has no attribute 'startfile'
I just can't work out why it has just stopped working?
It is python 3.3 in an virtual environment and the os is ubuntu server 12.04
os.startfile is a Windows specific method, it won't work on linux.
I am executing selenium test cases via Proboscis, for good reporting of test results. I have the following test case written
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from proboscis import test
import unittest
driver = webdriver.Firefox()
#test(groups=["unit","login"])
class UI_test(unittest.TestCase):
def test_SuccessfulErrorMsgOnEmptyUserName(self):
driver.get("http://127.0.0.1:7999/login/")
username_input = driver.find_element_by_id("id_email")
username_input.send_keys('')
password_input = driver.find_element_by_id("id_password")
password_input.send_keys('bill3')
driver.find_element_by_xpath('//input[#value = "Log In"]').click()
driver.implicitly_wait(3)
driver.find_element_by_class_name("error-login")
driver.close()
def run_tests():
from proboscis import TestProgram
# from tests import unit
# Run Proboscis and exit.
TestProgram().run_and_exit()
if __name__ == '__main__':
run_tests()
What could be causing the BadStatusLine exception in this code?
Looks like a duplicate of Python/Django "BadStatusLine" error but i can't flag due to this question having a bounty. According to this answer, a BadStatusLine exception is likely caused by an empty response, as in there being no status line at all.
According to this answer, the server formally tells the client there is no more data, instead of simply causing a connection reset or rude timeout.