Python code: Local variable referenced before assignment - python

I have the following program in python 2.7 to launch a web page and do an activity. I have parsed the HTML DOM of a web page and was able to make this work when launched via PyCharm IDE or via an Exe created with PyInstaller or via a bat file that wraps an Exe.
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.common.by import By
import time
import sys
def main():
try:
mgmt_console_server_name = sys.argv[1]
user_session_to_terminate = sys.argv[2]
# Phase 1: Launch a browser and open the management console page
# Using IE to access web
driver = webdriver.Ie('IEDriverServer32.exe')
return_code = 0
# Open the management console page.
driver.get("http://" + mgmt_console_server_name + ":8183/mgmt/security/login.html")
# Phase 2: Enter the LDAP credentials and hit enter
# Select the username and the password text boxes
username = driver.find_element_by_class_name('gwt-TextBox')
password = driver.find_element_by_class_name('gwt-PasswordTextBox')
# Send username information
username.send_keys('sa-tcnxbot-gds')
# Send password information
password.send_keys('zzzzzzzzz')
# Login to Teamcenter management console with the above set credentials.
signinbutton = driver.find_element_by_class_name('GFHWBTICII')
signinbutton.click()
# Phase 3: Click on the 'TcServer' component to reach the UI where we can find and kill the user sessions.
# We are now in the main page. We need to wait till we find an XML element by the ID
# 'Console'. This signifies that the page has loaded. And we wait at the maximum of 20 seconds.
WebDriverWait(driver, 20).until(ec.presence_of_element_located((By.ID, "Console")))
# We find the XML element whose InnerHTML is 'Tc Server'.
tcserverelement = driver.find_element_by_xpath("//div[text()='Tc Server']")
# We then find its immediate parent, which is the clickable element and finally click it.
tcserverclickableelement = tcserverelement.find_element_by_xpath('..')
tcserverclickableelement.click()
# Phase 4: We enter the user id whose session is to be terminated in the search field and hit the search.
WebDriverWait(driver, 20).until(ec.presence_of_element_located((By.XPATH, "//div[text()='Assigned User:']")))
# We are at the HTML element that has the text 'Assigned User:'
assigneduserelement = driver.find_element_by_xpath("//div[text()='Assigned User:']")
# print(assigneduserelement)
# An immediate parent of this HTML element is the TD element.
assigneduserelementparent = assigneduserelement.find_element_by_xpath('..')
# print(assigneduserelementparent)
# An immediate sibling of this TD HTML element is another TD element which contains INPUT HTML element.
assigneduserelementparent.find_element_by_xpath("//TD/following-sibling::TD")
# print(assigneduserelementparent_sibling)
# assignedusertextbox = assigneduserelementparent_sibling.find_elements_by_xpath(".//*")
# print(assignedusertextbox[0])
# Send username information
driver.find_elements_by_class_name('gwt-TextBox')[1].send_keys(user_session_to_terminate)
search_button = driver.find_element_by_xpath("//button[text()='Search']")
# We then find its immediate parent, which is the Search button and finally click it.
search_button.click()
time.sleep(4)
# There would be three cases here.
# Case 1: The input user has no sessions on his name.
# Case 2: The input user has one session on his name.
# Case 3: The input user has more than one sessions on his name.
# Case 1: This should be one of the table header elements containing the list of servers assigned to the user.
assigned_server_rows = driver.find_elements_by_xpath("//div[text()='Assigned']")
if len(assigned_server_rows) == 0:
return_code = 4
else:
# Case 2 and Case 3:
for each_assigned_server in assigned_server_rows:
print each_assigned_server.tag_name
assigned_server_parent_td = each_assigned_server.find_element_by_xpath('..') # td
print assigned_server_parent_td.tag_name
assigned_server_parent_td.click()
# assigned_server_parent_tr = assigned_server_parent_td.find_element_by_xpath('..') #tr
# print assigned_server_parent_tr.tag_name
# assigned_server_parent_tr.click()
shutdown_button_element = driver.find_element_by_xpath("//button[text()='Shutdown Server']")
shutdown_button_element.click()
time.sleep(2)
main_page = driver.window_handles[0]
alert_window = driver.switch_to.alert
alert_window.accept()
driver.switch_to.window(main_page)
except:
return_code = 1
finally:
driver.quit()
if return_code == 0:
print('=> Successfully terminated sessions for the user ' + user_session_to_terminate)
elif return_code == 4:
print('=> There are no sessions assigned to the user ' + user_session_to_terminate)
else:
print('=> An error occurred while tying to terminate sessions for the user ' + user_session_to_terminate)
return return_code
if __name__ == "__main__":
main()
But as part of Azure Chatbot, when we tried to plug it in NodeJS code, we are seeing this problem. Is this really some problem with my code?. How should I correctly correct it.
I read on scoping of python but in this case everything is inside the main function and got to know that python try-catches do not add new block scope. So my expectation is that everything should have worked. Please let me know what I am missing.
PyAutomationScript Error:Error: Command failed: C:\tcnxbot_data\automated_script\auto.exe localhost pdittaka
[9904] Failed to execute script auto
Traceback (most recent call last):
File "auto.py", line 131, in <module>
File "auto.py", line 118, in main
UnboundLocalError: local variable 'driver' referenced before assignment
Thanks,
Pavan.

