How to implement method chaining of Selenium multiple WebDriverWait in Python
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
|
show 1 more comment
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
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 assumedpresence_of_element_located
andelement_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 offdriver
- so it's from the top of the DOM.
– Todor Minakov
Nov 28 '18 at 9:54
|
show 1 more comment
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
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
python selenium lambda method-chaining webdriverwait
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 assumedpresence_of_element_located
andelement_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 offdriver
- so it's from the top of the DOM.
– Todor Minakov
Nov 28 '18 at 9:54
|
show 1 more comment
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 assumedpresence_of_element_located
andelement_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 offdriver
- 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
|
show 1 more comment
3 Answers
3
active
oldest
votes
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']]"))
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
add a comment |
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()
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
add a comment |
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.
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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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']]"))
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
add a comment |
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']]"))
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
add a comment |
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']]"))
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']]"))
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
add a comment |
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
add a comment |
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()
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
add a comment |
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()
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
add a comment |
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()
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()
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
add a comment |
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
add a comment |
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.
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
add a comment |
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.
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
add a comment |
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.
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.
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
add a comment |
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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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
andelement_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