Skip to content
This repository has been archived by the owner on Jan 19, 2024. It is now read-only.

Commit

Permalink
Merge pull request #263 from eduNEXT/lmm/py38
Browse files Browse the repository at this point in the history
[BD-6] Add python 3.8 tests
  • Loading branch information
awais786 authored May 8, 2020
2 parents 3b246a9 + dd3f56f commit dbf7818
Show file tree
Hide file tree
Showing 21 changed files with 171 additions and 221 deletions.
7 changes: 3 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
language: python
python:
- '2.7'
- '3.5'
- '3.6'
- 3.5
- 3.8
env:
- TOXENV=core
- TOXENV=needle
- TOXENV=doc
sudo: false
branches:
only:
Expand All @@ -23,7 +23,6 @@ install:
- pip install -r requirements/travis.txt
script:
- tox -- -n 2 --durations=10
- tox -e doc
after_success:
- codecov
deploy:
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
V1.1.0 (05/04/2020)
* Drop support for python 2.7
* Python 3.8 support
v1.0.1 (10/25/19)
* Fix saving of test failure artifacts under Python 3
* Make the saving of page source more robust to missing directories, log problems doing it
Expand Down
11 changes: 4 additions & 7 deletions bok_choy/a11y/a11y_audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,16 @@ class AccessibilityError(Exception):
"""
The page violates one or more accessibility rules.
"""
pass


class A11yAuditConfigError(Exception):
"""
An error in A11yAuditConfig.
"""
pass


@six.add_metaclass(ABCMeta)
class A11yAuditConfig(object):
class A11yAuditConfig:
"""
The `A11yAuditConfig` object defines the options available in an
accessibility ruleset.
Expand Down Expand Up @@ -93,7 +91,7 @@ def customize_ruleset(self, custom_ruleset_file=None):


@six.add_metaclass(ABCMeta)
class A11yAudit(object):
class A11yAudit:
"""
Allows auditing of a page for accessibility issues.
Expand Down Expand Up @@ -138,9 +136,8 @@ def _get_rules_js(self):
self.config.rules_file)
raise RuntimeError(msg)

else:
with io.open(self.config.rules_file, "r", encoding="utf-8") as rules_file:
return rules_file.read()
with io.open(self.config.rules_file, "r", encoding="utf-8") as rules_file:
return rules_file.read()