This might be an issue with the line inside the finally function. What you are essentially saying is irrespective of whether there is an error or not (whether it goes into try or except) execute driver.quit().
But if your code runs into and error inside the try before or during the driver is defined, it goes into the except, then the finally where you are attempting to close the driver. However, this is not possible because the driver hasn't been defined yet. What you can do is add this at the beginning of the main function:
driver = None
and change the code inside the finally: to be this:
if driver is not None:
driver.quit()

Related

Check if text is visible with Selenium, Python

I am making a script that will fill the forms to create a Gmail account with Python. When a username is already used a message becomes visible. In dutch: "Dez gebruikersnaam worst al gebruikt. Probeer been andere gebruikersnaam." To be able to deal with this I need to detect when this message is visible, but I have no idea how to do that. If anyone can help, that would be amazing
Try this code:
from selenium import webdriver
import time
path = '/home/avionerman/Documents/stack'
driver = webdriver.Firefox(path)
driver.get('https://www.google.com/intl/nl/gmail/about/#')
try:
print('locating create account button')
create_account_button = driver.find_element_by_class_name('h-c-button')
except:
print("error, couldn't find create account button")
try:
create_account_button.click()
print('navigating to creation page')
except:
print('error navigating to creation page')
time.sleep(8)
handles = driver.window_handles
size = len(handles)
driver.switch_to.window(handles[1])
print(driver.title)
first_name_input = driver.find_element_by_id('firstName')
first_name_input.click()
first_name_input.send_keys("WhateverYouWant")
last_name_input = driver.find_element_by_id('lastName')
last_name_input.click()
last_name_input.send_keys("WhateverYouWant2")
username_input = driver.find_element_by_id('username')
username_input.click()
username_input.send_keys('papadopoulos')
pswd_input = driver.find_element_by_name('Passwd')
pswd_input.click()
pswd_input.send_keys('whateveryouwant')
pswd_conf_input = driver.find_element_by_name('ConfirmPasswd')
pswd_conf_input.click()
pswd_conf_input.send_keys('whateveryouwant')
next_button = driver.find_element_by_id("accountDetailsNext")
next_button.click()
# In the variable x I save the text that is included inside the specific xpath
x = driver.find_element_by_xpath("//*[#id='view_container']/form/div[2]/div/div[1]/div[2]/div[1]/div/div[2]/div[2]/div").text
print(x)
# I assert in order to check if the variable x has the proper text value (the expected one)
assert x == 'Dez gebruikersnaam worst al gebruikt. Probeer been andere gebruikersnaam.'
time.sleep(10)
In this way, if the assert passes mean that you see the warning message and in any other case the username for the mail is unique. So, the part of the code that I wrote to you, you can insert it inside if statements and you can handle it as you wish. If you need any further info feel free to ping me.

Python Selenium - Trying to fail a test when expected value is not found

