How to implement method chaining of Selenium multiple WebDriverWait in Python












3















I am looking to implement method chaining of Selenium WebDriverWaits.



To start with, this block of code implementing a single WebDriverWait works perfect:



from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait

options = webdriver.ChromeOptions()
options.add_argument("start-maximized")
options.add_argument('disable-infobars')
driver = webdriver.Chrome(chrome_options=options, executable_path=r'C:UtilityBrowserDriverschromedriver.exe')
driver.get('https://www.facebook.com')
element = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_xpath("//input[@id='email']"))
element.send_keys("method_chaining")


As per as my current requirement I have to implement chaining of two WebDriverWait instances as the idea is to fetch the element returned from the first WebDriverWait as an input to the (chained) second WebDriverWait.



To achieve this, I followed the discussion method chaining in python tried to use the use Python's lambda function through method chaining using Pipe - Python library to use infix notation in Python.



Here is my code trial:



from pipe import *
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

options = webdriver.ChromeOptions()
options.add_argument("start-maximized")
options.add_argument('disable-infobars')
driver = webdriver.Chrome(chrome_options=options, executable_path=r'C:WebDriverschromedriver.exe')
driver.get('https://www.facebook.com')
element = WebDriverWait(driver,15).until((lambda driver: driver.find_element_by_xpath("//input[@id='email']"))
| where(lambda driver: driver.find_element_by_css_selector("table[role='presentation']")))
element.send_keys("method_chaining")


I am seeing an error as:



DevTools listening on ws://127.0.0.1:52456/devtools/browser/e09c1d5e-35e3-4c00-80eb-cb642fa273ad
Traceback (most recent call last):
File "C:UsersSoma BhattacharjeeDesktopDebanjanPyProgramspython_pipe_example.py", line 24, in <module>
| where(lambda driver: driver.find_elements(By.CSS_SELECTOR,"table[role='presentation']")))
File "C:Pythonlibsite-packagespipe.py", line 58, in __ror__
return self.function(other)
File "C:Pythonlibsite-packagespipe.py", line 61, in <lambda>
return Pipe(lambda x: self.function(x, *args, **kwargs))
File "C:Pythonlibsite-packagespipe.py", line 271, in where
return (x for x in iterable if (predicate(x)))
TypeError: 'function' object is not iterable


Followed the following discussions:




  • python3 TypeError: 'function' object is not iterable


  • TypeError: 'function' object is not iterable' Python 3


Still no clue what I am missing.



Can someone guide me where I am going wrong?










share|improve this question




















  • 1





    to implement WebDriverWait for two expected_conditions... Which expected conditions?

    – Andersson
    Nov 25 '18 at 13:21











  • @Andersson good question...(in my answer I assumed presence_of_element_located and element_to_be_clickable).

    – Moshe Slavin
    Nov 25 '18 at 14:05











  • @DebanjanB In my answer, you can see some of your issues, I am sure you will have a more elegant way to implement it...

    – Moshe Slavin
    Nov 25 '18 at 14:05











  • @Andersson Thanks for looking. I have updated the question for brevity. Let me know if you need more details.

    – DebanjanB
    Nov 26 '18 at 14:20






  • 2





    The question keeps changing, quite a moving target :). The latest edit is "as the idea is to fetch the element returned from the first WebDriverWait as an input to the (chained) second WebDriverWait." - but in your attempt sample you're not using the first element, the wait is based off driver - so it's from the top of the DOM.

    – Todor Minakov
    Nov 28 '18 at 9:54
















3















I am looking to implement method chaining of Selenium WebDriverWaits.



To start with, this block of code implementing a single WebDriverWait works perfect:



from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait

options = webdriver.ChromeOptions()
options.add_argument("start-maximized")
options.add_argument('disable-infobars')
driver = webdriver.Chrome(chrome_options=options, executable_path=r'C:UtilityBrowserDriverschromedriver.exe')
driver.get('https://www.facebook.com')
element = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_xpath("//input[@id='email']"))
element.send_keys("method_chaining")


As per as my current requirement I have to implement chaining of two WebDriverWait instances as the idea is to fetch the element returned from the first WebDriverWait as an input to the (chained) second WebDriverWait.



To achieve this, I followed the discussion method chaining in python tried to use the use Python's lambda function through method chaining using Pipe - Python library to use infix notation in Python.



Here is my code trial:



from pipe import *
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

options = webdriver.ChromeOptions()
options.add_argument("start-maximized")
options.add_argument('disable-infobars')
driver = webdriver.Chrome(chrome_options=options, executable_path=r'C:WebDriverschromedriver.exe')
driver.get('https://www.facebook.com')
element = WebDriverWait(driver,15).until((lambda driver: driver.find_element_by_xpath("//input[@id='email']"))
| where(lambda driver: driver.find_element_by_css_selector("table[role='presentation']")))
element.send_keys("method_chaining")


I am seeing an error as:



DevTools listening on ws://127.0.0.1:52456/devtools/browser/e09c1d5e-35e3-4c00-80eb-cb642fa273ad
Traceback (most recent call last):
File "C:UsersSoma BhattacharjeeDesktopDebanjanPyProgramspython_pipe_example.py", line 24, in <module>
| where(lambda driver: driver.find_elements(By.CSS_SELECTOR,"table[role='presentation']")))
File "C:Pythonlibsite-packagespipe.py", line 58, in __ror__
return self.function(other)
File "C:Pythonlibsite-packagespipe.py", line 61, in <lambda>
return Pipe(lambda x: self.function(x, *args, **kwargs))
File "C:Pythonlibsite-packagespipe.py", line 271, in where
return (x for x in iterable if (predicate(x)))
TypeError: 'function' object is not iterable


