Selenium: Execute third function after first two finished - python

I am using Selenium Webdriver with Firefox to run my code. I am using pytest so I can run the functions in parallel. I have three main functions: first and second function return something and third function uses the data from the pervious functions. My problem is that I want to execute third function with the data returned from two functions once the first two functions have finished.
The code itself is actually much more complex but to clarify I made a new code which demonstrates my problem. I have two functions, one is named "test1" and other is named "test2" - both of these run parallel and return information. I also have a third function named "test3" to process the data returned from test1 and test2 once they're both finished. In this example "comp" should just print out some text.
Here's the code:
import unittest
from time import sleep
from selenium import webdriver
# pytest -s -v tests.py <----- I use to execute this script
# py.test -s tests.py -d --tx 2*popen//python=python2.7 <------- I use this to run the tests in parallel
# For some reason program doesnt print in parallel mode. Although "-s" fixes that in the normal execution of pytest.
class TestParallel(unittest.TestCase):
def setUp(self):
self.browser = webdriver.Firefox(executable_path='./dependencies/geckodriver')
def test1(self):
browser = self.browser
browser.get('https://www.google.com/')
asd = browser.find_element_by_xpath("/html/body/div/div[3]/div[1]/div/div/div/div[1]/div[1]/a").text # returns "Gmail"
sleep(2)
print asd
return asd
def test2(self):
browser = self.browser
browser.get('https://www.google.com/')
asd2 = browser.find_element_by_xpath("/html/body/div[1]/div[3]/div[1]/div/div/div/div[1]/div[2]/a").text # returns "Images"
sleep(1)
print asd2
return asd2
def test3(self):
print "word from test1 is " + TestParallel.test1(self) + " and word from test2 is " + TestParallel.test2(self)
def tearDown(self):
self.browser.quit()
if __name__ == "__main__":
unittest.main()
Maybe someone has ideas/suggestions as to how I could resolve this issue. Thank you!

Edit
Ok, here's another idea:
Declare two empty global string variables before test1 and test2 are
run.
Have test1 and test2 write to those two variables
Have test3
wait with a while loop until both of the variables contain something
or until a specific amount of time passes.
class TestParallel(unittest.TestCase):
string_a = ""
string_b = ""
def setUp(self):
self.browser = webdriver.Firefox(executable_path='./dependencies/geckodriver')
def test1(self):
[..]
string_a = "result_a"
def test2(self):
[..]
string_b = "result_b"
def test3(self):
counter = 0;
while ("" in string_a && "" in string_b):
sleep(0.1)
counter = counter + 1
if counter > 200:
break
print "word from test1 is " + string_a + " and word from test2 is " + string_b
Hmm, perhaps:
def test3(self):
counter = 0;
while ("" in string_a && "" in string_b):
sleep(0.1)
counter = counter + 1
if counter > 1000:
break
print "word from test1 is " + string_b + " and word from test2 is " + string_b

test1 and test2 don't really look like tests... they look like they should be functions that return data from the page that are used in a test. I would do something more like
def get_thing1(self):
return self.browser.find_element_by_xpath("/html/body/div/div[3]/div[1]/div/div/div/div[1]/div[1]/a").text # returns "Gmail"
def get_thing2(self):
return self.browser.find_element_by_xpath("/html/body/div[1]/div[3]/div[1]/div/div/div/div[1]/div[2]/a").text # returns "Images"
def test1(self):
browser = self.browser
browser.get('https://www.google.com/')
print "word from test1 is " + get_thing1(self) + " and word from test2 is " + get_thing2(self)
These two methods, get_thing1 and get_thing2 assume that you are on the right page and all they do is return whatever you are looking for. Please change the names to something more descriptive... I wasn't sure what exactly they were returning so I made up some generic name.
Now you only have test1 that runs and two methods that pull things from the page. You can run test1 as many times as you want... in parallel, etc. ... in a loop or whatever you desire.
Extra notes:
You really don't want to use XPaths that are that many levels deep and/or that start at the HTML tag. They are very brittle (likely to break with any little change to the HTML).
You should take some time to read about the page object model. You should create a GoogleSearchResultsPage page object and have get_thing1() and get_thing2() be in that page object. You test would then progress from the GoogleSearchPage to the GoogleSearchResultsPage and would then call those two methods, etc. to get data from the page.

Related

Is there a way to set variables at runtime in python

