selenium - can WebDriverWait().until(myFunc) use functions outside of the WebDriver? - python

Is it possible to call a function outside of the WebDriver in the .until? No matter what I try, I get the exception:
Exception: 'WebDriver' object has no attribute 'verifyObj_tag'.
I have a class called 'ad_selenium' and all calls to selenium are encapsulated within the library. The explicitWait function I wrote is trying to use another class method in the .until:
def explicitWait(self,tag_name,search_for,element=None,compare='contains',seconds=20):
element = WebDriverWait(self.__WD, seconds).until( lambda self: \
self.verifyObj_tag(tag_name,search_for,element=element,compare=compare))
I've tried all sorts of combinations of lambda functions and function varaibles like:
def explicitWait(self,tag_name,search_for,element=None,compare='contains',seconds=20):
x = self.verifyObj_tag
element = WebDriverWait(self.__WD, seconds).until( lambda x: \
x(tag_name,search_for,element=element,compare=compare))
Looking at the code inside selenium/webdriver/support/wait.py, it looks like it always passes webriver to the method passed in the until:
def until(self, method, message=''):
while(True):
try:
value = method(self._driver) #<<--webdriver passed here
if value:
return value
except self._ignored_exceptions:
pass
Any ideas on how to make that work?

You need to let it pass the driver as an argument:
element = WebDriverWait(self.__WD, seconds).until(lambda driver: \
self.verifyObj_tag(tag_name, search_for, element=element, compare=compare))

Related

Why is this code reporting function object is not scriptable

#pytest.fixture
def settings():
with open('../config.yaml') as yaml_stream:
return yaml.load(stream=yaml_stream)
#pytest.fixture
def viewers(settings):
try:
data = requests.get(settings['endpoints']['viewers']).json()
return data[0]['viewers']
except Exception:
print('ERROR retrieving viewers')
raise(SystemExit)
#pytest.fixture
def viewers_buffer_health(viewers):
print(viewers)
viewers_with_buffer_health = {}
for viewer in viewers:
try:
data = requests.get(settings['endpoints']['node_buffer_health']).replace('<NODE_ID>', viewer)
except Exception as e:
print('ERROR retrieving buffer_health for {}'.format(viewer))
raise(SystemExit)
viewers_with_buffer_health[viewer] = data[0]['avg_buffer_health']
return viewers_with_buffer_health
The fixture viewers_buffer_health is failing all the time on the requests because 'function' object is not subscriptable
Other times I have seen such error it has been because I was calling a variable and a function by the same name, but it's not the case (or I'm blind at all).
Although it shouldn't matter, the output of viewers is a list like ['a4a6b1c0-e98a-42c8-abe9-f4289360c220', '152bff1c-e82e-49e1-92b6-f652c58d3145', '55a06a01-9956-4d7c-bfd0-5a2e6a27b62b']
Since viewers_buffer_health() doesn't have a local definition for settings it is using the function defined previously. If it is meant to work in the same manner as viewers() then you will need to add a settings argument to its current set of arguments.
settings is a function.
data = requests.get(settings()['endpoints']['node_buffer_health']).replace('<NODE_ID>', viewer)

clickAndHold is not working in Selenium webdriver (python)

I have a function with actions like click, focus, etc. and works fine, but I need the function clickAndHold and returns an error when I try to run test.
This is a piece of code of my function:
def start_action(self, selector, action, value):
browser = self.d
element = browser.find_element_by_xpath(selector)
if action == 'clickAndHold':
actions = ActionChains(browser)
actions.clickAndHold(element)
actions.perform()
And this is the error:
AttributeError: 'ActionChains' object has no attribute 'clickAndHold'
Please help me!
In Python this method called click_and_hold(). Try to use it instead of clickAndHold()
Note that in Python in most cases snake_case used instead of camelCase

call method of lambda function from another lambda function - Python