Followed the following discussions:




  • python3 TypeError: 'function' object is not iterable


  • TypeError: 'function' object is not iterable' Python 3


Still no clue what I am missing.



Can someone guide me where I am going wrong?










share|improve this question




















  • 1





    to implement WebDriverWait for two expected_conditions... Which expected conditions?

    – Andersson
    Nov 25 '18 at 13:21











  • @Andersson good question...(in my answer I assumed presence_of_element_located and element_to_be_clickable).

    – Moshe Slavin
    Nov 25 '18 at 14:05











  • @DebanjanB In my answer, you can see some of your issues, I am sure you will have a more elegant way to implement it...

    – Moshe Slavin
    Nov 25 '18 at 14:05











  • @Andersson Thanks for looking. I have updated the question for brevity. Let me know if you need more details.

    – DebanjanB
    Nov 26 '18 at 14:20






  • 2





    The question keeps changing, quite a moving target :). The latest edit is "as the idea is to fetch the element returned from the first WebDriverWait as an input to the (chained) second WebDriverWait." - but in your attempt sample you're not using the first element, the wait is based off driver - so it's from the top of the DOM.

    – Todor Minakov
    Nov 28 '18 at 9:54














3












3








3








I am looking to implement method chaining of Selenium WebDriverWaits.



To start with, this block of code implementing a single WebDriverWait works perfect:



from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait

options = webdriver.ChromeOptions()
options.add_argument("start-maximized")
options.add_argument('disable-infobars')
driver = webdriver.Chrome(chrome_options=options, executable_path=r'C:UtilityBrowserDriverschromedriver.exe')
driver.get('https://www.facebook.com')
element = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_xpath("//input[@id='email']"))
element.send_keys("method_chaining")


As per as my current requirement I have to implement chaining of two WebDriverWait instances as the idea is to fetch the element returned from the first WebDriverWait as an input to the (chained) second WebDriverWait.



To achieve this, I followed the discussion method chaining in python tried to use the use Python's lambda function through method chaining using Pipe - Python library to use infix notation in Python.



Here is my code trial:



from pipe import *
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

options = webdriver.ChromeOptions()
options.add_argument("start-maximized")
options.add_argument('disable-infobars')
driver = webdriver.Chrome(chrome_options=options, executable_path=r'C:WebDriverschromedriver.exe')
driver.get('https://www.facebook.com')
element = WebDriverWait(driver,15).until((lambda driver: driver.find_element_by_xpath("//input[@id='email']"))
| where(lambda driver: driver.find_element_by_css_selector("table[role='presentation']")))
element.send_keys("method_chaining")


I am seeing an error as:



DevTools listening on ws://127.0.0.1:52456/devtools/browser/e09c1d5e-35e3-4c00-80eb-cb642fa273ad
Traceback (most recent call last):
File "C:UsersSoma BhattacharjeeDesktopDebanjanPyProgramspython_pipe_example.py", line 24, in <module>
| where(lambda driver: driver.find_elements(By.CSS_SELECTOR,"table[role='presentation']")))
File "C:Pythonlibsite-packagespipe.py", line 58, in __ror__
return self.function(other)
File "C:Pythonlibsite-packagespipe.py", line 61, in <lambda>
return Pipe(lambda x: self.function(x, *args, **kwargs))
File "C:Pythonlibsite-packagespipe.py", line 271, in where
return (x for x in iterable if (predicate(x)))
TypeError: 'function' object is not iterable


Followed the following discussions:




  • python3 TypeError: 'function' object is not iterable


  • TypeError: 'function' object is not iterable' Python 3


Still no clue what I am missing.



Can someone guide me where I am going wrong?










share|improve this question
















I am looking to implement method chaining of Selenium WebDriverWaits.



To start with, this block of code implementing a single WebDriverWait works perfect:



from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait

options = webdriver.ChromeOptions()
options.add_argument("start-maximized")
options.add_argument('disable-infobars')
driver = webdriver.Chrome(chrome_options=options, executable_path=r'C:UtilityBrowserDriverschromedriver.exe')
driver.get('https://www.facebook.com')
element = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_xpath("//input[@id='email']"))
element.send_keys("method_chaining")


As per as my current requirement I have to implement chaining of two WebDriverWait instances as the idea is to fetch the element returned from the first WebDriverWait as an input to the (chained) second WebDriverWait.



To achieve this, I followed the discussion method chaining in python tried to use the use Python's lambda function through method chaining using Pipe - Python library to use infix notation in Python.



Here is my code trial:



from pipe import *
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

options = webdriver.ChromeOptions()
options.add_argument("start-maximized")
options.add_argument('disable-infobars')
driver = webdriver.Chrome(chrome_options=options, executable_path=r'C:WebDriverschromedriver.exe')
driver.get('https://www.facebook.com')
element = WebDriverWait(driver,15).until((lambda driver: driver.find_element_by_xpath("//input[@id='email']"))
| where(lambda driver: driver.find_element_by_css_selector("table[role='presentation']")))
element.send_keys("method_chaining")


I am seeing an error as:



