Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/py/selenium/webdriver/common/utils.py
1864 views
1
# Licensed to the Software Freedom Conservancy (SFC) under one
2
# or more contributor license agreements. See the NOTICE file
3
# distributed with this work for additional information
4
# regarding copyright ownership. The SFC licenses this file
5
# to you under the Apache License, Version 2.0 (the
6
# "License"); you may not use this file except in compliance
7
# with the License. You may obtain a copy of the License at
8
#
9
# http://www.apache.org/licenses/LICENSE-2.0
10
#
11
# Unless required by applicable law or agreed to in writing,
12
# software distributed under the License is distributed on an
13
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
# KIND, either express or implied. See the License for the
15
# specific language governing permissions and limitations
16
# under the License.
17
"""The Utils methods."""
18
19
import socket
20
from collections.abc import Iterable
21
from typing import Optional, Union
22
23
from selenium.types import AnyKey
24
from selenium.webdriver.common.keys import Keys
25
26
_is_connectable_exceptions = (socket.error, ConnectionResetError)
27
28
29
def free_port() -> int:
30
"""Determines a free port using sockets.
31
32
First try IPv4, but use IPv6 if it can't bind (IPv6-only system).
33
"""
34
free_socket = None
35
try:
36
# IPv4
37
free_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
38
free_socket.bind(("127.0.0.1", 0))
39
except OSError:
40
if free_socket:
41
free_socket.close()
42
# IPv6
43
try:
44
free_socket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
45
free_socket.bind(("::1", 0))
46
except OSError:
47
if free_socket:
48
free_socket.close()
49
raise RuntimeError("Can't find free port (Unable to bind to IPv4 or IPv6)")
50
try:
51
port: int = free_socket.getsockname()[1]
52
except Exception as e:
53
raise RuntimeError(f"Can't find free port: ({e})")
54
finally:
55
free_socket.close()
56
return port
57
58
59
def find_connectable_ip(host: Union[str, bytes, bytearray, None], port: Optional[int] = None) -> Optional[str]:
60
"""Resolve a hostname to an IP, preferring IPv4 addresses.
61
62
We prefer IPv4 so that we don't change behavior from previous IPv4-only
63
implementations, and because some drivers (e.g., FirefoxDriver) do not
64
support IPv6 connections.
65
66
If the optional port number is provided, only IPs that listen on the given
67
port are considered.
68
69
:Args:
70
- host - A hostname.
71
- port - Optional port number.
72
73
:Returns:
74
A single IP address, as a string. If any IPv4 address is found, one is
75
returned. Otherwise, if any IPv6 address is found, one is returned. If
76
neither, then None is returned.
77
"""
78
try:
79
addrinfos = socket.getaddrinfo(host, None)
80
except socket.gaierror:
81
return None
82
83
ip = None
84
for family, _, _, _, sockaddr in addrinfos:
85
connectable = True
86
if port:
87
connectable = is_connectable(port, str(sockaddr[0]))
88
89
if connectable and family == socket.AF_INET:
90
return str(sockaddr[0])
91
if connectable and not ip and family == socket.AF_INET6:
92
ip = str(sockaddr[0])
93
return ip
94
95
96
def join_host_port(host: str, port: int) -> str:
97
"""Joins a hostname and port together.
98
99
This is a minimal implementation intended to cope with IPv6 literals. For
100
example, _join_host_port('::1', 80) == '[::1]:80'.
101
102
:Args:
103
- host - A hostname.
104
- port - An integer port.
105
"""
106
if ":" in host and not host.startswith("["):
107
return f"[{host}]:{port}"
108
return f"{host}:{port}"
109
110
111
def is_connectable(port: int, host: Optional[str] = "localhost") -> bool:
112
"""Tries to connect to the server at port to see if it is running.
113
114
:Args:
115
- port - The port to connect.
116
"""
117
socket_ = None
118
try:
119
socket_ = socket.create_connection((host, port), 1)
120
result = True
121
except _is_connectable_exceptions:
122
result = False
123
finally:
124
if socket_:
125
try:
126
socket_.shutdown(socket.SHUT_RDWR)
127
except Exception:
128
pass
129
socket_.close()
130
return result
131
132
133
def is_url_connectable(port: Union[int, str]) -> bool:
134
"""Tries to connect to the HTTP server at /status path and specified port
135
to see if it responds successfully.
136
137
:Args:
138
- port - The port to connect.
139
"""
140
from urllib import request as url_request
141
142
try:
143
res = url_request.urlopen(f"http://127.0.0.1:{port}/status")
144
return res.getcode() == 200
145
except Exception:
146
return False
147
148
149
def keys_to_typing(value: Iterable[AnyKey]) -> list[str]:
150
"""Processes the values that will be typed in the element."""
151
characters: list[str] = []
152
for val in value:
153
if isinstance(val, Keys):
154
# Todo: Does this even work?
155
characters.append(str(val))
156
elif isinstance(val, (int, float)):
157
characters.extend(str(val))
158
else:
159
characters.extend(val)
160
return characters
161
162