I have an application where users can create lists...once they create a list it will show up in a table on their homepage of the app. Only lists the user creates should display in the "created by" column of the table.
I'm trying to have the test fail and print if the expected name is not found.
users_names = context.browser.find_elements_by_xpath("//tr//td[7]")
expected_name = "%s" % name
for name in expected_name:
if name.text != expected_name:
print("Failed\n", users_names)
If I understand your question correctly, you would like to verify that the only lists shown are in-fact created by the user. There's a few ways of doing this, and the example below can be improved.
We have our setUp() that's used to get everything ready before we
start our test, profiles, preferences etc etc
Then test_show_only_user_created_lists() is the meat of our test,
where we hold the functionality of what we're testing (you may have
to place your remaining code within this section, if you had to do
anything before checking the list)
Then we have our tearDown() which we use to finish off our remaining
test, in this case we just close down our browser.
We could use our handy unit test library and asserting only after our loop has finished. But we must make sure to populate our 'expected_name' variable.
import unittest
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
class listTest(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
def test_show_only_user_created_lists(self):
driver = self.driver
driver.get("http://yoursite.com")
users_names = driver.find_elements_by_xpath("//tr//td[7]")
testOutcome = 1
for name in users_names:
if name.text != expected_name:
testOutcome = 0
### Assert ####
self.assertTrue(testOutcome)
def tearDown(self):
self.driver.quit()
if __name__ == "__main__":
unittest.main()
We can then run our test with the following command with indication of passes or failures:
python selenium-python-test.py

Python Selenium - How to handle alert that doesn't show up until after WebDriverWait finishes?

Currently I'm trying to automate an order process and at some point, if an order has been recently placed, an alert will pop-up stating, "Customer has placed an order for these same items within 2 days. Please check for duplicates or check Override Duplicate Order to continue."
I've tried the following to intercept that alert and allow the script to continue running:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.alert import Alert
from selenium.webdriver.support import expected_conditions as ExCon
from selenium.common.exceptions import TimeoutException, NoSuchElementException, NoAlertPresentException,\
UnexpectedAlertPresentException
from oleaprocs import Order
"""
Will put the following constants in their own file later
"""
GEN_NEXT_ID = "cmdNext"
SHIP_DET_METH_ID = "cboAvailItemsShip"
SHIP_DET_NEXT_ID = "cmdNext"
ORDER_REP_ID = "cboServiceRep"
EMAIL_ID = "ctl00_ctl00_main_content_main_content_ctl00_txtEmail"
SEARCH_RESULT_ID = "ctl00_ctl00_main_content_main_content_ctl00_dgResults_ctl03_lnkCustName"
ADD_ORDER_ID = "cmdAddNewOrder"
LOGIN_ID = 'ctl00_ctl00_main_content_main_content_ctl00_UserName'
PASS_ID = 'ctl00_ctl00_main_content_main_content_ctl00_password'
SIGNIN_ID = 'ctl00_ctl00_main_content_main_content_ctl00_SigninBtn'
PLACED_VIA = 'Phone'
BILL_OPTION = 'Visa x1111'
username = 'user'
password = 'pass'
customer = 'user'
items = {'Item1': '100', 'Item2': '125'} # One or many items - also noting quantity
# This setup will likely be steamlined to determine whose server to use, etc
driver = webdriver.Chrome()
driver.maximize_window()
driver.get("website-placeholder-for-security-reasons")
# Login will be separated out into a function, to allow for various logins
# log-in
driver.find_element_by_id(LOGIN_ID).send_keys(username)
driver.find_element_by_id(PASS_ID).send_keys(password)
driver.find_element_by_id(SIGNIN_ID).click()
driver.find_element_by_xpath('//a[text()="Customers"]').click()
# Type in search for user-email - separated to function later
search_email = driver.find_element_by_id(EMAIL_ID)
search_email.send_keys(customer)
search_email.send_keys(Keys.RETURN)
# Click the (hopefully) singular search result
driver.find_element_by_id(SEARCH_RESULT_ID).click()
#search_result = driver.find_element_by_id(SEARCH_RESULT_ID).click()
#search_result.click()
### Start creating new order ###
## Order Items ##
# Accept Customer Orders alert
"""
alert_obj = driver.switch_to.alert
alert_obj.accept()
"""
Alert(driver).accept()
# Click on "Add New Order"
driver.find_element_by_id(ADD_ORDER_ID).click()
order = Order(driver)
# Set Placed Via
placed_via = Select(driver.find_element_by_name('cboPlacedVia'))
placed_via.select_by_visible_text(PLACED_VIA) # could also set IDs in a dict
# Set Billing Option
bill_option = Select(driver.find_element_by_name('ctrlBillOption$cboBillOption'))
bill_option.select_by_visible_text(BILL_OPTION)
# Add items to order
order.add_items(items)
# Will likely do some assertions here at some point, for custom / printed items
driver.find_element_by_id('cmdNext').click()
## Shipping Details ##
# Select Shipping Method
# If similar order recently placed - confirm alert and try/except duplicate order override
# driver.implicitly_wait(2)
try:
print("WebDriverWait - 2 seconds")
WebDriverWait(driver, 2).until(ExCon.alert_is_present())
Alert(driver).accept()
print("Switching to Alert")
#alert_dupe = driver.switch_to.alert
# print(str(alert_dupe.text))
# alert_dupe.accept()
except TimeoutException:
print("Timeout")
except NoAlertPresentException:
print("No Alert Present")
except UnexpectedAlertPresentException:
print("Unexpected alert, yo!")
try:
driver.find_element_by_id('chkDuplicateOrderOverride').click()
except NoSuchElementException:
print("No duplicate order detected")
# Continue
driver.find_element_by_id('cmdNext').click()
## Order Group Details ##
# Check for Authorize button (I could bypass this when I implement "order_type" later
try:
driver.find_element_by_id('cmdAuthorize').click()
except NoSuchElementException:
print("No Authorize Element Found - This payment method does not require authorization")
driver.find_element_by_id('cmdPlaceOrder').click()
And the other file referenced:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
"""
Order will be used to keep track of the state of an order throughout
the order-process. This can include things like the order total, items
included, and can even get as complicated as 1:1 mirroring all of the
details of an order. This will depend on our requirements.
"""
class Order(object):
def __init__(self, driver):
self.driver = driver
# self.product_name_field = self.driver.find_element_by_id('txtProductName')
# self.quantity_field = self.driver.find_element_by_id('txtQuantity')
# self.add_item_button = self.driver.find_element_by_id('cmdAddSaveItem')
# Add items to an order
def add_items(self, items):
"""
Will need to make the quantity check in here.
"""
# product_name_field = self.driver.find_element_by_id('txtProductName')
# quantity_field = self.driver.find_element_by_id('txtQuantity')
# add_item_button = self.driver.find_element_by_id('cmdAddSaveItem')
"""
Cannot simply one-time set the above because of the references
going stale x_x - need to see if I can ignore stale-references.
"""
for item, quantity in items.items():
product_name_field = self.driver.find_element_by_id('txtProductName')
product_name_field.send_keys(item)
product_name_field.send_keys(Keys.TAB)
quantity_field = self.driver.find_element_by_id('txtQuantity')
quantity_field.send_keys(quantity)
quantity_field.send_keys(Keys.TAB)
add_item_button = self.driver.find_element_by_id('cmdAddSaveItem')
add_item_button.click()
I made a comment about the previous alert potentially not releasing resources... I have the following code a good bit earlier to handle an alert that always pops up, so I don't have to try that one:
alert_obj = driver.switch_to.alert
alert_obj.accept()
I use the driver.switch_to.alert variation here because I've tried both variations in the earlier code and neither worked.
Basically what happens when the code gets to WebDriverWait(drive, 2)... is that the browser sits there and waits 2 seconds, THEN the alert pops up. I've tried various arbitrary lengths of time and it will always wait that amount of time, then show the alert. I feel like I'm being trolled here :|
Here is the error info I receive after this happens:
Traceback (most recent call last):
File "C:\Users\user\Documents\Projects\Selenium\proj.py", line 136, in <module>
driver.find_element_by_id('cmdAuthorize').click()
File "C:\Python\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 353, in find_element_by_id
return self.find_element(by=By.ID, value=id_)
File "C:\Python\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 957, in find_element
'value': value})['value']
File "C:\Python\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 314, in execute
self.error_handler.check_response(response)
File "C:\Python\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 241, in check_response
raise exception_class(message, screen, stacktrace, alert_text)
selenium.common.exceptions.UnexpectedAlertPresentException: Alert Text: None
Message: unexpected alert open: {Alert text : Customer has placed an order for these same items within 2 days. Please check for duplicates or check Override Duplicate Order to continue.}
(Session info: chrome=66.0.3359.181)
(Driver info: chromedriver=2.38.552522 (437e6fbedfa8762dec75e2c5b3ddb86763dc9dcb),platform=Windows NT 10.0.16299 x86_64)
Any idea why this might be occurring? If I recall correctly, I don't believe we really have any alerts that also have checkboxes or input, so I wouldn't be 100% opposed to just 100% blocking alerts from being acknowledged by Selenium (or auto-accepting them), but I would like to avoid that if I can.
The code runs completely fine and places an order all the way through properly if no order has been placed recently (or I use a different account to test the order creation under over and over).
The manual steps from the point of adding items (just before the problematic page) would be:
1) Enter item name, then enter the item quantity
2) Do this for each item in the "items" dict
3) Hit the next button
4) Next page with shipping options "loads"
5) Issue occurs if an order was recently placed -- the WebDriverWait seems to be halting the loading of the page? It seems like this is the case since the alert will not show up until after the WebDriverWait time runs out.
I'm not really doing anything special after telling Selenium to hit the next button to reach the next page. Nothing different from the previous "hit the next button" actions, and the page shouldn't really be behaving any different than the other pages - even though the Alert is apparently just not having it x_x
I didn't have a "click next button" before the alert check -- the alert doesn't pop up until after I try and submit the shipping details first. Reason why it seemed to continue on to further steps after the alert-check failure.
Outline the process beforehand, kids.