DevTools listening on ws://127.0.0.1:52456/devtools/browser/e09c1d5e-35e3-4c00-80eb-cb642fa273ad
Traceback (most recent call last):
File "C:UsersSoma BhattacharjeeDesktopDebanjanPyProgramspython_pipe_example.py", line 24, in <module>
| where(lambda driver: driver.find_elements(By.CSS_SELECTOR,"table[role='presentation']")))
File "C:Pythonlibsite-packagespipe.py", line 58, in __ror__
return self.function(other)
File "C:Pythonlibsite-packagespipe.py", line 61, in <lambda>
return Pipe(lambda x: self.function(x, *args, **kwargs))
File "C:Pythonlibsite-packagespipe.py", line 271, in where
return (x for x in iterable if (predicate(x)))
TypeError: 'function' object is not iterable


Followed the following discussions:




  • python3 TypeError: 'function' object is not iterable


  • TypeError: 'function' object is not iterable' Python 3


Still no clue what I am missing.



Can someone guide me where I am going wrong?







python selenium lambda method-chaining webdriverwait






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 28 '18 at 9:40







DebanjanB

















asked Nov 25 '18 at 13:05









DebanjanBDebanjanB

41k73878




41k73878








  • 1





    to implement WebDriverWait for two expected_conditions... Which expected conditions?

    – Andersson
    Nov 25 '18 at 13:21











  • @Andersson good question...(in my answer I assumed presence_of_element_located and element_to_be_clickable).

    – Moshe Slavin
    Nov 25 '18 at 14:05











  • @DebanjanB In my answer, you can see some of your issues, I am sure you will have a more elegant way to implement it...

    – Moshe Slavin
    Nov 25 '18 at 14:05











  • @Andersson Thanks for looking. I have updated the question for brevity. Let me know if you need more details.

    – DebanjanB
    Nov 26 '18 at 14:20






  • 2





    The question keeps changing, quite a moving target :). The latest edit is "as the idea is to fetch the element returned from the first WebDriverWait as an input to the (chained) second WebDriverWait." - but in your attempt sample you're not using the first element, the wait is based off driver - so it's from the top of the DOM.

    – Todor Minakov
    Nov 28 '18 at 9:54














  • 1





    to implement WebDriverWait for two expected_conditions... Which expected conditions?

    – Andersson
    Nov 25 '18 at 13:21











  • @Andersson good question...(in my answer I assumed presence_of_element_located and element_to_be_clickable).

    – Moshe Slavin
    Nov 25 '18 at 14:05











  • @DebanjanB In my answer, you can see some of your issues, I am sure you will have a more elegant way to implement it...

    – Moshe Slavin
    Nov 25 '18 at 14:05











  • @Andersson Thanks for looking. I have updated the question for brevity. Let me know if you need more details.

    – DebanjanB
    Nov 26 '18 at 14:20






  • 2





    The question keeps changing, quite a moving target :). The latest edit is "as the idea is to fetch the element returned from the first WebDriverWait as an input to the (chained) second WebDriverWait." - but in your attempt sample you're not using the first element, the wait is based off driver - so it's from the top of the DOM.

    – Todor Minakov
    Nov 28 '18 at 9:54








1




1





to implement WebDriverWait for two expected_conditions... Which expected conditions?

– Andersson
Nov 25 '18 at 13:21





to implement WebDriverWait for two expected_conditions... Which expected conditions?

– Andersson
Nov 25 '18 at 13:21













@Andersson good question...(in my answer I assumed presence_of_element_located and element_to_be_clickable).

– Moshe Slavin
Nov 25 '18 at 14:05





@Andersson good question...(in my answer I assumed presence_of_element_located and element_to_be_clickable).

– Moshe Slavin
Nov 25 '18 at 14:05













@DebanjanB In my answer, you can see some of your issues, I am sure you will have a more elegant way to implement it...

– Moshe Slavin
Nov 25 '18 at 14:05





@DebanjanB In my answer, you can see some of your issues, I am sure you will have a more elegant way to implement it...

– Moshe Slavin
Nov 25 '18 at 14:05













@Andersson Thanks for looking. I have updated the question for brevity. Let me know if you need more details.

– DebanjanB
Nov 26 '18 at 14:20





@Andersson Thanks for looking. I have updated the question for brevity. Let me know if you need more details.

– DebanjanB
Nov 26 '18 at 14:20




2




2





The question keeps changing, quite a moving target :). The latest edit is "as the idea is to fetch the element returned from the first WebDriverWait as an input to the (chained) second WebDriverWait." - but in your attempt sample you're not using the first element, the wait is based off driver - so it's from the top of the DOM.

– Todor Minakov
Nov 28 '18 at 9:54





The question keeps changing, quite a moving target :). The latest edit is "as the idea is to fetch the element returned from the first WebDriverWait as an input to the (chained) second WebDriverWait." - but in your attempt sample you're not using the first element, the wait is based off driver - so it's from the top of the DOM.

– Todor Minakov
Nov 28 '18 at 9:54












3 Answers
3






active

oldest

votes


















3














As I gather your requirement is actually to have a WebDriverWait with two expected conditions, not precisely to use method chaining and the pipe library at all cost.



You can do that, by pushing the lambda expression syntax a bit. The cleanest solution is to make it an enumerable over function calls, and get the returned value of the one you need:



element = WebDriverWait(driver, 5).until(lambda x: (x.find_element_by_xpath("//input[@id='email']"), x.find_element_by_css_selector("table[role='presentation']"))[1])