I am trying to set/unset some of the debug flags while my code is running. Below is the snippet of the function
class ABC:
def __init__(self,debugFlag):
self.debugFlag = False
def some_function()
if self.debugFlag is True:
print "Some debug logs"
Above is the code snippet. I want to set this debugFlag while my program is running and depends on the situation want to set/unset its value. Based on the current value of debugFlag it should print debug logs or not
How to do this in python
Explaining my problem again : Suppose I am having a script that takes 60 mins to run. I executed the script with debugFlag False. After 15 mins, I want to enable the debug logs. How can I do this without interrupting my execution.
How about:
class ABC:
def __init__(self,debugFlag):
self.debugFlag = False
def some_function():
if self.debugFlag is True:
print "Some debug logs"
def set_flag():
self.debugFlag = True
You can change the value of self.debugFlag when a condition is met, yes.
class ABC:
def __init__(self,debugFlag):
self.debugFlag = debugFlag # or omit that arg and always false
def some_function(self): # Need self
if self.debugFlag:
print "Some debug logs"
def condition_setter(self):
# Do some checks here then set debugflag to False
self.debugFlag = False
One way to accomplish this is to declare var in your modules root, and import/reference them in the same scope when you set and reference.
Imagine the directory structure of your modules like so
my_module/
- __init__.py
- another_module.py
- utils/
- __init__.py
- and_so_on.py
in my_module/__init__.py declare your __debug__ var
__debug__ = False
In your example code
import my_module
class ABC:
def __init__(self):
pass
def some_function()
if my_module.__debug__ is True:
print "Some debug logs"
Then before you actually execute the code, set your debug flag to False importing and referencing in the same fashion
import my_module
my_module.__debug__ = True
As long as you import and reference the variable the same IE:
import my_module
if my_module.__debug__ is True:
print("IN DEBUG")
It will retain its value throughout your execution
Try something like this :
class ABC():
def __init__(self, debugFlag):
self.debugFlag = debugFlag
def some_function(self):
if self.debugFlag:
print('Debug on\n')
else:
print('Debug off\n')
abc_object = ABC(False)
def check_choice():
if str(choice) == '1':
abc_object.debugFlag = True
abc_object.some_function()
elif str(choice) == '2':
abc_object.debugFlag = False
abc_object.some_function()
else :
print('Invalid input')
while True:
choice = input('Type 1 to enable debugging, 2 to disable debuigging : ')
check_choice()
Summary:
When you initialize the class it takes 1 mandatory argument debugFlag, either True or False.
When you define a function from within the class you should use the 'self' argument.
Explanation as to of why this is
'if self.debugFlag' is the same as if 'self.debugFlag is True :' The former should be used as it is more concise.
We instantiate an instance of ABC and store it in the variable abc_object. We pass it a default value for debugFlag, in this case False.
We then introduce some logic to check the state of debugFlag, and then perform some function based on the outcome of our logic.
Hope this helps. Let me know if you need further clarification.
I dont think you can do this directly from variables, but you can, for example, create a file (debug.txt for example) and check if it exists for your triggering. For example, create an empty file called debug.txt and check, inside your script, if the file exists.
Untested code:
import os
class ABC:
def __init__(self,debugFlag):
self.debugFlag = False
def some_function()
if os.path.exists("debug.txt"):
print "Some debug logs"
This way you can trigger/untrigger debug by creating/deleting the file "debug.txt".
With a slight modification of your class:
class ABC:
def __init__(self,debugFlag=False):
self.debugFlag = debugFlag # initialize the flag here or use default
def some_function()
if self.debugFlag is True:
print "Some debug logs"
After you create the object you will be able to change its attributes, like:
obj_abc = ABC() # debug off by default
obj_abc.some_function() # no debug print
obj_abc.debugFlag = True # enable debug
obj_abc.some_function() # now with debug print
obj_abc.debugFlag = False # disable debug
obj_abc.some_function() # now without debug print

How to return a value from one python script to another?

file1.py
from processing file import sendfunction
class ban():
def returnhello():
x = "hello"
return x #gives reply a value of "hello replied" in processingfile
print(sendfunction.reply()) #this should fetch the value of reply from processingfile,right?
processingfile.py
from file1 import ban
class sendfunction():
def reply():
reply = (ban.returnhello() + " replied")
return reply
I can't really seem to get any results, any help would be appreciated.
You need to create object of class ban before calling his member function as follows
from file1 import ban
class sendfunction():
def reply(self): # Member methods must have `self` as first argument
b = ban() # <------- here creation of object
reply = (b.returnhello() + " replied")
return reply
OR, you make returnhello method as static method. Then you don't need to create an object of class beforehand to use.
class ban():
#staticmethod # <---- this is how you make static method
def returnhello(): # Static methods don't require `self` as first arugment
x = "hello"
return x #gives reply a value of "hello replied" in processingfile
BTW: Good programming practice is that, you always start you class name with Capital Letter.
And function and variable names should be lowercase with underscores, so returnhello() should be return_hello(). As mentioned here.
Lets suppose we have two file A.py and B.py
A.py
a = 3
print('saying hi in A')
B.py
from A import a
print('The value of a is %s in B' % str(a))
On executing B.py you get the following output:
└> python B.py
saying hi in A
The value of a is 3 in B

