Commit 246d38c6 authored by Thomas Goirand's avatar Thomas Goirand

Imported Upstream version 2.53.2+dfsg1

parent aa55db27
......@@ -16,5 +16,5 @@ recursive-include py/selenium/webdriver/support *.py
include py/selenium/selenium.py
include py/selenium/__init__.py
include py/CHANGES
include py/README
include py/README.rst
recursive-include selenium.egg-info *
Metadata-Version: 1.1
Name: selenium
Version: 2.48.0
Version: 2.53.2
Summary: Python bindings for Selenium
Home-page: https://github.com/SeleniumHQ/selenium/
Author: UNKNOWN
......@@ -22,7 +22,7 @@ Description: ======================
+-----------+-----------------------------------------------------------------------------------+
| **Docs**: | `selenium package API <http://selenium.googlecode.com/git/docs/api/py/api.html>`_ |
+-----------+-----------------------------------------------------------------------------------+
| **Dev**: | https://github.com/SeleniumHQ/selenium |
| **Dev**: | https://github.com/SeleniumHQ/selenium |
+-----------+-----------------------------------------------------------------------------------+
| **PyPI**: | https://pypi.python.org/pypi/selenium |
+-----------+-----------------------------------------------------------------------------------+
......@@ -35,7 +35,7 @@ Description: ======================
=========================
* Python 2.6, 2.7
* Python 3.2, 3.3
* Python 3.2+
Installing
==========
......@@ -44,7 +44,7 @@ Description: ======================
pip install -U selenium
Alternately, you can download the source distribution from `PyPI <http://pypi.python.org/pypi/selenium>`_ (e.g. selenium-2.48.tar.gz), unarchive it, and run::
Alternately, you can download the source distribution from `PyPI <http://pypi.python.org/pypi/selenium>`_ (e.g. selenium-2.53.2.tar.gz), unarchive it, and run::
python setup.py install
......@@ -115,11 +115,11 @@ Description: ======================
However, to use Selenium Webdriver Remote or the legacy Selenium API (Selenium-RC), you need to also run the Selenium server. The server requires a Java Runtime Environment (JRE).
Download the server separately, from: http://selenium-release.storage.googleapis.com/2.48/selenium-server-standalone-2.48.0.jar
Download the server separately, from: http://selenium-release.storage.googleapis.com/2.53/selenium-server-standalone-2.53.0.jar
Run the server from the command line::
java -jar selenium-server-standalone-2.48.8.jar
java -jar selenium-server-standalone-2.53.0.jar
Then run your Python client scripts.
......
Selenium 2.53.2
* Fix send keys when using PUA keys e.g. Keys.RIGHT #1839
* Fix cookie file leak in PhantomJS #1854
Selenium 2.53.1
* Fix basestring reference to work with python 3. Fixes #1820
* Correct Length conditional when filtering in PhantomJS. Fixes #1817
Selenium 2.53.0
* Adding Options object for use with Python FirefoxDriver
* Fixed improper usage of super in exceptions module
* create a temp file for cookies in phantomjs if not specified
* Pass in the executable that FirefoxBinary finds to the service if there isnt one passed in as a kwarg or capability
* Applied some DRY and extracted out the keys_to_typing()
* Fix deselecting options in <select>
Selenium 2.52.0
* Fixing case where UnexpectedAlertException doesn't get the alert_text in the error object
* Firefox: Actually use launch_browser timeout Fixes #1300
Selenium 2.51.1
* correcting bundling issue missing README.rst file
Selenium 2.51.0
* Firefox updates (see java changelog)
Selenium 2.50.1
* Fixing error message handling. Fixes issue #1497
* Fixing error message handling. Fixes issue #1507
* Update webelement to handle W3C commands for size/location and rect
* rewrite click scrolling tests to match the Java ones
Selenium 2.50.0
* handle potential URLError from sending shutdown, set self.process to None after it's already been quit
* Add support for submit() with W3C compliant endpoint
Selenium 2.49.1
* Ensure you can close stream before attempting to close it.
* message response may cause json loads ValueError when it's not actually json
and just a string (like the message that occurs when firefox driver thinks
another element will receive the click)
* Cleanup some error handling when sniffing what protocol you are speaking
Selenium 2.49.0
* Have Firefox service write to a file instead of PIPE
* on osx for firefox, fallback to checking homebrew install, if the default isn't there
* Added Firefox path variable for string placeholder
* Update README to show Python 3.2+
* refactoring all the service classes to use a common one.
* Add Firefox specific command to switch context between Browser content and Browser chrome
* updating files after go copyright:update
* Use specificationLevel to know that we are speaking GeckoDriver
* Bug fixes: #1294, #1186
Selenium 2.48.0
* Update error pulling to match spec when we encounter a spec compliant browser.
* Disable tests that are not working with Marionette when running Marionette tests
......
......@@ -14,7 +14,7 @@ The `selenium` package is used automate web browser interaction from Python.
+-----------+-----------------------------------------------------------------------------------+
| **Docs**: | `selenium package API <http://selenium.googlecode.com/git/docs/api/py/api.html>`_ |
+-----------+-----------------------------------------------------------------------------------+
| **Dev**: | https://github.com/SeleniumHQ/selenium |
| **Dev**: | https://github.com/SeleniumHQ/selenium |
+-----------+-----------------------------------------------------------------------------------+
| **PyPI**: | https://pypi.python.org/pypi/selenium |
+-----------+-----------------------------------------------------------------------------------+
......@@ -27,7 +27,7 @@ Supported Python Versions
=========================
* Python 2.6, 2.7
* Python 3.2, 3.3
* Python 3.2+
Installing
==========
......@@ -36,7 +36,7 @@ If you have `pip <http://www.pip-installer.org>`_ on your system, you can simply
pip install -U selenium
Alternately, you can download the source distribution from `PyPI <http://pypi.python.org/pypi/selenium>`_ (e.g. selenium-2.48.tar.gz), unarchive it, and run::
Alternately, you can download the source distribution from `PyPI <http://pypi.python.org/pypi/selenium>`_ (e.g. selenium-2.53.2.tar.gz), unarchive it, and run::
python setup.py install
......@@ -107,11 +107,11 @@ For normal WebDriver scripts (non-Remote), the Java server is not needed.
However, to use Selenium Webdriver Remote or the legacy Selenium API (Selenium-RC), you need to also run the Selenium server. The server requires a Java Runtime Environment (JRE).
Download the server separately, from: http://selenium-release.storage.googleapis.com/2.48/selenium-server-standalone-2.48.0.jar
Download the server separately, from: http://selenium-release.storage.googleapis.com/2.53/selenium-server-standalone-2.53.0.jar
Run the server from the command line::
java -jar selenium-server-standalone-2.48.8.jar
java -jar selenium-server-standalone-2.53.0.jar
Then run your Python client scripts.
......
......@@ -18,4 +18,4 @@
from selenium import selenium
__version__ = "2.48.0"
__version__ = "2.53.2"
......@@ -130,7 +130,7 @@ class UnexpectedAlertPresentException(WebDriverException):
self.alert_text = alert_text
def __str__(self):
return "Alert Text: %s\n%s" % (self.alert_text, str(super(WebDriverException, self)))
return "Alert Text: %s\n%s" % (self.alert_text, super(UnexpectedAlertPresentException, self).__str__())
class NoAlertPresentException(WebDriverException):
"""
......
......@@ -32,4 +32,4 @@ from .common.action_chains import ActionChains
from .common.touch_actions import TouchActions
from .common.proxy import Proxy
__version__ = '2.48.0'
__version__ = '2.53.2'
......@@ -14,16 +14,9 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import os
import errno
import subprocess
from subprocess import PIPE
import time
from selenium.webdriver.common import service
from selenium.common.exceptions import WebDriverException
from selenium.webdriver.common import utils
class Service(object):
class Service(service.Service):
"""
Object that manages the starting and stopping of the ChromeDriver
"""
......@@ -39,90 +32,12 @@ class Service(object):
- service_args : List of args to pass to the chromedriver service
- log_path : Path for the chromedriver service to log to"""
self.port = port
self.path = executable_path
self.service_args = service_args or []
if log_path:
self.service_args.append('--log-path=%s' % log_path)
if self.port == 0:
self.port = utils.free_port()
self.env = env
def start(self):
"""
Starts the ChromeDriver Service.
:Exceptions:
- WebDriverException : Raised either when it cannot find the
executable, when it does not have permissions for the
executable, or when it cannot connect to the service.
- Possibly other Exceptions in rare circumstances (OSError, etc).
"""
env = self.env or os.environ
try:
self.process = subprocess.Popen([
self.path,
"--port=%d" % self.port] +
self.service_args, env=env, stdout=PIPE, stderr=PIPE)
except OSError as err:
docs_msg = "Please see " \
"https://sites.google.com/a/chromium.org/chromedriver/home"
if err.errno == errno.ENOENT:
raise WebDriverException(
"'%s' executable needs to be in PATH. %s" % (
os.path.basename(self.path), docs_msg)
)
elif err.errno == errno.EACCES:
raise WebDriverException(
"'%s' executable may have wrong permissions. %s" % (
os.path.basename(self.path), docs_msg)
)
else:
raise
count = 0
while not utils.is_connectable(self.port):
count += 1
time.sleep(1)
if count == 30:
raise WebDriverException("Can not connect to the '" +
os.path.basename(self.path) + "'")
@property
def service_url(self):
"""
Gets the url of the ChromeDriver Service
"""
return "http://localhost:%d" % self.port
def stop(self):
"""
Tells the ChromeDriver to stop and cleans up the process
"""
#If its dead dont worry
if self.process is None:
return
#Tell the Server to die!
try:
from urllib import request as url_request
except ImportError:
import urllib2 as url_request
url_request.urlopen("http://127.0.0.1:%d/shutdown" % self.port)
count = 0
while utils.is_connectable(self.port):
if count == 30:
break
count += 1
time.sleep(1)
service.Service.__init__(self, executable_path, port=port, env=env,
start_error_message="Please see https://sites.google.com/a/chromium.org/chromedriver/home")
#Tell the Server to properly die in case
try:
if self.process:
self.process.stdout.close()
self.process.stderr.close()
self.process.kill()
self.process.wait()
except OSError:
# kill may not be available under windows environment
pass
def command_line_args(self):
return ["--port=%d" % self.port] + self.service_args
......@@ -19,7 +19,9 @@
The ActionChains implementation,
"""
from selenium.webdriver.remote.command import Command
from selenium.webdriver.common.keys import Keys
from .utils import keys_to_typing
class ActionChains(object):
"""
......@@ -169,7 +171,7 @@ class ActionChains(object):
if element: self.click(element)
self._actions.append(lambda:
self._driver.execute(Command.SEND_KEYS_TO_ACTIVE_ELEMENT, {
"value": self._keys_to_typing(value) }))
"value": keys_to_typing(value) }))
return self
def key_up(self, value, element=None):
......@@ -189,7 +191,7 @@ class ActionChains(object):
if element: self.click(element)
self._actions.append(lambda:
self._driver.execute(Command.SEND_KEYS_TO_ACTIVE_ELEMENT, {
"value": self._keys_to_typing(value) }))
"value": keys_to_typing(value) }))
return self
def move_by_offset(self, xoffset, yoffset):
......@@ -257,7 +259,7 @@ class ActionChains(object):
"""
self._actions.append(lambda:
self._driver.execute(Command.SEND_KEYS_TO_ACTIVE_ELEMENT,
{ 'value': self._keys_to_typing(keys_to_send)}))
{ 'value': keys_to_typing(keys_to_send)}))
return self
def send_keys_to_element(self, element, *keys_to_send):
......@@ -273,20 +275,6 @@ class ActionChains(object):
element.send_keys(*keys_to_send))
return self
def _keys_to_typing(self, value):
typing = []
for val in value:
if isinstance(val, Keys):
typing.append(val)
elif isinstance(val, int):
val = str(val)
for i in range(len(val)):
typing.append(val[i])
else:
for i in range(len(val)):
typing.append(val[i])
return typing
# Context manager so ActionChains can be used in a 'with .. as' statements.
def __enter__(self):
return self # Return created instance of self.
......
......@@ -85,7 +85,7 @@ class DesiredCapabilities(object):
SAFARI = {
"browserName": "safari",
"version": "",
"platform": "ANY",
"platform": "MAC",
"javascriptEnabled": True,
}
......
# Licensed to the Software Freedom Conservancy (SFC) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The SFC licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import errno
import os
import platform
import subprocess
from subprocess import PIPE
import time
from selenium.common.exceptions import WebDriverException
from selenium.webdriver.common import utils
class Service(object):
def __init__(self, executable, port=0, log_file=PIPE, env=None, start_error_message=""):
self.path = executable
self.port = port
if self.port == 0:
self.port = utils.free_port()
self.start_error_message = start_error_message
self.log_file = log_file
self.env = env or os.environ
@property
def service_url(self):
"""
Gets the url of the Service
"""
return "http://localhost:%d" % self.port
def command_line_args(self):
raise NotImplemented("This method needs to be implemented in a sub class")
def start(self):
"""
Starts the Service.
:Exceptions:
- WebDriverException : Raised either when it can't start the service
or when it can't connect to the service
"""
try:
cmd = [self.path]
cmd.extend(self.command_line_args())
self.process = subprocess.Popen(cmd, env=self.env,
close_fds=platform.system() != 'Windows',
stdout=self.log_file, stderr=self.log_file)
except TypeError:
raise
except OSError as err:
if err.errno == errno.ENOENT:
raise WebDriverException(
"'%s' executable needs to be in PATH. %s" % (
os.path.basename(self.path), self.start_error_message)
)
elif err.errno == errno.EACCES:
raise WebDriverException(
"'%s' executable may have wrong permissions. %s" % (
os.path.basename(self.path), self.start_error_message)
)
else:
raise
except Exception as e:
raise WebDriverException(
"The executable %s needs to be available in the path. %s\n%s" %
(os.path.basename(self.path), self.start_error_message, str(e))
)
count = 0
while not self.is_connectable():
count += 1
time.sleep(1)
if count == 30:
raise WebDriverException("Can not connect to the Service %s" % self.path)
def is_connectable(self):
return utils.is_connectable(self.port)
def send_remote_shutdown_command(self):
try:
from urllib import request as url_request
URLError = url_request.URLError
except ImportError:
import urllib2 as url_request
import urllib2
URLError = urllib2.URLError
try:
url_request.urlopen("http://127.0.0.1:%d/shutdown" % self.port)
except URLError:
return
count = 0
while self.is_connectable():
if count == 30:
break
count += 1
time.sleep(1)
def stop(self):
"""
Stops the service.
"""
if self.log_file != PIPE:
try:
self.log_file.close()
except Exception:
pass
if self.process is None:
return
try:
self.send_remote_shutdown_command()
except TypeError:
pass
try:
if self.process:
for stream in [self.process.stdin,
self.process.stdout,
self.process.stderr]:
try:
stream.close()
except AttributeError:
pass
self.process.terminate()
self.process.kill()
self.process.wait()
self.process = None
except OSError:
# kill may not be available under windows environment
pass
def __del__(self):
# subprocess.Popen doesn't send signal on __del__;
# we have to try to stop the launched process.
self.stop()
......@@ -18,7 +18,15 @@
"""
The Utils methods.
"""
import socket
from selenium.webdriver.common.keys import Keys
try:
basestring
except NameError:
# Python 3
basestring = str
def free_port():
......@@ -71,3 +79,19 @@ def is_url_connectable(port):
return False
except:
return False
def keys_to_typing(value):
"""Processes the values that will be typed in the element."""
typing = []
for val in value:
if isinstance(val, Keys):
typing.append(val)
elif isinstance(val, int):
val = str(val)
for i in range(len(val)):
typing.append(val[i])
else:
for i in range(len(val)):
typing.append(val[i])
return typing
......@@ -14,86 +14,14 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import subprocess
from subprocess import PIPE
import time
from selenium.common.exceptions import WebDriverException
from selenium.webdriver.common import utils
class Service(object):
"""
Object that manages the starting and stopping of the EdgeDriver
"""
def __init__(self, executable_path, port=0):
"""
Creates a new instance of the Service
:Args:
- executable_path : Path to the EdgeDriver
- port : Port the service is running on
"""
self.path = executable_path
self.port = port
if self.port == 0:
self.port = utils.free_port()
def start(self):
"""
Starts the EdgeDriver Service.
:Exceptions:
- WebDriverException : Raised either when it can't start the service
or when it can't connect to the service
"""
try:
cmd = [self.path, "--port=%d" % self.port]
self.process = subprocess.Popen(cmd,
stdout=PIPE, stderr=PIPE)
except TypeError:
raise
except:
raise WebDriverException(
"The EdgeDriver executable needs to be available in the path. "
"Please download from http://go.microsoft.com/fwlink/?LinkId=619687 ")
count = 0
while not utils.is_connectable(self.port):
count += 1
time.sleep(1)
if count == 30:
raise WebDriverException("Can not connect to the EdgeDriver")
def stop(self):
"""
Tells the EdgeDriver to stop and cleans up the process
"""
#If its dead dont worry
if self.process is None:
return
#Tell the Server to die!
try:
from urllib import request as url_request
except ImportError:
import urllib2 as url_request
from subprocess import PIPE
from selenium.webdriver.common import service
url_request.urlopen("http://127.0.0.1:%d/shutdown" % self.port)
count = 0
while utils.is_connectable(self.port):
if count == 30:
break
count += 1
time.sleep(1)
class Service(service.Service):
def __init__(self, executable_path, port=0, log_file=PIPE):
service.Service.__init__(self, executable_path, port=port, log_file=log_file,
start_error_message="Please download from http://go.microsoft.com/fwlink/?LinkId=619687 ")
#Tell the Server to properly die in case
try:
if self.process:
self.process.stdout.close()
self.process.stderr.close()
self.process.kill()
self.process.wait()
except WindowsError:
# kill may not be available under windows environment
pass
def command_line_args(self):
return ["--port=%d" % self.port]
......@@ -34,6 +34,8 @@ class ExtensionConnection(RemoteConnection):
self.profile = firefox_profile
self.binary = firefox_binary
HOST = host
timeout = int(timeout)
if self.binary is None:
self.binary = FirefoxBinary()
......@@ -46,7 +48,7 @@ class ExtensionConnection(RemoteConnection):
self.profile.add_extension()
self.binary.launch_browser(self.profile)
self.binary.launch_browser(self.profile, timeout=timeout)
_URL = "http://%s:%d/hub" % (HOST, PORT)
RemoteConnection.__init__(
self, _URL, keep_alive=True)
......
......@@ -58,14 +58,14 @@ class FirefoxBinary(object):
def add_command_line_options(self, *args):
self.command_line = args
def launch_browser(self, profile):
def launch_browser(self, profile, timeout=30):
"""Launches the browser for the given profile name.
It is assumed the profile already exists.
"""
self.profile = profile
self._start_from_profile_path(self.profile.path)
self._wait_until_connectable()
self._wait_until_connectable(timeout=timeout)
def kill(self):
"""Kill the browser.
......@@ -89,7 +89,7 @@ class FirefoxBinary(object):
command, stdout=self._log_file, stderr=STDOUT,
env=self._firefox_env)
def _wait_until_connectable(self):
def _wait_until_connectable(self, timeout=30):
"""Blocks until the extension is connectable in the firefox."""
count = 0
while not utils.is_connectable(self.profile.port):
......@@ -98,11 +98,12 @@ class FirefoxBinary(object):
raise WebDriverException("The browser appears to have exited "
"before we could connect. If you specified a log_file in "
"the FirefoxBinary constructor, check it for details.")
if count == 30:
if count >= timeout:
self.kill()
raise WebDriverException("Can't load the profile. Profile "
"Dir: %s If you specified a log_file in the "
"FirefoxBinary constructor, check it for details.")
"FirefoxBinary constructor, check it for details."
% (self.profile.path))
count += 1
time.sleep(1)
return True
......@@ -142,7 +143,10 @@ class FirefoxBinary(object):
"""Return the command to start firefox."""
start_cmd = ""
if platform.system() == "Darwin":
start_cmd = ("/Applications/Firefox.app/Contents/MacOS/firefox-bin")
start_cmd = "/Applications/Firefox.app/Contents/MacOS/firefox-bin"
# fallback to homebrew installation for mac users
if not os.path.exists(start_cmd):
start_cmd = os.path.expanduser("~") + start_cmd
elif platform.system() == "Windows":
start_cmd = (self._find_exe_in_registry() or
self._default_windows_location())
......
......@@ -164,6 +164,7 @@ class FirefoxProfile(object):
A zipped, base64 encoded string of profile directory
for use with remote WebDriver JSON wire protocol
"""
self.update_preferences()
fp = BytesIO()
zipped = zipfile.ZipFile(fp, 'w', zipfile.ZIP_DEFLATED)
path_root = len(self.path) + 1 # account for trailing slash
......
# Licensed to the Software Freedom Conservancy (SFC) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The SFC licenses this file