With the index you'll receive the second tuple member, e.g. the table element.



The expression can be rewritten to a boolean:



element = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_xpath("//input[@id='email']") and x.find_element_by_css_selector("table[role='presentation']"))


And you'll once again get the second element, the last part of the boolean. This implementation has some pitfalls though, when (ab)used with too complex boolean, so YMMV; I'd stick with the 1st one, the enumerable.



With this approach you get the benefits of WebDriverWait - if any of the calls in the tuple raises one of the handled exceptions there will be a rertry, etc.

There is one performance negative that comes out of this approach though - the call to the first method will be executed on every cycle, even if it has already passed successful and now the second condition is waited for.





And, here's a totally different alternative, the most clean solution - I see you're not shy to use xpath, so a pure xpath one.

As your aim is to get the table element, if and only if the input is present, this will do just that:



//table[@role='presentation' and ancestor::*//input[@id='email']]


This will select the table with the role. The other condition for it is to go up its ancestors - and the ancestor axis will go up to the top node in the DOM - and to find down from there an input element with that id attribute.



Thus if the input is still not present, the xpath will not match anything. The moment it's available, and there's also a table with that role value - it'll be returned.

Naturally, this selector can be used directly in the WebDriverWait with a single condition:



element = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_xpath("//table[@role='presentation' and ancestor::*//input[@id='email']]"))





share|improve this answer
























  • The first part of the answer was pretty much helpful. I have updated the verbatim of the requirement for more brevity. Can you have a re-look please?

    – DebanjanB
    Nov 28 '18 at 9:42



















3





+100









Edit:



I don't know if it meet your requirement, but we need to create custom construct.



@Pipe
def where(i, p):
if isinstance(i, list):
return [x for x in i if p(x)]
else:
return i if p(i.find_element_by_xpath('//ancestor::*')) else None

element = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_xpath("//input[@id='email']")
| where(lambda y: y.find_element_by_css_selector("table[role='presentation']")))

element.send_keys("method_chaining")




old:





I'm not an expert but I think maybe you misunderstand with how pipe work, by default it work to process previous value, for example



original | filter = result
[a,b,c] | select(b) = b


what you want maybe is and operator



WebDriverWait(driver,15).until(
lambda driver: driver.find_element(By.CSS_SELECTOR,"table[role='presentation']")
and driver.find_element(By.XPATH,"//input[@id='email']"))


or selenium ActionChains but no wait method, we need to extend it



from selenium.webdriver import ActionChains

class Actions(ActionChains):
def wait(self, second, condition):
element = WebDriverWait(self._driver, second).until(condition)
self.move_to_element(element)
return self

Actions(driver)
.wait(15, EC.presence_of_element_located((By.CSS_SELECTOR, "table[role='presentation']")))
.wait(15, EC.element_to_be_clickable((By.XPATH, "//input[@id='email']")))
.click()
.send_keys('method_chaining')
.perform()





share|improve this answer


























  • Thanks @ewwink I have updated the question for brevity. Can you please have a relook?

    – DebanjanB
    Nov 26 '18 at 14:22






  • 2





    hi @DebanjanB I edited the answer.

    – ewwink
    Nov 28 '18 at 13:34



















1














As your Error shows:




TypeError: 'function' object is not iterable




This is because:




where() method
Only yields the matching items of the given iterable
for example [1, 2, 3] | where(lambda x: x % 2 == 0) | concat => '2'




Hope this answers Can someone guide me where I am going wrong?



EDIT:



If you want to use pipe.where:
so you can do that with the same code you have just with some changes:
Your element var should be something like this:



element = WebDriverWait(driver,15).until((lambda driver: driver.find_elements(By.XPATH,"//input[@id='email']"))) 
| where(WebDriverWait(driver,15).until(lambda driver: driver.find_elements(By.CSS_SELECTOR,"table[role='presentation']")))


But you can't do anything with the element because it is a generator object.



The best thing to do for "to implement WebDriverWait for two expected conditions" is just to have two line's of WebDriverWait!



Like this:



presentation_element = WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.CSS_SELECTOR,"table[role='presentation']")))
email_element = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//input[@id='email']")))
email_element.send_keys("method_chaining")


Hope this helps you...



Edit2:



I think what you are looking for is to construct your one Pipe as shown here.






share|improve this answer


























  • Thanks @MosheSlavin I have updated the question for brevity. Can you please have a relook?

    – DebanjanB
    Nov 26 '18 at 14:22











  • @DebanjanB I don't know if it's possible to do but you can try constructing your one Pipe...

    – Moshe Slavin
    Nov 26 '18 at 14:49











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53467739%2fhow-to-implement-method-chaining-of-selenium-multiple-webdriverwait-in-python%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























3 Answers
3






active

oldest

votes








3 Answers
3






active

oldest

votes









active

oldest

votes






active

oldest

votes









3














As I gather your requirement is actually to have a WebDriverWait with two expected conditions, not precisely to use method chaining and the pipe library at all cost.



You can do that, by pushing the lambda expression syntax a bit. The cleanest solution is to make it an enumerable over function calls, and get the returned value of the one you need:



element = WebDriverWait(driver, 5).until(lambda x: (x.find_element_by_xpath("//input[@id='email']"), x.find_element_by_css_selector("table[role='presentation']"))[1])


With the index you'll receive the second tuple member, e.g. the table element.