def do_audit(self):
"""
Expand Down
117 changes: 56 additions & 61 deletions bok_choy/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ class BrowserConfigError(Exception):
"""
Misconfiguration error in the environment variables.
"""
pass


def save_source(driver, name):
Expand Down Expand Up @@ -130,7 +129,7 @@ def save_screenshot(driver, name):
if not screenshot_dir:
LOGGER.warning('The SCREENSHOT_DIR environment variable was not set; not saving a screenshot')
return
elif not os.path.exists(screenshot_dir):
if not os.path.exists(screenshot_dir):
os.makedirs(screenshot_dir)
image_name = os.path.join(screenshot_dir, name + '.png')
driver.save_screenshot(image_name)
Expand Down Expand Up @@ -164,7 +163,7 @@ def save_driver_logs(driver, prefix):
if not log_dir:
LOGGER.warning('The SELENIUM_DRIVER_LOG_DIR environment variable was not set; not saving logs')
return
elif not os.path.exists(log_dir):
if not os.path.exists(log_dir):
os.makedirs(log_dir)
if browser_name == 'firefox':
# Firefox doesn't yet provide logs to Selenium, but does log to a separate file
Expand Down Expand Up @@ -325,15 +324,14 @@ def _firefox_profile():
raise BrowserConfigError(
u"Firefox profile directory {env_var}={profile_dir} does not exist".format(
env_var=FIREFOX_PROFILE_ENV_VAR, profile_dir=profile_dir))
elif err.errno == errno.EACCES:
if err.errno == errno.EACCES:
raise BrowserConfigError(
u"Firefox profile directory {env_var}={profile_dir} has incorrect permissions. It must be \
readable and executable.".format(env_var=FIREFOX_PROFILE_ENV_VAR, profile_dir=profile_dir))
else:
# Some other OSError:
raise BrowserConfigError(
u"Problem with firefox profile directory {env_var}={profile_dir}: {msg}"
.format(env_var=FIREFOX_PROFILE_ENV_VAR, profile_dir=profile_dir, msg=str(err)))
# Some other OSError:
raise BrowserConfigError(
u"Problem with firefox profile directory {env_var}={profile_dir}: {msg}"
.format(env_var=FIREFOX_PROFILE_ENV_VAR, profile_dir=profile_dir, msg=str(err)))
else:
LOGGER.info("Using default firefox profile")
firefox_profile = webdriver.FirefoxProfile()
Expand Down Expand Up @@ -388,59 +386,56 @@ def _local_browser_class(browser_name):
raise BrowserConfigError(
u"Invalid browser name {name}. Options are: {options}".format(
name=browser_name, options=", ".join(list(BROWSERS.keys()))))
if browser_name == 'firefox':
# Remove geckodriver log data from previous test cases
log_path = os.path.join(os.getcwd(), 'geckodriver.log')
if os.path.exists(log_path):
os.remove(log_path)

firefox_options = FirefoxOptions()
firefox_options.log.level = 'trace'
if headless:
firefox_options.headless = True
browser_args = []
browser_kwargs = {
'firefox_profile': _firefox_profile(),
'options': firefox_options,
}

firefox_path = os.environ.get('SELENIUM_FIREFOX_PATH')
firefox_log = os.environ.get('SELENIUM_FIREFOX_LOG')
if firefox_path and firefox_log:
browser_kwargs.update({
'firefox_binary': FirefoxBinary(
firefox_path=firefox_path, log_file=firefox_log)
})
elif firefox_path:
browser_kwargs.update({
'firefox_binary': FirefoxBinary(firefox_path=firefox_path)
})
elif firefox_log:
browser_kwargs.update({
'firefox_binary': FirefoxBinary(log_file=firefox_log)
})

elif browser_name == 'chrome':
chrome_options = ChromeOptions()
if headless:
chrome_options.headless = True

# Emulate webcam and microphone for testing purposes
chrome_options.add_argument('--use-fake-device-for-media-stream')

# Bypasses the security prompt displayed by the browser when it attempts to
# access a media device (e.g., a webcam)
chrome_options.add_argument('--use-fake-ui-for-media-stream')
browser_args = []
browser_kwargs = {
'options': chrome_options,
}
else:
if browser_name == 'firefox':
# Remove geckodriver log data from previous test cases
log_path = os.path.join(os.getcwd(), 'geckodriver.log')
if os.path.exists(log_path):
os.remove(log_path)

firefox_options = FirefoxOptions()
firefox_options.log.level = 'trace'
if headless:
firefox_options.headless = True
browser_args = []
browser_kwargs = {
'firefox_profile': _firefox_profile(),
'options': firefox_options,
}

firefox_path = os.environ.get('SELENIUM_FIREFOX_PATH')
firefox_log = os.environ.get('SELENIUM_FIREFOX_LOG')
if firefox_path and firefox_log:
browser_kwargs.update({
'firefox_binary': FirefoxBinary(
firefox_path=firefox_path, log_file=firefox_log)
})
elif firefox_path:
browser_kwargs.update({
'firefox_binary': FirefoxBinary(firefox_path=firefox_path)
})
elif firefox_log:
browser_kwargs.update({
'firefox_binary': FirefoxBinary(log_file=firefox_log)
})

elif browser_name == 'chrome':
chrome_options = ChromeOptions()
if headless:
chrome_options.headless = True

# Emulate webcam and microphone for testing purposes
chrome_options.add_argument('--use-fake-device-for-media-stream')

# Bypasses the security prompt displayed by the browser when it attempts to
# access a media device (e.g., a webcam)
chrome_options.add_argument('--use-fake-ui-for-media-stream')

browser_args = []
browser_kwargs = {
'options': chrome_options,
}
else:
browser_args, browser_kwargs = [], {}

return browser_class, browser_args, browser_kwargs
browser_args, browser_kwargs = [], {}
return browser_class, browser_args, browser_kwargs


def _remote_browser_class(env_vars, tags=None):
Expand Down
20 changes: 9 additions & 11 deletions bok_choy/javascript.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,16 @@ def wrapper(*args, **kwargs): # pylint: disable=missing-docstring
return function(*args, **kwargs)

# Otherwise, retrieve `self` as the first arg
else:
self = args[0]
self = args[0]

# If the class has been decorated by one of the
# JavaScript dependency decorators, it should have
# a `wait_for_js` method
if hasattr(self, 'wait_for_js'):
self.wait_for_js()
# If the class has been decorated by one of the
# JavaScript dependency decorators, it should have
# a `wait_for_js` method
if hasattr(self, 'wait_for_js'):
self.wait_for_js()

# Call the function
return function(*args, **kwargs)
# Call the function
return function(*args, **kwargs)

return wrapper

Expand Down Expand Up @@ -154,8 +153,7 @@ def _are_js_vars_defined(browser, js_vars):
except WebDriverException as exc:
if "is not defined" in exc.msg or "is undefined" in exc.msg:
return False
else:
raise
raise


def _are_requirejs_deps_loaded(browser, deps):
Expand Down
5 changes: 1 addition & 4 deletions bok_choy/page_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,18 @@ class WrongPageError(WebDriverException):
"""
The page object reports that we're on the wrong page!
"""
pass


class PageLoadError(WebDriverException):
"""
An error occurred while loading the page.
"""
pass


class XSSExposureError(Exception):
"""
An XSS issue has been found on the current page.
"""
pass


def no_selenium_errors(func):
Expand Down Expand Up @@ -173,7 +170,7 @@ def __new__(mcs, cls_name, cls_bases, cls_attrs, **kwargs): # pylint: disable=a


@six.add_metaclass(_PageObjectMetaclass)
class PageObject(object):
class PageObject:
"""
Encapsulates user interactions with a specific part
of a web application.
Expand Down
5 changes: 2 additions & 3 deletions bok_choy/promise.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def __str__(self):
return "Promise not satisfied: {0}".format(self._promise)