Facebook - Getting a python function to repeat?

I am hoping someone may be able to point out the error I am making; it is probably very straight forward!
What I am trying to do is run some code previous what I have shown below, then when I get to this point I need to get it to hold for the 600 seconds and then reload the download page:
try:
# Clicks OK in Download Requested window
driver.implicitly_wait(10)
ClickOkay = driver.find_element_by_css_selector("._42ft._42fu.layerCancel.uiOverlayButton.selected._42g-._42gy")
ClickOkay.click()
except:
print("error 2")
# Wait Time
# time.sleep(600) # Allow Facebook to compile the archive
# Reload Settings page
GoToURL('https://www.facebook.com/' + 'settings', driver)
# Goes back through to Download page
link = driver.find_element_by_link_text('Download a copy')
link.click()
At this point if the archive has finished being created then the button changes from Start Archive to Download Archive. However depending on the size of the profile the time taken to compile the archive varies. so what i was attempting (with the code below and a couple of attempts with the if and while arguments) was to get it to check if the button exists and if not go back and wait 300 seconds before trying again. Once the button appears it will then continue on to download using additional code.
try:
print("Checking if button exists")
DownloadArchive = driver.find_elements_by_css_selector("._42ft._42fu.selected._42gz._42gy")
print(DownloadArchive.count())
if(DownloadArchive.count() > 0):
print("button exists")
else:
print("button does not exist")
# Button to initiate password entry popup window
#driver.implicitly_wait(10)
#while (DownloadArchive = driver.find_element_by_css_selector("._42ft._42fu.selected._42gz._42gy")):
# if (DownloadArchive = True):
# DownloadArchive.click()
# print("wait")
# else:time.sleep(300)
Thanks in advance, James
You're mixing the assignment operator (=) with the equal operator (==).
So it should be:
while (DownloadArchive == driver.find_element_by_css_selector("._42ft._42fu.selected._42gz._42gy")):
if (DownloadArchive == True):
Or just:
while DownloadArchive == driver.find_element_by_css_selector("._42ft._42fu.selected._42gz._42gy"):
Hope it helps!