I am able to call lambda function from another lambda function but by default it goes to handler method. How do I invoke some other method defined in it?
Suppose there is lambda function master.py, which will have common methods which can be used by other lambda functions so that I don't have to write them again and again in every function. Now I want to call methods of master.py (lets say getTime(), authenticateUser() etc) from other lambda functions.
Basically I want to keep a lambda function which will have common methods which can be used by other lambda functions.
Any help is appreciated.
Below is the code I have tried to call one lambda function from another (i have taken code from this question) but it goes to handler() method:
lambda function A
def handler(event,context):
params = event['list']
return {"params" : params + ["abc"]}
lambda function B invoking A
import boto3
import json
lambda_client = boto3.client('lambda')
a=[1,2,3]
x = {"list" : a}
invoke_response = lambda_client.invoke(FunctionName="functionA",
InvocationType='RequestResponse',
Payload=json.dumps(x))
print (invoke_response['Payload'].read())
Output
{
"params": [1, 2, 3, "abc"]
}
You can pass the data needed to run your desired lambda function method within the event parameter upon calling invoke. If you include the following code in the top of your lambda_handler from the lambda function with the method you would like to invoke.
def lambda_handler(event, context):
"""
Intermediary method that is invoked by other lambda functions to run methods within this lambda
function and return the results.
Parameters
----------
event : dict
Dictionary specifying which method to run and the arguments to pass to it
{function: "nameOfTheMethodToExecute", arguments: {arg1: val1, ..., argn: valn}}
context : dict
Not used
Returns
-------
object : object
The return values from the executed function. If more than one object is returned then they
are contained within an array.
"""
if "function" in event:
return globals()[event["function"]](**event["arguments"])
else:
# your existing lambda_handler code...
Then, to call the method and get the return values from your other lambda function using the following method invoke.
import json
# returns the full name for a lambda function from AWS based on a given unique part
getFullName = lambda lambdaMethodName: [method["FunctionName"] for method in lambda_client.list_functions()["Functions"] if lambdaMethodName in method["FunctionName"]][0]
# execute a method in a different lambda function and return the results
def invoke(lambda_function, method_name, params):
# wrap up the method name to run and its parameters
payload = json.dumps({"function": method_name, "arguments": params})
# invoke the function and record the response
response = lambda_client.invoke(FunctionName=getFullName(lambda_function), InvocationType='RequestResponse', Payload=payload)
# parse the return values from the response
return json.loads(response["Payload"].read())
[rtn_val_1, rtn_val_2] = invoke("fromLambdaA", "desiredFunction", {arg1: val1, arg2: val2})
Note your lambda policy attached to the function that is invoking the other lambda function will need two polices: "lambda:ListFunctions" and "lambda:InvokeFunction"

Python Tornado get URL arguments

