Skip to content

Commit d095cd2

Browse files
Milan Falešníklukeis
authored andcommitted
[py] Applied some DRY and extracted out the keys_to_typing()
file_detector_context and custom file_detector * You can pass custom file_detector right in the constructor, default behaviour is unaltered. * file_detector_context context manager to safely change file detectors in limited contexts. Signed-off-by: Luke Inman-Semerau <[email protected]>
1 parent c46671f commit d095cd2

File tree

5 files changed

+67
-49
lines changed

5 files changed

+67
-49
lines changed

py/selenium/webdriver/common/action_chains.py

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
The ActionChains implementation,
2020
"""
2121
from selenium.webdriver.remote.command import Command
22-
from selenium.webdriver.common.keys import Keys
22+
23+
from .utils import keys_to_typing
24+
2325

2426
class ActionChains(object):
2527
"""
@@ -169,7 +171,7 @@ def key_down(self, value, element=None):
169171
if element: self.click(element)
170172
self._actions.append(lambda:
171173
self._driver.execute(Command.SEND_KEYS_TO_ACTIVE_ELEMENT, {
172-
"value": self._keys_to_typing(value) }))
174+
"value": keys_to_typing(value) }))
173175
return self
174176

175177
def key_up(self, value, element=None):
@@ -189,7 +191,7 @@ def key_up(self, value, element=None):
189191
if element: self.click(element)
190192
self._actions.append(lambda:
191193
self._driver.execute(Command.SEND_KEYS_TO_ACTIVE_ELEMENT, {
192-
"value": self._keys_to_typing(value) }))
194+
"value": keys_to_typing(value) }))
193195
return self
194196

195197
def move_by_offset(self, xoffset, yoffset):
@@ -257,7 +259,7 @@ def send_keys(self, *keys_to_send):
257259
"""
258260
self._actions.append(lambda:
259261
self._driver.execute(Command.SEND_KEYS_TO_ACTIVE_ELEMENT,
260-
{ 'value': self._keys_to_typing(keys_to_send)}))
262+
{ 'value': keys_to_typing(keys_to_send)}))
261263
return self
262264

263265
def send_keys_to_element(self, element, *keys_to_send):
@@ -273,20 +275,6 @@ def send_keys_to_element(self, element, *keys_to_send):
273275
element.send_keys(*keys_to_send))
274276
return self
275277

276-
def _keys_to_typing(self, value):
277-
typing = []
278-
for val in value:
279-
if isinstance(val, Keys):
280-
typing.append(val)
281-
elif isinstance(val, int):
282-
val = str(val)
283-
for i in range(len(val)):
284-
typing.append(val[i])
285-
else:
286-
for i in range(len(val)):
287-
typing.append(val[i])
288-
return typing
289-
290278
# Context manager so ActionChains can be used in a 'with .. as' statements.
291279
def __enter__(self):
292280
return self # Return created instance of self.

py/selenium/webdriver/common/utils.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@
2020
"""
2121
import socket
2222

23+
try:
24+
basestring
25+
except NameError:
26+
# Python 3
27+
basestring = str
28+
2329

2430
def free_port():
2531
"""
@@ -71,3 +77,19 @@ def is_url_connectable(port):
7177
return False
7278
except:
7379
return False
80+
81+
82+
def keys_to_typing(value):
83+
"""Processes the values that will be typed in the element."""
84+
typing = []
85+
for val in value:
86+
# If it is a non-string object, make it a string
87+
if not isinstance(val, basestring):
88+
# This str() call enables for abstraction if one has a custom object that has some
89+
# UI representation to implement __str__() to return the representation, making it
90+
# possible to pass that object to the filling methods.
91+
val = str(val)
92+
# Then just add the separate characters in the list
93+
# ['e'].extend('asdf') => ['e', 'a', 's', 'd', 'f']
94+
typing.extend(val)
95+
return typing

py/selenium/webdriver/remote/file_detector.py

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
import abc
1919
import os
20-
from selenium.webdriver.common.keys import Keys
20+
from selenium.webdriver.common.utils import keys_to_typing
2121

2222

2323
class FileDetector(object):
@@ -45,21 +45,9 @@ class LocalFileDetector(FileDetector):
4545
Detects files on the local disk.
4646
"""
4747
def is_local_file(self, *keys):
48-
file_path = ''
49-
typing = []
50-
for val in keys:
51-
if isinstance(val, Keys):
52-
typing.append(val)
53-
elif isinstance(val, int):
54-
val = val.__str__()
55-
for i in range(len(val)):
56-
typing.append(val[i])
57-
else:
58-
for i in range(len(val)):
59-
typing.append(val[i])
60-
file_path = ''.join(typing)
48+
file_path = ''.join(keys_to_typing(keys))
6149