The expression can be rewritten to a boolean:



element = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_xpath("//input[@id='email']") and x.find_element_by_css_selector("table[role='presentation']"))


And you'll once again get the second element, the last part of the boolean. This implementation has some pitfalls though, when (ab)used with too complex boolean, so YMMV; I'd stick with the 1st one, the enumerable.



With this approach you get the benefits of WebDriverWait - if any of the calls in the tuple raises one of the handled exceptions there will be a rertry, etc.

There is one performance negative that comes out of this approach though - the call to the first method will be executed on every cycle, even if it has already passed successful and now the second condition is waited for.





And, here's a totally different alternative, the most clean solution - I see you're not shy to use xpath, so a pure xpath one.

As your aim is to get the table element, if and only if the input is present, this will do just that:



//table[@role='presentation' and ancestor::*//input[@id='email']]


This will select the table with the role. The other condition for it is to go up its ancestors - and the ancestor axis will go up to the top node in the DOM - and to find down from there an input element with that id attribute.



Thus if the input is still not present, the xpath will not match anything. The moment it's available, and there's also a table with that role value - it'll be returned.

Naturally, this selector can be used directly in the WebDriverWait with a single condition:



element = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_xpath("//table[@role='presentation' and ancestor::*//input[@id='email']]"))





share|improve this answer
























  • The first part of the answer was pretty much helpful. I have updated the verbatim of the requirement for more brevity. Can you have a re-look please?

    – DebanjanB
    Nov 28 '18 at 9:42
















3














As I gather your requirement is actually to have a WebDriverWait with two expected conditions, not precisely to use method chaining and the pipe library at all cost.



You can do that, by pushing the lambda expression syntax a bit. The cleanest solution is to make it an enumerable over function calls, and get the returned value of the one you need:



element = WebDriverWait(driver, 5).until(lambda x: (x.find_element_by_xpath("//input[@id='email']"), x.find_element_by_css_selector("table[role='presentation']"))[1])


With the index you'll receive the second tuple member, e.g. the table element.



The expression can be rewritten to a boolean:



element = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_xpath("//input[@id='email']") and x.find_element_by_css_selector("table[role='presentation']"))


And you'll once again get the second element, the last part of the boolean. This implementation has some pitfalls though, when (ab)used with too complex boolean, so YMMV; I'd stick with the 1st one, the enumerable.



With this approach you get the benefits of WebDriverWait - if any of the calls in the tuple raises one of the handled exceptions there will be a rertry, etc.

There is one performance negative that comes out of this approach though - the call to the first method will be executed on every cycle, even if it has already passed successful and now the second condition is waited for.





And, here's a totally different alternative, the most clean solution - I see you're not shy to use xpath, so a pure xpath one.

As your aim is to get the table element, if and only if the input is present, this will do just that:



//table[@role='presentation' and ancestor::*//input[@id='email']]


This will select the table with the role. The other condition for it is to go up its ancestors - and the ancestor axis will go up to the top node in the DOM - and to find down from there an input element with that id attribute.



Thus if the input is still not present, the xpath will not match anything. The moment it's available, and there's also a table with that role value - it'll be returned.

Naturally, this selector can be used directly in the WebDriverWait with a single condition:



element = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_xpath("//table[@role='presentation' and ancestor::*//input[@id='email']]"))





share|improve this answer
























  • The first part of the answer was pretty much helpful. I have updated the verbatim of the requirement for more brevity. Can you have a re-look please?

    – DebanjanB
    Nov 28 '18 at 9:42














3












3








3







As I gather your requirement is actually to have a WebDriverWait with two expected conditions, not precisely to use method chaining and the pipe library at all cost.



You can do that, by pushing the lambda expression syntax a bit. The cleanest solution is to make it an enumerable over function calls, and get the returned value of the one you need:



element = WebDriverWait(driver, 5).until(lambda x: (x.find_element_by_xpath("//input[@id='email']"), x.find_element_by_css_selector("table[role='presentation']"))[1])


With the index you'll receive the second tuple member, e.g. the table element.



The expression can be rewritten to a boolean:



element = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_xpath("//input[@id='email']") and x.find_element_by_css_selector("table[role='presentation']"))


And you'll once again get the second element, the last part of the boolean. This implementation has some pitfalls though, when (ab)used with too complex boolean, so YMMV; I'd stick with the 1st one, the enumerable.



With this approach you get the benefits of WebDriverWait - if any of the calls in the tuple raises one of the handled exceptions there will be a rertry, etc.

There is one performance negative that comes out of this approach though - the call to the first method will be executed on every cycle, even if it has already passed successful and now the second condition is waited for.





And, here's a totally different alternative, the most clean solution - I see you're not shy to use xpath, so a pure xpath one.

As your aim is to get the table element, if and only if the input is present, this will do just that:



//table[@role='presentation' and ancestor::*//input[@id='email']]


This will select the table with the role. The other condition for it is to go up its ancestors - and the ancestor axis will go up to the top node in the DOM - and to find down from there an input element with that id attribute.



Thus if the input is still not present, the xpath will not match anything. The moment it's available, and there's also a table with that role value - it'll be returned.

Naturally, this selector can be used directly in the WebDriverWait with a single condition:



element = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_xpath("//table[@role='presentation' and ancestor::*//input[@id='email']]"))





share|improve this answer













As I gather your requirement is actually to have a WebDriverWait with two expected conditions, not precisely to use method chaining and the pipe library at all cost.