I'm trying to inspect a request's argument before the get() is invoked. I have a route which is described as so:
user_route = r"/users/key=(?P<key>\w+)"
app = web.Application([
web.URLSpec(user_route, user_manager.UserHandler), ..])
Next, (in the handler) prepare() is used to inspect the request before get().
def prepare(self):
# inspect request arguments
print(self.request.arguments) # prints "{}"
The problem I'm having is that I cannot access the arguments from prepare(). The last statement prints an empty dict. My get() successfully uses the arguments as they are passed in the function like this:
def get(self, key):
print(key) #works
How do I access arguments in prepare()? I have also tried self.argument('key') which gives an error "400 GET .... Missing argument key", but requested URL does have a key argument in it.
In your code key is not a GET-argument, it's a part of a path. tornado.we.URLSpec passes any capturing groups in the regex into the handler’s get/post/etc methods as arguments.
tornado.web.RequestHandler has RequestHandler.path_args and RequestHandler.path_kwargs which contain the positional and keyword arguments from URLSpec. Those are available in prepare method:
def prepare(self):
# inspect request arguments
print(self.path_kwargs) # prints {"key": "something"}
As Gennady Kandaurov mentioned, you passed the key as a part of the we.URLSpec path and you can access it using Tornado's self.path_kwargs. If you wanted to pass it as an argument you could used RequestHandler.get_argument to get the argument on your get method and use self.request.arguments on your prepare method to access it as your initial intention.
Your code could be as follow:
class Application(tornado.web.Application):
def __init__(self):
user_route = r"/users"
app = tornado.web.Application([
tornado.web.url(user_route, user_manager.UserHandler), ..])
class UserHandler(tornado.web.RequestHandler):
def get(self):
key = self.get_argument('key')
print(key)
def prepare(self):
# inspect request arguments
print(self.request.arguments)
Please let me know if you have any further question.
It's generally bad to use a character like = in a URL path fragment, since they are generally used for query arguments. Either don't use it:
`r"/users/(?P<key>\w+)"`
or turn it into a proper query argument
`r"/users/\?key=(?P<key>\w+)"`
Otherwise it's confusing for a maintainer to try to figure out which scheme you intended to use (did you really want to route a path fragment called /key%3D\w+? Or did you really mean you wanted a query arg and forgot the ??)
In any case, for URL path fragment matching ("slug-matching"), using argument unpacking can let you access them in the handler too, without having to invoke path_kwargs:
# `r"/users/(?P<key>\w+)"`
class Handler(RequestHandler):
def get(self, **kwargs):
key = kwargs.get('key')
# I prefer dict.get() here, since if you change the `+` to a `*`,
# it's possible that no key was supplied, and kwargs['key']
# will throw a KeyError exception
If you intended to use a query argument for key, then #afxentios's answer is appropriate. (You can also use self.get_query_argument('key') which will explicitly only look for query arguments in the URL (whereas get_argument also checks in the request BODY for a www-url-encoded argument (such as if you POST)).

Python - safe & elegant way to set a variable from function that may return None

I'm looking for a more elegant way of declaring a variable value where the function may return None and there are chained methods following the function call.
In the example below I am using BeautifulSoup to pass an HTML doc and if the element I am looking for is not found, the initial function call returns None. The chained methods then break the code because .string is not a method of None object.
Which all makes sense, but I'm wondering if there's a cleaner way to write these variable declarations that won't break on a None value.
# I want to do something like this but it throws error if soup.find returns
# none because .string is not a method of None.
title = soup.find("h1", "article-title").string or "none"
# This works but is both ugly and inefficient
title = "none" if soup.find("h1", "article-title") is None else soup.find("h1", "article-title").string
# So instead I'm using this which feels clunky as well
title = soup.find("h1", "article-title")
title = "none" if title is None else title.string
Any better way?
I like Shashank's answer, but this might work for you as well:
class placeholder:
string = "none"
title = (soup.find("h1", "article-title") or placeholder).string
This behavior of Beautiful Soup really annoys me as well. Here's my solution: http://soupy.readthedocs.org/en/latest/
This smooths over lots of edge cases in BeautifulSoup, allowing you to write queries like
dom.find('h1').find('h2').find('a')['href'].orelse('not found').val()
Which returns what you're looking for if it exists, or 'not found' otherwise.
The general strategy in soupy is to wrap the data you care about in thin wrapper classes. A simple example of such a wrapper:
class Scalar(object):
def __init__(self, val):
self._val = val
def __getattr__(self, key):
return Scalar(getattr(self._val, key, None))
def __call__(self, *args, **kwargs):
return Scalar(self._val(*args, **kwargs))
def __str__(self):
return 'Scalar(%s)' % self._val
s = Scalar('hi there')
s.upper() # Scalar('HI THERE')
s.a.b.c.d # Scalar(None)
If you want to be fancy about it, the mathematical property that lets you safely chain things forever is closure (ie methods return instances of the same type). Lots of BeautifulSoup methods don't have this property, which is what soupy addresses.
You can use the getattr built-in function to provide a default value in case the desired attribute is not found within a given object:
title = getattr(soup.find("h1", "article-title"), "string", "none")
Alternatively, you can use a try statement:
try:
title = soup.find("h1", "article-title").string
except AttributeError:
title = "none"
The first method is more elegant in my opinion.

Categories

Resources