equivalent to shell "set -x" for python

On Linux, is there a debugging tool for a python script that prints the lines of code before executing them, similar to the "set -x" directive in shell scripts ?
I know the debugging pdb module, but I am not aware it can do this (the stacktrace is not suitable).
I know strace, but it does not do this level of debugging.
Example :
def step_1():
print("some step 1...")
return 123
def step_2(some_value):
print("some step 2... %s" % (some_value) )
return "abc"
# main
x = step_1()
y = step_2(x)
Execution with the hypothetic debugging tool I'm looking for:
$ python t.py
+ step_1()
+ print("some step 1...")
some step 1...
+ x = 123
+ step_2(123)
+ print("some step 2... %s" % (123) )
some step 2... 123
+ y = "abc"
The system trace, which is often used by debuggers for similar purposes, can be used to implement such a feature. Here is a minimal example that you can tweak to suit your needs:
import sys
import inspect
this_module = sys.modules['__main__']
source_lines = inspect.getsource(this_module).splitlines()
def mytrace(frame, event, arg):
if source_lines and event in {'line', 'call', 'return'}:
line = source_lines[frame.f_lineno].strip()
print('+', line)
return mytrace
sys.settrace(mytrace)
def step_1():
print("some step 1...")
return 123
def step_2(some_value):
print("some step 2... %s" % (some_value) )
return "abc"
# main
x = step_1()
y = step_2(x)
Since Python is not bash and the execution model is different, you might not get the exact same output as seen with set -x in a shell script (for example the line + y = "abc" with literal rvalue will not make sense in a Python context) but you should be able to recreate something similar enough to be useful for your needs, by interacting with the frame object passed to the trace.

Python and pytest testing

I have to do some testing using pytest, but I have no idea where to start.
Here is piece of a code which i would like to test:
def print_url_and_id():
for item in movie_link[:100]:
print item.contents[1], "The ID of this movie is:", '"' + item.contents[1]['href'][7:16] + '"'
Could anyone tell me how it suppose to look like?
You can do something like this:
import pytest
def parametrized():
expected_results = ["movie_link_01", "movie_link_02"]
movie_link = ["movie_link_01", "movie_link_02", "movie_link_03"]
# you can define your new_movie_link list like this as you have done, but instead of
# printing it, add it to a this new_movie_link list
return [(item_1, item_2) for item_1, item_2 in zip(movie_link[:2], expected_results)]
#pytest.mark.parametrize("movie_link, expected", parametrized())
def test_parametrizer(movie_link, expected):
assert movie_link == expected

How to print a string static member of a class with `yield` from a class method

I am really new to python, so this might be really easy.
I want to print two strings defined in a class as static members with a class method that yields each string.
This is a simplified version of what I am trying to do:
#!/usr/bin/python
import sys
class test:
str1 = "Hello"
str2 = "World\n" #"\n" is needed for the example
def printMe(self):
yield test.str1
yield test.str2
hello = test()
print "Testing initiated:"
sys.stdout.write(hello.printMe())
sys.stdout.write(hello.printMe())
This is the output:
sys.stdout.write(hello.printMe()) TypeError: expected a character
buffer object
You are attempting to use a generator function, read about the yield keyword here
import sys
class Test:
def __init__(self): # it's possible to initialise these attributes in the __init__ method, so they are created on class instantiation(when you did hello = Test())
self.str1 = "Hello"
self.str2 = "World\n" #"\n" is needed for the example
def printMe(self):
for i in [self.str1, self.str2]:
yield i
app = Test()
print "Testing initiated:"
for i in app.printMe():
print i # is there a reason why you can't use print?
If however you want to print the lines one at a time, at specific points in the code, like in your loop you mentioned in the comment:
gen = app.printMe()
then every time you want to print:
gen.next()
this triggers the next yield statement. The generator function effectively 'holds'/remembers it's place until you call next again, until all the yield statements have been yielded.
You should do something like this
for line in hello.printMe():
print line
But really there are a lot of easier ways than using yield statements.
using yield turns your function into a generator. If this is really what you want, you will need to iterate over the generator to get the values:
gen = hello.printMe()
sys.stdout.write(gen.next())
sys.stdout.write(gen.next())
or better:
for prop in hello.printMe():
sys.stdout.write(prop)
Your printMe method is a generator function, which returns an iterable. You need to iterate over it to get the results :
for item in hello.printMe():
print item
You can do this, but I'm using print, hope this helps you:
class test:
str1 = "Hello"
str2 = "World\n" #"\n" is needed for the example
def printMe(self):
yield test.str1
yield test.str2
hello = test()
print "Testing initiated:"
out = hello.printMe()
print(out.next(),end=' ')
print(out.next(),end=' ')

Categories