I have 10 links in a list, upon clicked,which will open a new window. Different links would yield different set of pages, however i have 3 common elements for all 10 links.
Following is the function example.
def handle_window(self):
self.driver.go_to_new_window()
try: # block 1
elements = ["element1", "element2", "element3"]
for element in elements:
try: #block 2
self.assertEqual(True, is_exist_in_new_window(element)))
except:
continue
except:
# in 'try block 2' if assert yields true at least once,
print 'passed'
# if it fails for all 3 elements,
print 'failed'
self.driver.close_current_window()
self.driver.go_to_main_window()
I am not sure how do i evaluate the results of 'try block 2', so that to do some action in block 1.
Any possible solutions ?
If "element1", etc. are meant to be CSS selectors, the most efficient way would be:
elements = ["element1", "element2", "element3"]
self.assertTrue(exists_in_new_window(",".join(elements)))
(I've renamed is_exist_in_new_window to exists_in_new_window.) The , operator in CSS means "or". So the CSS selector passed to exists_in_new_window means you are looking for "element1" or "element2" or "element3". Doing it this way will need one round-trip between the Selenium client and the browser, no matter what. Note that the code above is not meant to handle meaningfully the case where elements is a zero-length list.
With XPath selectors you could use the | operator to perform a similar transformation. In this case, I would want to additionally use parentheses to preserve semantics of the individual selectors so something like "(" + ")|(".join(elements) + ")". (I believe the semantics issue does not arise in CSS due to CSS' very rigid syntax.)
In the more general case where it is not possible to combine the search criteria into one expression, one can fall back onto alecxe's suggestion:
elements = ["element1", "element2", "element3"]
self.assertTrue(any((exists_in_new_window(element) for element in elements)))
This method causes a minimum of min(1, len(elements)) round-trips between the Selenium client and the browser and a maximum of len(elements) depending on what is present on the page.
You can use any() to check if at least one element existed on a page:
elements = ["element1", "element2", "element3"]
value = any((is_exist_in_new_window(element) for element in elements))
self.assertTrue(value)
This code assumes is_exist_in_new_window() returns True or False.
Hope that helps.
Related
my #g = (1,2,3,4);
say reduce {is-prime}, #g; # ==> gives error
say reduce {is-prime *}, #g; #==> gives error
say reduce {is-prime}, (1,2,3,4); # ==> gives error
say so is-prime #g.all; # ==> gives error
How to check if all elements of list are prime in Raku?
The answers above are all helpful, but they fail to explain why your solution does not work. Basically reduce is not going to apply a function (in your case, is-prime) to every member of a list. You want map for that. The error says
Calling is-prime() will never work with signature of the proto ($, *%)
Because reduce expects an infix, thus binary, function, or a function with two arguments; what it does is to apply them to the first pair of elements, then to the result and the third element, and so on. Last statement does not work for a similar reason: you are calling is-prime with a list argument, not a single argument.
You're basically asking: are there any elements in this list which are not prime? I would write that as:
say "not all prime" if #g.first: !*.is-prime;
Please note though, that apparently 1 is not considered prime according to the is-prime function:
say 1.is-prime; # False
so the first would trigger on the 1 in your example, not on the 4.
There are of course may ways to do this. A very explicit way is using a for loop:
for #g -> $g {
if $g.is-prime {
say $g;
}
}
Or with a grep (you could leave the $_ implicit):
#g.grep({ $_.is-prime }).say
Both above are assuming you really want to filter the primes out. Of course you can also really check each number and get a boolean:
#g.map({ .is-prime }).say
There is a big problem with this:
say reduce {is-prime}, #g;
You created a lambda:
{ }
The only thing it does is calls a function:
is-prime
You didn't give the function any arguments though.
Is it just supposed to guess what the arguments should be?
If you meant to pass in is-prime as a reference, you should have used &is-prime rather than {is-prime}.
Of course that still wouldn't have worked.
The other problem is that reduce operates by recursively combining values.
It can't do that if it operates on one argument at a time.
The bare block lambda {}, takes zero or one argument, not two or more.
reduce is often combined with map.
It happens so often that there is a Wikipedia page about MapReduce.
say ( map &is-prime, #g ==> reduce { $^a and $^b } );
# False
say ( map &is-prime, 2,3,5 ==> reduce { $^a and $^b } );
# True
I wrote it that way so that map would be in the line before reduce, but perhaps it would be more clear this way:
say reduce {$^a and $^b}, map &is-prime, 2,3,5;
# True
reduce with an infix operator is so common that there is a shorter way to write it.
say [and] map &is-prime, 2,3,5;
# True
Of course it would be better to just find the first value that isn't prime, and say the inverse.
Since if there is even a single value that isn't prime that would mean they can't all be primes.
You have to be careful though, as you may think something like this would always work:
not #g.first: !*.is-prime;
It does happen to work for the values you gave it, but may not always.
first returns Nil if it can't find the value.
not (2,3,5).first: !*.is-prime;
# not Nil === True
not (2,3,4).first: !*.is-prime;
# not 4 === False
not (2,3,0,4).first: !*.is-prime;
# not 0 === True
That last one returned 0 which when combined with not returns True.
You could fix this with defined.
not defined (2,3,0,4).first: !*.is-prime;
# False
This only works if first wouldn't return an undefined element that happens to be in the list.
(Int,Any).first: Real
# Int
defined (Int,Any).first: Real
# False
You could fix that by asking for the index instead of the value.
You of course still need defined.
(Int,Any).first: :k, Real
# 0
defined (Int,Any).first: :k, Real
# True
The other way to fix it is to just use grep.
not (2,3,0,4).grep: !*.is-prime;
# not (0,4) === False
Since grep always returns a List, you don't have to worry about checking for 0 or undefined elements.
(A List is True if it contains any elements, no matter what the values.)
grep is smart enough to know that if you coerce to Bool that it can stop upon finding the first value.
So it short-circuits the same as if you had used first.
This results in some fairly funky code, with those two negating operators. So it should be put into a function.
sub all-prime ( +#_ ) {
# return False if we find any non-prime
not #_.grep: !*.is-prime
# grep short-circuits in Bool context, so this will stop early
}
This could still fail if you give it something weird
all-prime 2,3,5, Date.today;
# ERROR: No such method 'is-prime' for invocant of type 'Date'
If you care, add some error handling.
sub all-prime ( +#_ ) {
# return Nil if there was an error
CATCH { default { return Nil }}
# return False if we find any non-prime
not #_.grep: !*.is-prime
}
all-prime 2,3,5, Date.today;
# Nil
use the all junction:
say so all #g».is-prime; # False
How can I only keep words / numbers from list?
I use the follow script and I want to count unique payment methods, but I have unwanted values on my list
I also tried to use "word of item" but this is not working
I try different version of the script but always having an issue
set PaymentMethods to {}
set UniquePaymentMethods to {}
set walletPayement to {}
set mobilePayemnt to {}
tell application "Safari"
set PaymentMethods to do JavaScript "var outPut=[]; var arr=document.getElementsByClassName('sortable Summary');for (var i in arr) {outPut.push(arr[i].innerHTML)};outPut;" in current tab of window 1
end tell
repeat with x from 1 to count of items of PaymentMethods
set n to item x of PaymentMethods
if n is in PaymentMethods and n is not in UniquePaymentMethods and n does not contain "<a href=\"/finance/Support.ok" and n does not contain "Safari" and n does not contain "None" then set end of UniquePaymentMethods to n
end repeat
e.g of the result :
{"
PayPal
", "
MasterCard (999)
", "
MasterCard (888)
", application "Safari"}
It's good that you're generally mindful about supplying a sample of the input, as you've done here with the list that I presume relates to PaymentMethods. But don't forget to also provide the output you want to get back at the end. It took me a while to realise "keep words / numbers from list" was actually referring to items of class text (or string), which was about my fifth interpretation of what was being asked.
Your solution appears to do what you want, but it doesn't really because you've had to use that very case-specific set of conditionals, i.e.:
if n is in PaymentMethods ¬
and n is not in UniquePaymentMethods ¬
and n does not contain ("<a href=\"/finance/Support.ok") ¬
and n does not contain ("Safari") ¬
and n does not contain "None" then ¬
set end of UniquePaymentMethods to n
Without that, the item application "Safari", for instance, would simply be coerced into class text, which would return "Safari" in your resulting list.
So, while your request was to filter a list's data types to contain only text class items, your proposed fix, i.e.:
set n to item x of PaymentMethods as text
doesn't isolate text items; it coerces items of any class into text.
The way to filter a list by class type is to use this syntax:
get every [class] in [list]
where [class] is the AppleScript class you want to keep (discarding any items not of this class), and [list] is the list (or variable that references a list), e.g.:
every text in {1, "Hello", true, missing value, "2", text, number, pi}
--> {"Hello", "2"}
every number in {1, "Hello", true, missing value, "2", text, number, pi}
--> {1, 3.14159265359}
every application in {"PayPal", "MasterCard (999)", "MasterCard (888)", application "Safari"}
--> {application "Safari"}
every text in {"PayPal", "MasterCard (999)", "MasterCard (888)", application "Safari"}
--> {"PayPal", "MasterCard (999)", "MasterCard (888)"}
But, there's a lot you can do to simplify your script by having the initial JavaScript code do the heavy lifting so it returns a cleaner list of items that will be simpler for AppleScript to process, or eliminate any need for additional processing.
Your list items have a lot of whitespace in them. In JS, use trim().
Your AppleScript conditionals reference "innerHTML property without ever wanting to use any actual HTML. You've been consistently interested only in the text that gets printed on your webpage. Therefore, in JS, experiment with innerText applied to the right HTML element and you'll probably be able to isolate the payment methods text straight away.
You appear to want your list to contain unique items. In JS, use sets, which are basically arrays with unique items.
Implementing these three recommendations, together with the above method of filtering by text class, would look something like:
tell application "Safari" to tell document 1 to tell (do JavaScript "
[...new Set( document.getElementsByClassName('sortable Summary') )]
.map( x => x.innerText.trim() );") ¬
to set PaymentMethods to every text
As I don't know what your webpage source looks like, you may need to make slight adjustments to how you want to transform innerText besides trim(), and/or consider whether getElementsByClassName('sortable Summary') is the best way to get access to the parts of the HTML DOM tree you require. querySelectorAll() is a much more powerful method to use, which I have mentioned before.
Found it, need to add the kind for each item
set n to item x of PaymentMethods as text
I am writing a program to create a list from a spreadsheet based on a position value in another cell. So my code looks like
for j in xrange(1,13):
for sheet in wb.sheets():
for i in xrange(1,12*15):
team=sheet.cell(i,0)
position=sheet.cell(i,2)
games=sheet.cell(i,23)
if re.match(owner[j], str(team.value)) and (not re.findall('Defense' or 'K,' or 'KFG' or 'KKO', str(position.value))):
try:
list.append(int(games.value))
except ValueError:
list.append(0)
else:
pass
print list
list=[]
So the goal of this is to append to a list when a row matches owner in the first column, and not Defense K, KFG KKO in the position column.
Unfortunately, the values for K, KFG and KKO all show
up in my lists, but the Defense values properly do not. How can I
ensure the other filtering criteria are met?
As a side note, these positions are in amongst other bits of text so
the search() is used here instead of match().
"Defense" is a 'truthy' value, so the result of:
'Defense' or 'K,' or 'KFG' or 'KKO'
is 'Defense'.
Therefore, the condition you have is no different from:
re.match(owner[j], str(team.value)) and (not re.findall('Defense', str(position.value)))
If you want alternatives in a regex, use | in the pattern:
re.match(owner[j], str(team.value)) and (not re.findall('Defense|K,|KFG|KKO', str(position.value)))
I have the following repeated piece of the web-page:
<div class="txt ext">
<strong class="param">param_value1</strong>
<strong class="param">param_value2</strong>
</div>
I would like to extract separately values param_value1 and param_value2 using Xpath. How can I do it?
I have tried the following constructions:
'//strong[#class="param"]/text()[0]'
'//strong[#class="txt ext"]/strong[#class="param"][0]/text()'
'//strong[#class="param"]'
none of which returned me separately param_value1 and param_value2.
P.S. I am using Python 2.7 and the latest version of Scrapy.
Here is my testing code:
test_content = '<div class="txt ext"><strong class="param">param_value1</strong><strong class="param">param_value2</strong></div>'
sel = HtmlXPathSelector(text=test_content)
sel.select('//div/strong[#class="param"]/text()').extract()[0]
sel.select('//div/strong[#class="param"]/text()').extract()[1]
// means descendant or self. You are selecting any strong element in any context. [...] is a predicate which restricts your selection according to some boolean test. There is no strong element with a class attribute which equals txt ext, so you can exclude your second expression.
Your last expression will actually return a node-set of all the strong elements which have a param attribute. You can then extract individual nodes from the node set (use [1], [2]) and then get their text contents (use text()).
Your first expression selects the text contents of both nodes but it's also wrong. It's in the wrong place and you can't select node zero (it doesn't exist). If you want the text contents of the first node you should use:
//strong[#class="param"][1]/text()
and you can use
//strong[#class="param"][2]/text()
for the second text.
I'm trying to match values of a list to a regex pattern. If the particular value within the list matches, I'll append it to a different list of dicts. If the above mentioned value does not match, I want to remove the value from the list.
import subprocess
def list_installed():
rawlist = subprocess.check_output(['yum', 'list', 'installed']).splitlines()
#print rawlist
for each_item in rawlist:
if "[\w86]" or \
"noarch" in each_item:
print each_item #additional stuff here to append list of dicts
#i haven't done the appending part yet
#the list of dict's will be returned at end of this funct
else:
remove(each_item)
list_installed()
The end goal is to eventually be able to do something similar to:
nifty_module.tellme(installed_packages[3]['version'])
nifty_module.dosomething(installed_packages[6])
Note to gnu/linux users going wtf:
This will eventually grow into a larger sysadmin frontend.
Despite the lack of an actual question in your post, I'll make a couple of comments.
You have a problem here:
if "[\w86]" or "noarch" in each_item:
It's not interpreted the way you think of it and it always evaluates to True. You probably need
if "[\w86]" in each_item or "noarch" in each_item:
Also, I'm not sure what you are doing, but in case you expect that Python will do regex matching here: it won't. If you need that, look at re module.
remove(each_item)
I don't know how it's implemented, but it probably won't work if you expect it to remove the element from rawlist: remove won't be able to actually access the list defined inside list_installed. I'd advise to use rawlist.remove(each_item) instead, but not in this case, because you are iterating over rawlist. You need to re-think the procedure a little (create another list and append needed elements to it instead of removing, for example).