You can do that, by pushing the lambda expression syntax a bit. The cleanest solution is to make it an enumerable over function calls, and get the returned value of the one you need:



element = WebDriverWait(driver, 5).until(lambda x: (x.find_element_by_xpath("//input[@id='email']"), x.find_element_by_css_selector("table[role='presentation']"))[1])


With the index you'll receive the second tuple member, e.g. the table element.



The expression can be rewritten to a boolean:



element = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_xpath("//input[@id='email']") and x.find_element_by_css_selector("table[role='presentation']"))


And you'll once again get the second element, the last part of the boolean. This implementation has some pitfalls though, when (ab)used with too complex boolean, so YMMV; I'd stick with the 1st one, the enumerable.



With this approach you get the benefits of WebDriverWait - if any of the calls in the tuple raises one of the handled exceptions there will be a rertry, etc.

There is one performance negative that comes out of this approach though - the call to the first method will be executed on every cycle, even if it has already passed successful and now the second condition is waited for.





And, here's a totally different alternative, the most clean solution - I see you're not shy to use xpath, so a pure xpath one.

As your aim is to get the table element, if and only if the input is present, this will do just that:



//table[@role='presentation' and ancestor::*//input[@id='email']]


This will select the table with the role. The other condition for it is to go up its ancestors - and the ancestor axis will go up to the top node in the DOM - and to find down from there an input element with that id attribute.



Thus if the input is still not present, the xpath will not match anything. The moment it's available, and there's also a table with that role value - it'll be returned.

Naturally, this selector can be used directly in the WebDriverWait with a single condition:



element = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_xpath("//table[@role='presentation' and ancestor::*//input[@id='email']]"))






share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 28 '18 at 8:01









Todor MinakovTodor Minakov

6,32212136




6,32212136













  • The first part of the answer was pretty much helpful. I have updated the verbatim of the requirement for more brevity. Can you have a re-look please?

    – DebanjanB
    Nov 28 '18 at 9:42



















  • The first part of the answer was pretty much helpful. I have updated the verbatim of the requirement for more brevity. Can you have a re-look please?

    – DebanjanB
    Nov 28 '18 at 9:42

















The first part of the answer was pretty much helpful. I have updated the verbatim of the requirement for more brevity. Can you have a re-look please?

– DebanjanB
Nov 28 '18 at 9:42





The first part of the answer was pretty much helpful. I have updated the verbatim of the requirement for more brevity. Can you have a re-look please?

– DebanjanB
Nov 28 '18 at 9:42













3





+100









Edit:



I don't know if it meet your requirement, but we need to create custom construct.



@Pipe
def where(i, p):
if isinstance(i, list):
return [x for x in i if p(x)]
else:
return i if p(i.find_element_by_xpath('//ancestor::*')) else None

element = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_xpath("//input[@id='email']")
| where(lambda y: y.find_element_by_css_selector("table[role='presentation']")))

element.send_keys("method_chaining")




old:





I'm not an expert but I think maybe you misunderstand with how pipe work, by default it work to process previous value, for example



original | filter = result
[a,b,c] | select(b) = b


what you want maybe is and operator



WebDriverWait(driver,15).until(
lambda driver: driver.find_element(By.CSS_SELECTOR,"table[role='presentation']")
and driver.find_element(By.XPATH,"//input[@id='email']"))


or selenium ActionChains but no wait method, we need to extend it



from selenium.webdriver import ActionChains

class Actions(ActionChains):
def wait(self, second, condition):
element = WebDriverWait(self._driver, second).until(condition)
self.move_to_element(element)
return self

Actions(driver)
.wait(15, EC.presence_of_element_located((By.CSS_SELECTOR, "table[role='presentation']")))
.wait(15, EC.element_to_be_clickable((By.XPATH, "//input[@id='email']")))
.click()
.send_keys('method_chaining')
.perform()





share|improve this answer


























  • Thanks @ewwink I have updated the question for brevity. Can you please have a relook?

    – DebanjanB
    Nov 26 '18 at 14:22






  • 2





    hi @DebanjanB I edited the answer.

    – ewwink
    Nov 28 '18 at 13:34
















3





+100









Edit:



I don't know if it meet your requirement, but we need to create custom construct.



@Pipe
def where(i, p):
if isinstance(i, list):
return [x for x in i if p(x)]
else:
return i if p(i.find_element_by_xpath('//ancestor::*')) else None

element = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_xpath("//input[@id='email']")
| where(lambda y: y.find_element_by_css_selector("table[role='presentation']")))

element.send_keys("method_chaining")




old:





I'm not an expert but I think maybe you misunderstand with how pipe work, by default it work to process previous value, for example



original | filter = result
[a,b,c] | select(b) = b


what you want maybe is and operator



WebDriverWait(driver,15).until(
lambda driver: driver.find_element(By.CSS_SELECTOR,"table[role='presentation']")
and driver.find_element(By.XPATH,"//input[@id='email']"))


or selenium ActionChains but no wait method, we need to extend it



from selenium.webdriver import ActionChains

class Actions(ActionChains):
def wait(self, second, condition):
element = WebDriverWait(self._driver, second).until(condition)
self.move_to_element(element)
return self

Actions(driver)
.wait(15, EC.presence_of_element_located((By.CSS_SELECTOR, "table[role='presentation']")))
.wait(15, EC.element_to_be_clickable((By.XPATH, "//input[@id='email']")))
.click()
.send_keys('method_chaining')
.perform()





