Skip to content

Commit ca7c066

Browse files
isaulvBeyondEvil
authored andcommitted
Lazy import requests to improve test run time
1 parent 6e355ce commit ca7c066

File tree

7 files changed

+94
-9
lines changed

7 files changed

+94
-9
lines changed

pytest_selenium/drivers/browserstack.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
44

55
import pytest
6-
import requests
76

87
from pytest_selenium.drivers.cloud import Provider
98

@@ -43,6 +42,9 @@ def pytest_selenium_runtest_makereport(item, report, summary, extra):
4342
session_id = item._driver.session_id
4443
api_url = provider.API.format(session=session_id)
4544

45+
# lazy import requests for projects that don't need requests
46+
import requests
47+
4648
try:
4749
job_info = requests.get(api_url, auth=provider.auth, timeout=10).json()
4850
job_url = job_info["automation_session"]["browser_url"]

pytest_selenium/drivers/crossbrowsertesting.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
from py.xml import html
66
import pytest
7-
import requests
87

98
from pytest_selenium.drivers.cloud import Provider
109

@@ -40,6 +39,9 @@ def pytest_selenium_capture_debug(item, report, extra):
4039
if not provider.uses_driver(item.config.getoption("driver")):
4140
return
4241

42+
# lazy import requests for projects that don't need requests
43+
import requests
44+
4345
videos = (
4446
requests.get(
4547
provider.API.format(session=item._driver.session_id),
@@ -63,6 +65,9 @@ def pytest_selenium_runtest_makereport(item, report, summary, extra):
6365

6466
passed = report.passed or (report.failed and hasattr(report, "wasxfail"))
6567

68+
# lazy import requests for projects that don't need requests
69+
import requests
70+
6671
# Add the test URL to the summary
6772
info = requests.get(
6873
provider.API.format(session=item._driver.session_id),

pytest_selenium/drivers/saucelabs.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
from py.xml import html
99
import pytest
10-
import requests
1110

1211
from pytest_selenium.drivers.cloud import Provider
1312

@@ -68,6 +67,9 @@ def pytest_selenium_runtest_makereport(item, report, summary, extra):
6867
# Add the job URL to the HTML report
6968
extra.append(pytest_html.extras.url(job_url, "{0} Job".format(provider.name)))
7069

70+
# lazy import requests for projects that don't need requests
71+
import requests
72+
7173
try:
7274
# Update the job result
7375
api_url = provider.API.format(session=session_id, username=provider.username)

pytest_selenium/drivers/testingbot.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
# License, v. 2.0. If a copy of the MPL was not distributed with this
33
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
44

5-
import pytest
6-
import requests
7-
85
from hashlib import md5
6+
7+
import pytest
98
from py.xml import html
9+
1010
from pytest_selenium.drivers.cloud import Provider
1111

1212
HOST = "hub.testingbot.com"
@@ -72,6 +72,9 @@ def pytest_selenium_runtest_makereport(item, report, summary, extra):
7272
# Add the job URL to the HTML report
7373
extra.append(pytest_html.extras.url(job_url, "{0} Job".format(provider.name)))
7474

75+
# lazy import requests for projects that don't need requests
76+
import requests
77+
7578
try:
7679
# Update the job result
7780
api_url = provider.API.format(session=session_id)

pytest_selenium/pytest_selenium.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,15 @@
1010
import logging
1111

1212
import pytest
13-
from requests.structures import CaseInsensitiveDict
1413
from selenium import webdriver
1514
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
1615
from selenium.webdriver.support.event_firing_webdriver import EventFiringWebDriver
1716

17+
from .utils import CaseInsensitiveDict
1818
from . import drivers
1919

2020
LOGGER = logging.getLogger(__name__)
2121

22-
2322
SUPPORTED_DRIVERS = CaseInsensitiveDict(
2423
{
2524
"BrowserStack": webdriver.Remote,

pytest_selenium/safety.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import re
88

99
import pytest
10-
import requests
1110

1211

1312
def pytest_addoption(parser):
@@ -56,6 +55,10 @@ def sensitive_url(request, base_url):
5655
# consider this environment sensitive if the base url or any redirection
5756
# history matches the regular expression
5857
urls = [base_url]
58+
59+
# lazy import requests for projects that don't need requests
60+
import requests
61+
5962
try:
6063
response = requests.get(base_url, timeout=10)
6164
urls.append(response.url)

pytest_selenium/utils.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
from collections.abc import Mapping, MutableMapping
2+
3+
4+
class CaseInsensitiveDict(MutableMapping):
5+
"""A case-insensitive ``dict``-like object.
6+
7+
Implements all methods and operations of
8+
``MutableMapping`` as well as dict's ``copy``. Also
9+
provides ``lower_items``.
10+
11+
All keys are expected to be strings. The structure remembers the
12+
case of the last key to be set, and ``iter(instance)``,
13+
``keys()``, ``items()``, ``iterkeys()``, and ``iteritems()``
14+
will contain case-sensitive keys. However, querying and contains
15+
testing is case insensitive::
16+
17+
cid = CaseInsensitiveDict()
18+
cid['Accept'] = 'application/json'
19+
cid['aCCEPT'] == 'application/json' # True
20+
list(cid) == ['Accept'] # True
21+
22+
For example, ``headers['content-encoding']`` will return the
23+
value of a ``'Content-Encoding'`` response header, regardless
24+
of how the header name was originally stored.
25+
26+
If the constructor, ``.update``, or equality comparison
27+
operations are given keys that have equal ``.lower()``s, the
28+
behavior is undefined.
29+
"""
30+
31+
def __init__(self, data=None, **kwargs):
32+
self._store = dict()
33+
if data is None:
34+
data = {}
35+
self.update(data, **kwargs)
36+
37+
def __setitem__(self, key, value):
38+
# Use the lowercased key for lookups, but store the actual
39+
# key alongside the value.
40+
self._store[key.lower()] = (key, value)
41+
42+
def __getitem__(self, key):
43+
return self._store[key.lower()][1]
44+
45+
def __delitem__(self, key):
46+
del self._store[key.lower()]
47+
48+
def __iter__(self):
49+
return (casedkey for casedkey, mappedvalue in self._store.values())
50+
51+
def __len__(self):
52+
return len(self._store)
53+
54+
def lower_items(self):
55+
"""Like iteritems(), but with all lowercase keys."""
56+
return ((lowerkey, keyval[1]) for lowerkey, keyval in self._store.items())
57+
58+
def __eq__(self, other):
59+
if isinstance(other, Mapping):
60+
other = CaseInsensitiveDict(other)
61+
else:
62+
return NotImplemented
63+
# Compare insensitively
64+
return dict(self.lower_items()) == dict(other.lower_items())
65+
66+
# Copy is required
67+
def copy(self):
68+
return CaseInsensitiveDict(self._store.values())
69+
70+
def __repr__(self):
71+
return str(dict(self.items()))

0 commit comments

Comments
 (0)