class Promise(object):
class Promise:
"""
Check that an asynchronous action completed, blocking until it does
or timeout / try limits are reached.
Expand Down Expand Up @@ -102,8 +102,7 @@ def fulfill(self):

if is_fulfilled:
return result
else:
raise BrokenPromise(self)
raise BrokenPromise(self)

def __str__(self):
return str(self._description)
Expand Down
2 changes: 1 addition & 1 deletion bok_choy/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import logging

from copy import copy
from collections import Sequence
from collections.abc import Sequence
from itertools import islice
from selenium.common.exceptions import WebDriverException
import six
Expand Down
2 changes: 1 addition & 1 deletion docs/code/round_3/pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def search_results(self):
"""
Return a list of results returned from a search
"""
return self.q(css='ul.repo-list > li > div > h3 > a').text
return self.q(css='ul.repo-list > li > div > div > a').text


class GitHubSearchPage(PageObject):
Expand Down
6 changes: 0 additions & 6 deletions requirements/constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,6 @@
# pin when possible. Writing an issue against the offending project and
# linking to it here is good.

# more-itertools 6.0.0 dropped Python 2.7 support
more-itertools<6.0.0

# Newer versions of pylint-plugin-utils drop Python 2.7 support
pylint-plugin-utils<0.4

# requests only supports urllib 1.24: https://github.com/kennethreitz/requests/issues/5067
urllib3<1.25

Expand Down
Loading

0 comments on commit dbf7818

Please sign in to comment.