share|improve this answer


























  • Thanks @ewwink I have updated the question for brevity. Can you please have a relook?

    – DebanjanB
    Nov 26 '18 at 14:22






  • 2





    hi @DebanjanB I edited the answer.

    – ewwink
    Nov 28 '18 at 13:34














3





+100







3





+100



3




+100





Edit:



I don't know if it meet your requirement, but we need to create custom construct.



@Pipe
def where(i, p):
if isinstance(i, list):
return [x for x in i if p(x)]
else:
return i if p(i.find_element_by_xpath('//ancestor::*')) else None

element = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_xpath("//input[@id='email']")
| where(lambda y: y.find_element_by_css_selector("table[role='presentation']")))

element.send_keys("method_chaining")




old:





I'm not an expert but I think maybe you misunderstand with how pipe work, by default it work to process previous value, for example



original | filter = result
[a,b,c] | select(b) = b


what you want maybe is and operator



WebDriverWait(driver,15).until(
lambda driver: driver.find_element(By.CSS_SELECTOR,"table[role='presentation']")
and driver.find_element(By.XPATH,"//input[@id='email']"))


or selenium ActionChains but no wait method, we need to extend it



from selenium.webdriver import ActionChains

class Actions(ActionChains):
def wait(self, second, condition):
element = WebDriverWait(self._driver, second).until(condition)
self.move_to_element(element)
return self

Actions(driver)
.wait(15, EC.presence_of_element_located((By.CSS_SELECTOR, "table[role='presentation']")))
.wait(15, EC.element_to_be_clickable((By.XPATH, "//input[@id='email']")))
.click()
.send_keys('method_chaining')
.perform()





share|improve this answer















Edit:



I don't know if it meet your requirement, but we need to create custom construct.



@Pipe
def where(i, p):
if isinstance(i, list):
return [x for x in i if p(x)]
else:
return i if p(i.find_element_by_xpath('//ancestor::*')) else None

element = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_xpath("//input[@id='email']")
| where(lambda y: y.find_element_by_css_selector("table[role='presentation']")))

element.send_keys("method_chaining")




old:





I'm not an expert but I think maybe you misunderstand with how pipe work, by default it work to process previous value, for example



original | filter = result
[a,b,c] | select(b) = b


what you want maybe is and operator



WebDriverWait(driver,15).until(
lambda driver: driver.find_element(By.CSS_SELECTOR,"table[role='presentation']")
and driver.find_element(By.XPATH,"//input[@id='email']"))


or selenium ActionChains but no wait method, we need to extend it



from selenium.webdriver import ActionChains

class Actions(ActionChains):
def wait(self, second, condition):
element = WebDriverWait(self._driver, second).until(condition)
self.move_to_element(element)
return self

Actions(driver)
.wait(15, EC.presence_of_element_located((By.CSS_SELECTOR, "table[role='presentation']")))
.wait(15, EC.element_to_be_clickable((By.XPATH, "//input[@id='email']")))
.click()
.send_keys('method_chaining')
.perform()






share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 28 '18 at 13:32

























answered Nov 26 '18 at 13:48









ewwinkewwink

11.7k22238




11.7k22238













  • Thanks @ewwink I have updated the question for brevity. Can you please have a relook?

    – DebanjanB
    Nov 26 '18 at 14:22






  • 2





    hi @DebanjanB I edited the answer.

    – ewwink
    Nov 28 '18 at 13:34



















  • Thanks @ewwink I have updated the question for brevity. Can you please have a relook?

    – DebanjanB
    Nov 26 '18 at 14:22






  • 2





    hi @DebanjanB I edited the answer.

    – ewwink
    Nov 28 '18 at 13:34

















Thanks @ewwink I have updated the question for brevity. Can you please have a relook?

– DebanjanB
Nov 26 '18 at 14:22





Thanks @ewwink I have updated the question for brevity. Can you please have a relook?

– DebanjanB
Nov 26 '18 at 14:22




2




2





hi @DebanjanB I edited the answer.

– ewwink
Nov 28 '18 at 13:34





hi @DebanjanB I edited the answer.

– ewwink
Nov 28 '18 at 13:34











1














As your Error shows:




TypeError: 'function' object is not iterable




This is because:




where() method
Only yields the matching items of the given iterable
for example [1, 2, 3] | where(lambda x: x % 2 == 0) | concat => '2'




Hope this answers Can someone guide me where I am going wrong?



EDIT:



If you want to use pipe.where:
so you can do that with the same code you have just with some changes:
Your element var should be something like this:



element = WebDriverWait(driver,15).until((lambda driver: driver.find_elements(By.XPATH,"//input[@id='email']"))) 
| where(WebDriverWait(driver,15).until(lambda driver: driver.find_elements(By.CSS_SELECTOR,"table[role='presentation']")))


But you can't do anything with the element because it is a generator object.



The best thing to do for "to implement WebDriverWait for two expected conditions" is just to have two line's of WebDriverWait!



Like this:



presentation_element = WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.CSS_SELECTOR,"table[role='presentation']")))
email_element = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//input[@id='email']")))
email_element.send_keys("method_chaining")


Hope this helps you...



Edit2:



I think what you are looking for is to construct your one Pipe as shown here.