62-
if file_path is '':
50+
if not file_path:
6351
return None
6452

6553
try:

py/selenium/webdriver/remote/webdriver.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import base64
2121
import warnings
22+
from contextlib import contextmanager
2223

2324
from .command import Command
2425
from .webelement import WebElement
@@ -54,7 +55,8 @@ class WebDriver(object):
5455
"""
5556

5657
def __init__(self, command_executor='http://127.0.0.1:4444/wd/hub',
57-
desired_capabilities=None, browser_profile=None, proxy=None, keep_alive=False):
58+
desired_capabilities=None, browser_profile=None, proxy=None, keep_alive=False,
59+
file_detector=None):
5860
"""
5961
Create a new driver that will issue commands using the wire protocol.
6062
@@ -69,6 +71,8 @@ def __init__(self, command_executor='http://127.0.0.1:4444/wd/hub',
6971
be started with given proxy settings, if possible. Optional.
7072
- keep_alive - Whether to configure remote_connection.RemoteConnection to use
7173
HTTP keep-alive. Defaults to False.
74+
- file_detector - Pass custom file detector object during instantiation. If None,
75+
then default LocalFileDetector() will be used.
7276
"""
7377
if desired_capabilities is None:
7478
raise WebDriverException("Desired Capabilities can't be None")
@@ -87,12 +91,40 @@ def __init__(self, command_executor='http://127.0.0.1:4444/wd/hub',
8791
self.start_session(desired_capabilities, browser_profile)
8892
self._switch_to = SwitchTo(self)
8993
self._mobile = Mobile(self)
90-
self.file_detector = LocalFileDetector()
94+
self.file_detector = file_detector or LocalFileDetector()
9195

9296
def __repr__(self):
9397
return '<{0.__module__}.{0.__name__} (session="{1}")>'.format(
9498
type(self), self.session_id)
9599

100+
@contextmanager
101+
def file_detector_context(self, file_detector_class, *args, **kwargs):
102+
"""
103+
Overrides the current file detector (if necessary) in limited context.
104+
Ensures the original file detector is set afterwards.
105+
106+
Example:
107+
108+
with webdriver.file_detector_context(UselessFileDetector):
109+
someinput.send_keys('/etc/hosts')
110+
111+
:Args:
112+
- file_detector_class - Class of the desired file detector. If the class is different
113+
from the current file_detector, then the class is instantiated with args and kwargs
114+
and used as a file detector during the duration of the context manager.
115+
- args - Optional arguments that get passed to the file detector class during
116+
instantiation.
117+
- kwargs - Keyword arguments, passed the same way as args.
118+
"""
119+
last_detector = None
120+
if not isinstance(self.file_detector, file_detector_class):
121+
last_detector = self.file_detector
122+
self.file_detector = file_detector_class(*args, **kwargs)
123+
try:
124+
yield
125+
finally:
126+
if last_detector is not None:
127+
self.file_detector = last_detector
96128

97129
@property
98130
def mobile(self):

py/selenium/webdriver/remote/webelement.py

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
# under the License.
1717

1818
import hashlib
19-
from numbers import Number
2019
import os
2120
import zipfile
2221
try:
@@ -29,7 +28,7 @@
2928
from selenium.common.exceptions import WebDriverException
3029
from selenium.common.exceptions import InvalidSelectorException
3130
from selenium.webdriver.common.by import By
32-
from selenium.webdriver.common.keys import Keys
31+
from selenium.webdriver.common.utils import keys_to_typing
3332

3433

3534
try:
@@ -320,18 +319,7 @@ def send_keys(self, *value):
320319
if local_file is not None:
321320
value = self._upload(local_file)
322321

323-
typing = []
324-
for val in value:
325-
if isinstance(val, Keys):
326-
typing.append(val)
327-
elif isinstance(val, Number):
328-
val = val.__str__()
329-
for i in range(len(val)):
330-
typing.append(val[i])
331-
else:
332-
for i in range(len(val)):
333-
typing.append(val[i])
334-
self._execute(Command.SEND_KEYS_TO_ELEMENT, {'value': typing})
322+
self._execute(Command.SEND_KEYS_TO_ELEMENT, {'value': keys_to_typing(value)})
335323

336324
# RenderedWebElement Items
337325
def is_displayed(self):

0 commit comments

Comments
 (0)