Selenium 'Modal dialog present' but is not actually on screen

I have a comprehensive list of Australian postcodes, and I need to use the search function of a specific site to get corresponding remoteness codes. I created a Python script to do that, and it does it efficiently.
Except that, at a seemingly random time during the iteration, it throws a 'Modal dialog present' exception. The problem is, I see no dialog! The webpage looks as usual, and I can interact normally with it with my mouse. What could be the problem and is there a solution?
browser = webdriver.Firefox() # Get local session of firefox
browser.set_page_load_timeout(30)
browser.get("http://www.doctorconnect.gov.au/internet/otd/Publishing.nsf/Content/locator") # Load page
assert "Locator" in browser.title
search = browser.find_element_by_name("Search") # Find the query box
ret = browser.find_element_by_id("searchButton")
doha_addr = []
doha_ra = []
for i in search_string_list:
search.send_keys(i)
ret.send_keys(Keys.RETURN)
addr = browser.find_element_by_xpath("//table/tbody/tr[2]/td[2]")
doha_addr.append(addr.text)
ra = browser.find_element_by_xpath("//table/tbody/tr[4]/td[2]")
doha_ra.append(ra.text)
try:
browser.find_element_by_xpath("//html/body/div/div[3]/div/div/div/div/div/div[7]/div/div[13]/div[1]").click()
except:
pass
search.clear()
I seem to have caught a glimpse of a popup dialog that shows up and hides itself while my script was running. Anyway, this becomes irrelevant with a while switch and a try/except clause... :7D
doha_ra = {}
for i in search_string_list:
switch = True
while switch == True:
search.send_keys(i)
ret.send_keys(Keys.RETURN)
try:
addr = browser.find_element_by_xpath("//table/tbody/tr[2]/td[2]")
ra = browser.find_element_by_xpath("//table/tbody/tr[4]/td[2]")
doha_ra[addr.text] = ra.text
switch = False
except:
pass
search.clear()

Categories

Resources