share|improve this answer


























  • Thanks @MosheSlavin I have updated the question for brevity. Can you please have a relook?

    – DebanjanB
    Nov 26 '18 at 14:22











  • @DebanjanB I don't know if it's possible to do but you can try constructing your one Pipe...

    – Moshe Slavin
    Nov 26 '18 at 14:49
















1














As your Error shows:




TypeError: 'function' object is not iterable




This is because:




where() method
Only yields the matching items of the given iterable
for example [1, 2, 3] | where(lambda x: x % 2 == 0) | concat => '2'




Hope this answers Can someone guide me where I am going wrong?



EDIT:



If you want to use pipe.where:
so you can do that with the same code you have just with some changes:
Your element var should be something like this:



element = WebDriverWait(driver,15).until((lambda driver: driver.find_elements(By.XPATH,"//input[@id='email']"))) 
| where(WebDriverWait(driver,15).until(lambda driver: driver.find_elements(By.CSS_SELECTOR,"table[role='presentation']")))


But you can't do anything with the element because it is a generator object.



The best thing to do for "to implement WebDriverWait for two expected conditions" is just to have two line's of WebDriverWait!



Like this:



presentation_element = WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.CSS_SELECTOR,"table[role='presentation']")))
email_element = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//input[@id='email']")))
email_element.send_keys("method_chaining")


Hope this helps you...



Edit2:



I think what you are looking for is to construct your one Pipe as shown here.






share|improve this answer


























  • Thanks @MosheSlavin I have updated the question for brevity. Can you please have a relook?

    – DebanjanB
    Nov 26 '18 at 14:22











  • @DebanjanB I don't know if it's possible to do but you can try constructing your one Pipe...

    – Moshe Slavin
    Nov 26 '18 at 14:49














1












1








1







As your Error shows:




TypeError: 'function' object is not iterable




This is because:




where() method
Only yields the matching items of the given iterable
for example [1, 2, 3] | where(lambda x: x % 2 == 0) | concat => '2'




Hope this answers Can someone guide me where I am going wrong?



EDIT:



If you want to use pipe.where:
so you can do that with the same code you have just with some changes:
Your element var should be something like this:



element = WebDriverWait(driver,15).until((lambda driver: driver.find_elements(By.XPATH,"//input[@id='email']"))) 
| where(WebDriverWait(driver,15).until(lambda driver: driver.find_elements(By.CSS_SELECTOR,"table[role='presentation']")))


But you can't do anything with the element because it is a generator object.



The best thing to do for "to implement WebDriverWait for two expected conditions" is just to have two line's of WebDriverWait!



Like this:



presentation_element = WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.CSS_SELECTOR,"table[role='presentation']")))
email_element = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//input[@id='email']")))
email_element.send_keys("method_chaining")


Hope this helps you...



Edit2:



I think what you are looking for is to construct your one Pipe as shown here.






share|improve this answer















As your Error shows:




TypeError: 'function' object is not iterable




This is because:




where() method
Only yields the matching items of the given iterable
for example [1, 2, 3] | where(lambda x: x % 2 == 0) | concat => '2'




Hope this answers Can someone guide me where I am going wrong?



EDIT:



If you want to use pipe.where:
so you can do that with the same code you have just with some changes:
Your element var should be something like this:



element = WebDriverWait(driver,15).until((lambda driver: driver.find_elements(By.XPATH,"//input[@id='email']"))) 
| where(WebDriverWait(driver,15).until(lambda driver: driver.find_elements(By.CSS_SELECTOR,"table[role='presentation']")))


But you can't do anything with the element because it is a generator object.



The best thing to do for "to implement WebDriverWait for two expected conditions" is just to have two line's of WebDriverWait!



Like this:



presentation_element = WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.CSS_SELECTOR,"table[role='presentation']")))
email_element = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//input[@id='email']")))
email_element.send_keys("method_chaining")


Hope this helps you...



Edit2:



I think what you are looking for is to construct your one Pipe as shown here.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 26 '18 at 14:48

























answered Nov 25 '18 at 13:29









Moshe SlavinMoshe Slavin

1,6212821




1,6212821













  • Thanks @MosheSlavin I have updated the question for brevity. Can you please have a relook?

    – DebanjanB
    Nov 26 '18 at 14:22











  • @DebanjanB I don't know if it's possible to do but you can try constructing your one Pipe...

    – Moshe Slavin
    Nov 26 '18 at 14:49



















  • Thanks @MosheSlavin I have updated the question for brevity. Can you please have a relook?

    – DebanjanB
    Nov 26 '18 at 14:22











  • @DebanjanB I don't know if it's possible to do but you can try constructing your one Pipe...

    – Moshe Slavin
    Nov 26 '18 at 14:49

















Thanks @MosheSlavin I have updated the question for brevity. Can you please have a relook?

– DebanjanB
Nov 26 '18 at 14:22





Thanks @MosheSlavin I have updated the question for brevity. Can you please have a relook?

– DebanjanB
Nov 26 '18 at 14:22













@DebanjanB I don't know if it's possible to do but you can try constructing your one Pipe...

– Moshe Slavin
Nov 26 '18 at 14:49





@DebanjanB I don't know if it's possible to do but you can try constructing your one Pipe...

– Moshe Slavin
Nov 26 '18 at 14:49


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53467739%2fhow-to-implement-method-chaining-of-selenium-multiple-webdriverwait-in-python%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

Calculate evaluation metrics using cross_val_predict sklearn

Insert data from modal to MySQL (multiple modal on website)