Updated to Python 3.8.7.

master
Pacman Ghost 3 years ago
parent 8f7077a884
commit 951b57c6be
  1. 6
      .pylintrc
  2. 4
      Dockerfile
  3. 36
      conftest.py
  4. 6
      freeze.py
  5. 14
      requirements-dev.txt
  6. 10
      requirements.txt
  7. 5
      setup.py
  8. 2
      tools/build_file.py
  9. 7
      vasl_templates/main.py
  10. 5
      vasl_templates/main_window.py
  11. 4
      vasl_templates/tools/dump_log_file_analysis.py
  12. 2
      vasl_templates/webapp/scenarios.py
  13. 5
      vasl_templates/webapp/static/help/index.html
  14. 3
      vasl_templates/webapp/tests/__init__.py
  15. 13
      vasl_templates/webapp/tests/test_capabilities.py
  16. 3
      vasl_templates/webapp/tests/test_counters.py
  17. 4
      vasl_templates/webapp/tests/test_dirty_scenario_checks.py
  18. 3
      vasl_templates/webapp/tests/test_jshint.py
  19. 3
      vasl_templates/webapp/tests/test_scenario_search.py
  20. 3
      vasl_templates/webapp/tests/test_snippets.py
  21. 5
      vasl_templates/webapp/tests/test_vassal.py
  22. 5
      vasl_templates/webapp/tests/test_vehicles_ordnance.py
  23. 3
      vasl_templates/webapp/tests/test_vo_notes.py
  24. 3
      vasl_templates/webapp/tests/test_vo_reports.py
  25. 7
      vasl_templates/webapp/tests/utils.py
  26. 8
      vasl_templates/webapp/utils.py
  27. 2
      vasl_templates/webapp/vassal.py
  28. 27
      vasl_templates/webapp/webdriver.py

@ -144,7 +144,9 @@ disable=print-statement,
duplicate-code, # can't get it to shut up about @pytest.mark.skipif's :-/
no-else-return,
len-as-condition,
consider-using-enumerate
consider-using-enumerate,
import-outside-toplevel,
isinstance-second-argument-not-valid-type
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
@ -511,7 +513,7 @@ max-public-methods=20
max-returns=10
# Maximum number of statements in function / method body
max-statements=80
max-statements=100
# Minimum number of public methods for a class (see R0903).
min-public-methods=2

@ -9,7 +9,7 @@ FROM centos:8 AS base
RUN dnf -y upgrade-minimal
# install Python
RUN dnf install -y python36 && pip3 install --upgrade pip
RUN dnf install -y python38 python3-pip
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -21,7 +21,7 @@ RUN dnf install -y python36 && pip3 install --upgrade pip
FROM base AS build
# set up a virtualenv
RUN python3 -m venv /opt/venv && pip3 install --upgrade pip
RUN python3 -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
# install the application requirements

@ -18,6 +18,8 @@ from vasl_templates.webapp.tests.control_tests import ControlTests
FLASK_WEBAPP_PORT = 5011
_pytest_options = None
# ---------------------------------------------------------------------
def pytest_addoption( parser ):
@ -59,6 +61,15 @@ def pytest_addoption( parser ):
help="Use the clipboard to get snippets."
)
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
def pytest_configure( config ):
"""Called after command-line options have been parsed."""
global _pytest_options
_pytest_options = config.option
import vasl_templates.webapp.tests
vasl_templates.webapp.tests.pytest_options = config.option
# ---------------------------------------------------------------------
_webapp = None
@ -85,7 +96,7 @@ def _make_webapp():
"""Create the global webapp fixture."""
# initialize
webapp_url = pytest.config.option.webapp_url #pylint: disable=no-member
webapp_url = _pytest_options.webapp_url
if webapp_url and not webapp_url.startswith( "http://" ):
webapp_url = "http://" + webapp_url
app.base_url = webapp_url if webapp_url else "http://localhost:{}".format( FLASK_WEBAPP_PORT )
@ -103,11 +114,11 @@ def _make_webapp():
# stop the browser from checking for a dirty scenario when leaving the page
kwargs["disable_close_window_check"] = 1
# check if the tests are being run headless
if pytest.config.option.headless: #pylint: disable=no-member
if _pytest_options.headless:
# yup - there is no clipboard support :-/
pytest.config.option.use_clipboard = False #pylint: disable=no-member
_pytest_options.use_clipboard = False
# check if we should disable using the clipboard for snippets
if not pytest.config.option.use_clipboard: #pylint: disable=no-member
if not _pytest_options.use_clipboard:
# NOTE: It's not a bad idea to bypass the clipboard, even when running in a browser,
# to avoid problems if something else uses the clipboard while the tests are running.
kwargs["store_clipboard"] = 1
@ -152,7 +163,7 @@ def _make_webapp():
)
except urllib.error.HTTPError as ex:
if ex.code == 404:
raise RuntimeError( "Can't get the test control port - has remote test control been enabled?" )
raise RuntimeError( "Can't get the test control port - has remote test control been enabled?" ) from ex
raise
port_no = resp.get( "port" )
if not port_no:
@ -188,20 +199,21 @@ def webdriver( request ):
from selenium import webdriver as wb
if driver == "firefox":
options = wb.FirefoxOptions()
options.set_headless( headless = pytest.config.option.headless ) #pylint: disable=no-member
options.headless = _pytest_options.headless
driver = wb.Firefox(
firefox_options = options,
log_path = os.path.join( tempfile.gettempdir(), "geckodriver.log" )
options = options,
service_log_path = os.path.join( tempfile.gettempdir(), "geckodriver.log" )
)
elif driver == "chrome":
options = wb.ChromeOptions()
options.set_headless( headless = pytest.config.option.headless ) #pylint: disable=no-member
driver = wb.Chrome( chrome_options=options )
options.headless = _pytest_options.headless
options.add_argument( "--disable-gpu" )
driver = wb.Chrome( options=options )
elif driver == "ie":
# NOTE: IE11 requires a registry key to be set:
# https://github.com/SeleniumHQ/selenium/wiki/InternetExplorerDriver#required-configuration
options = wb.IeOptions()
if pytest.config.option.headless: #pylint: disable=no-member
if _pytest_options.headless:
raise RuntimeError( "IE WebDriver cannot be run headless." )
options.IntroduceInstabilityByIgnoringProtectedModeSettings = True
options.EnsureCleanSession = True
@ -210,7 +222,7 @@ def webdriver( request ):
raise RuntimeError( "Unknown webdriver: {}".format( driver ) )
# set the browser size
words = pytest.config.option.window_size.split( "x" ) #pylint: disable=no-member
words = _pytest_options.window_size.split( "x" )
driver.set_window_size( int(words[0]), int(words[1]) )
# return the webdriver to the caller

@ -32,7 +32,8 @@ def get_git_info():
# get the latest commit ID
proc = subprocess.run(
[ "git", "log" ],
stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8"
stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8",
check=True
)
buf = proc.stdout.split( "\n" )[0]
mo = re.search( r"^commit ([a-z0-9]+)$", buf )
@ -41,7 +42,8 @@ def get_git_info():
# get the current git branch
proc = subprocess.run(
[ "git", "branch" ],
stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8"
stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8",
check=True
)
lines = [ s for s in proc.stdout.split("\n") if s.startswith("* ") ]
if len(lines) != 1:

@ -1,7 +1,7 @@
pytest==3.6.0
grpcio-tools==1.33.2
tabulate==0.8.2
lxml==4.2.4
pylint==1.9.2
pytest-pylint==0.9.0
pyinstaller==3.6
pytest==6.2.1
grpcio-tools==1.34.1
tabulate==0.8.7
lxml==4.6.2
pylint==2.6.0
pytest-pylint==0.18.0
pyinstaller==4.2

@ -1,7 +1,7 @@
# python 3.6.8
# python 3.8.7
flask==1.0.2
flask==1.1.2
pyyaml==5.3.1
pillow==7.0.0
selenium==3.12.0
click==6.7
pillow==8.1.0
selenium==3.141.0
click==7.1.2

@ -37,8 +37,9 @@ setup(
"gui": [
# NOTE: PyQt5 requirements: https://doc.qt.io/qt-5/linux.html
# Linux: mesa-libGL-devel ; @"C Development Tools and Libraries"
# nb: WebEngine seems to be broken in 5.10.1 :-/
"PyQT5==5.10.0",
# NOTE: You may need to disable VMware 3D acceleration, if QWebEngineView is crashing.
"PyQT5==5.15.2",
"PyQtWebEngine==5.15.2",
],
"dev": parse_requirements( "requirements-dev.txt" ),
},

@ -46,7 +46,7 @@ class BuildFile:
val = click.style( child.tag, fg="green" )
if line_nos:
val += ":{}".format( click.style( str(child.sourceline), fg="cyan" ) )
click.echo( "{} {} {}".format( header, val, header ) )
click.echo( "{header} {} {header}".format( val, header=header ) )
click.echo()
# dump any attributes
if attribs:

@ -179,10 +179,9 @@ def _do_main( template_pack, default_scenario, remote_debugging, debug ): #pylin
raise SimpleError( "Unexpected server check response: {}".format( resp ) )
if resp[6:] == INSTANCE_ID:
break
else:
from vasl_templates.webapp.config.constants import APP_NAME
QMessageBox.warning( None, APP_NAME, "The program is already running." )
return -1
from vasl_templates.webapp.config.constants import APP_NAME
QMessageBox.warning( None, APP_NAME, "The program is already running." )
return -1
except URLError:
# no response - the webapp server is probably still starting up
time.sleep( 0.25 )

@ -97,7 +97,7 @@ class MainWindow( QWidget ):
# initialize the layout
layout = QVBoxLayout( self )
layout.addWidget( menu_bar )
layout.setMenuBar( menu_bar )
# FUDGE! We offer the option to disable the QWebEngineView since getting it to run
# under Windows (especially older versions) is unreliable (since it uses OpenGL).
# By disabling it, the program will at least start (in particular, the webapp server),
@ -165,6 +165,9 @@ class MainWindow( QWidget ):
if self._view:
app_settings.setValue( "MainWindow/geometry", self.saveGeometry() )
self.close()
# FUDGE! We need to do this to stop PyQt 5.15.2 from complaining that the profile
# is being deleted while the page is still alive.
self._view.page().deleteLater()
# check if the scenario is dirty
def callback( is_dirty ):

@ -179,7 +179,7 @@ def dump_time_plot( players, log_file, roll_type, window_size ):
"""Dump the buffered ROLL events."""
print( tabulate.tabulate( rolls, tablefmt="plain" ) )
def onTurnTrack( evt ): #pylint: disable=unused-variable
def onTurnTrack( evt ): #pylint: disable=unused-variable,possibly-unused-variable
"""Process a TURN TRACK event."""
nonlocal rolls
if rolls:
@ -189,7 +189,7 @@ def dump_time_plot( players, log_file, roll_type, window_size ):
print( "--- {} Turn {} {} ---".format( evt["side"], evt["turnNo"], evt["phase"] ) )
print()
def onRoll( evt ) : #pylint: disable=unused-variable
def onRoll( evt ) : #pylint: disable=unused-variable,possibly-unused-variable
"""Process a ROLL event"""
# check if we should process this ROLL event
if roll_type:

@ -385,7 +385,7 @@ def get_scenario_card( scenario_id ): #pylint: disable=too-many-branches
min_turns = scenario.get( "min_turns", "0" )
max_turns = scenario.get( "max_turns", "0" )
if min_turns != "0":
if min_turns == max_turns or max_turns == "0":
if max_turns in ("0",min_turns):
args[ "TURN_COUNT" ] = friendly_fractions( min_turns, "turn", "turns" )
elif max_turns != "0":
args[ "TURN_COUNT" ] = "{}-{} turns".format( friendly_fractions(min_turns), friendly_fractions(max_turns) )

@ -52,7 +52,7 @@
<p> If you're on a Mac or Linux, you can run the program directly from the source code. Get a copy from <a href="https://github.com/pacman-ghost/vasl-templates">Github</a> in the usual way, by <tt>git clone</tt>'ing it, or downloading a ZIP and unpacking it somewhere.
<p> The web server was written and tested using Python 3.6, but it doesn't do anything particularly funky, so any recent version of Python <em>should</em> work.
<p> The web server was written and tested using Python 3.8.7, but it doesn't do anything particularly funky, so any recent version of Python <em>should</em> work.
<p> While not essential, it is <em>strongly</em> recommended that you set up a <a href="https://virtualenv.pypa.io/en/stable/">virtual environment</a> first. Then, install the requirements:
<div class="code">
@ -63,7 +63,8 @@ pip install .[gui]
<p> If you're on Windows, the Qt runtime will have been installed as part of PyQt5 (when you did the <tt>pip install</tt> above), but if you're in a virtual environment and you're getting <em>"DLL load failed"</em> errors, this is due to a problem with the way Python sets up the virtualenv. In the virtualenv's <tt>scripts/</tt> sub-directory, there should be <em>two</em> Python DLL's, so if you're missing <tt>python3.dll</tt>, copy it over from the Python installation the virtualenv was created from, and you should be good to go.
<p> If you're on Linux, you will need to install Qt 5.10.0. While your distro may have it as a package, I didn't have much luck on Fedora 27, and had to install it manually using their <a href="https://www.qt.io/download">installer</a>.
<p> If you're on Linux, you <em>may</em> need to install Qt 5.15.2. On Fedora 33, running the "gui" install above should install everything you need.
<p> Then, just run the <tt>vasl-templates</tt> command.
<h4> Running just the web server </h4>

@ -0,0 +1,3 @@
"""Module definitions."""
pytest_options = None

@ -10,6 +10,7 @@ from vasl_templates.webapp.tests.utils import \
init_webapp, select_menu_option, select_tab, click_dialog_button, \
find_child, find_children, wait_for_clipboard, \
set_scenario_date
from vasl_templates.webapp.tests import pytest_options
from vasl_templates.webapp.tests.test_vo_reports import get_vo_report
from vasl_templates.webapp.tests.test_vehicles_ordnance import add_vo
from vasl_templates.webapp.tests.test_scenario_persistence import save_scenario, load_scenario
@ -18,7 +19,7 @@ _IGNORE_CAPABILITIES = [ "T", "NT", "ST" ]
# ---------------------------------------------------------------------
@pytest.mark.skipif( pytest.config.option.short_tests, reason="--short-tests specified" ) #pylint: disable=no-member
@pytest.mark.skipif( pytest_options.short_tests, reason="--short-tests specified" )
def test_month_capabilities( webapp, webdriver ): #pylint: disable=too-many-statements
"""Test date-based capabilities that change in the middle of a year."""
@ -302,7 +303,7 @@ def test_month_capabilities( webapp, webdriver ): #pylint: disable=too-many-stat
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@pytest.mark.skipif( pytest.config.option.short_tests, reason="--short-tests specified" ) #pylint: disable=no-member
@pytest.mark.skipif( pytest_options.short_tests, reason="--short-tests specified" )
def test_kfw( webapp, webdriver ):
"""Test date-based capabilities for K:FW vehicles/ordnance."""
@ -322,7 +323,7 @@ def test_kfw( webapp, webdriver ):
# ---------------------------------------------------------------------
@pytest.mark.skipif( pytest.config.option.short_tests, reason="--short-tests specified" ) #pylint: disable=no-member
@pytest.mark.skipif( pytest_options.short_tests, reason="--short-tests specified" )
def test_theater_capabilities( webapp, webdriver ):
"""Test theater-specific capabilities."""
@ -398,7 +399,7 @@ def test_theater_capabilities( webapp, webdriver ):
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@pytest.mark.skipif( pytest.config.option.short_tests, reason="--short-tests specified" ) #pylint: disable=no-member
@pytest.mark.skipif( pytest_options.short_tests, reason="--short-tests specified" )
def test_theater_capabilities_bfp( webapp, webdriver ):
"""Test theater-specific capabilities (BFP extension)."""
@ -425,7 +426,7 @@ def test_theater_capabilities_bfp( webapp, webdriver ):
# ---------------------------------------------------------------------
@pytest.mark.skipif( pytest.config.option.short_tests, reason="--short-tests specified" ) #pylint: disable=no-member
@pytest.mark.skipif( pytest_options.short_tests, reason="--short-tests specified" )
def test_american_ordnance_note_c( webapp, webdriver ):
"""Test handling of American Ordnance Note C."""
@ -450,7 +451,7 @@ def test_american_ordnance_note_c( webapp, webdriver ):
# ---------------------------------------------------------------------
@pytest.mark.skipif( pytest.config.option.short_tests, reason="--short-tests specified" ) #pylint: disable=no-member
@pytest.mark.skipif( pytest_options.short_tests, reason="--short-tests specified" )
def test_nationality_capabilities( webapp, webdriver ):
"""Test nationality-specific capabilities."""

@ -12,6 +12,7 @@ from vasl_templates.webapp.vassal import SUPPORTED_VASSAL_VERSIONS
from vasl_templates.webapp.vasl_mod import get_vo_gpids, SUPPORTED_VASL_MOD_VERSIONS
from vasl_templates.webapp.vo import _kfw_listings #pylint: disable=protected-access
from vasl_templates.webapp.utils import compare_version_strings
from vasl_templates.webapp.tests import pytest_options
from vasl_templates.webapp.tests.utils import init_webapp, select_tab, find_child, find_children
from vasl_templates.webapp.tests.test_scenario_persistence import load_scenario
@ -19,7 +20,7 @@ _EXPECTED_MISSING_GPIDS_EXCEPTIONS = [ "6.5.0", "6.5.1", "6.6.0", "6.6.1" ]
# ---------------------------------------------------------------------
@pytest.mark.skipif( pytest.config.option.short_tests, reason="--short-tests specified" ) #pylint: disable=no-member
@pytest.mark.skipif( pytest_options.short_tests, reason="--short-tests specified" )
def test_counter_images( webapp, webdriver ): #pylint: disable=too-many-locals
"""Test that counter images are served correctly."""

@ -2,9 +2,9 @@
import re
import pytest
from selenium.webdriver.support.ui import Select
from vasl_templates.webapp.tests import pytest_options
from vasl_templates.webapp.tests.test_scenario_persistence import ALL_SCENARIO_PARAMS
from vasl_templates.webapp.tests.test_vehicles_ordnance import add_vo
from vasl_templates.webapp.tests.utils import \
@ -174,5 +174,5 @@ def test_dirty_scenario_checks( webapp, webdriver ):
for tab_id,params in ALL_SCENARIO_PARAMS.items():
for param in params:
do_test( tab_id, param )
if pytest.config.option.short_tests: #pylint: disable=no-member
if pytest_options.short_tests:
break # nb: it's a bit excessive to check *every* parameter :-/

@ -35,7 +35,8 @@ def test_jshint():
# run JSHint for the next file
proc = subprocess.run(
[ jshint, os.path.join(dname,fname) ],
stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8"
stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8",
check=False
)
if proc.stdout or proc.stderr:
print( "=== JSHint failed: {} ===".format( fname ) )

@ -10,6 +10,7 @@ from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import StaleElementReferenceException
from vasl_templates.webapp.tests import pytest_options
from vasl_templates.webapp.tests.test_scenario_persistence import save_scenario, load_scenario
from vasl_templates.webapp.tests.test_vassal import run_vassal_tests
from vasl_templates.webapp.tests.utils import init_webapp, select_tab, new_scenario, \
@ -368,7 +369,7 @@ def test_roar_matching( webapp, webdriver ):
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@pytest.mark.skipif(
pytest.config.option.webapp_url is not None, #pylint: disable=no-member
pytest_options.webapp_url is not None,
reason = "Can't test against a remote webapp server."
)
def test_roar_matching2( webapp, webdriver ):

@ -6,6 +6,7 @@ import pytest
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
from vasl_templates.webapp.tests import pytest_options
from vasl_templates.webapp.tests.utils import \
init_webapp, select_tab, find_snippet_buttons, set_template_params, wait_for, wait_for_clipboard, \
get_stored_msg, set_stored_msg_marker, find_child, find_children, adjust_html, \
@ -313,7 +314,7 @@ def test_edit_templates( webapp, webdriver ):
# However, the workaround we implemented in that script (dismissing the dialog) doesn't work here,
# and I just couldn't get things to work (not even reloading the page each time helped) :-(
@pytest.mark.skipif(
pytest.config.option.webdriver == "firefox", #pylint: disable=no-member
pytest_options.webdriver == "firefox",
reason="Selenium problems (?) cause these tests to fail under Firefox."
)
def test_snippet_images( webapp, webdriver ):

@ -7,9 +7,8 @@ import base64
import random
import typing.re #pylint: disable=import-error
import pytest
from vasl_templates.webapp.utils import TempFile, change_extn, compare_version_strings
from vasl_templates.webapp.tests import pytest_options
from vasl_templates.webapp.tests.utils import \
init_webapp, select_menu_option, get_stored_msg, set_stored_msg, set_stored_msg_marker, wait_for, \
new_scenario, set_player, find_child
@ -764,7 +763,7 @@ def run_vassal_tests( webapp, func, all_combos=None, min_vasl_version=None, vasl
# check if we want to test all VASSAL+VASL combinations (nb: if not, we test against only one combination,
# and since they all should give the same results, it doesn't matter which one.
if all_combos is None:
all_combos = not pytest.config.option.short_tests #pylint: disable=no-member
all_combos = not pytest_options.short_tests
if not all_combos:
for _ in range(0,100):
vasl_version = random.choice( vasl_versions )

@ -8,6 +8,7 @@ import pytest
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
from vasl_templates.webapp.tests import pytest_options
from vasl_templates.webapp.tests.test_scenario_persistence import load_scenario, save_scenario
from vasl_templates.webapp.tests.utils import \
init_webapp, get_nationalities, select_tab, set_template_params, find_child, find_children, \
@ -342,7 +343,7 @@ def test_duplicate_vo_entries( webapp, webdriver ):
# ---------------------------------------------------------------------
@pytest.mark.skipif( pytest.config.option.short_tests, reason="--short-tests specified" ) #pylint: disable=no-member
@pytest.mark.skipif( pytest_options.short_tests, reason="--short-tests specified" )
def test_common_vo( webapp, webdriver ): #pylint: disable=too-many-locals
"""Test loading of common vehicles/ordnance and landing craft."""
@ -415,7 +416,7 @@ def test_common_vo( webapp, webdriver ): #pylint: disable=too-many-locals
if nat in ["thai","indonesian","anzac","burmese","filipino"]: # nb: these are in the BFP extension
assert not elem.is_enabled()
continue
elif nat == "kfw-cpva" and vo_type == "vehicles":
if nat == "kfw-cpva" and vo_type == "vehicles":
assert not elem.is_enabled()
continue
elem.click()

@ -10,6 +10,7 @@ import lxml.html
import lxml.etree
import tabulate
from vasl_templates.webapp.tests import pytest_options
from vasl_templates.webapp.tests.utils import \
init_webapp, get_nationalities, select_tab, set_player, select_menu_option, click_dialog_button, \
find_child, find_children, wait_for, wait_for_clipboard
@ -431,7 +432,7 @@ def test_special_cases( webapp, webdriver ):
# ---------------------------------------------------------------------
@pytest.mark.skipif( pytest.config.option.short_tests, reason="--short-tests specified" ) #pylint: disable=no-member
@pytest.mark.skipif( pytest_options.short_tests, reason="--short-tests specified" )
def test_vo_notes_reports( webapp, webdriver ): #pylint: disable=too-many-locals
"""Check the vehicle/ordnance notes reports."""

@ -10,12 +10,13 @@ import lxml.html
import lxml.etree
import tabulate
from vasl_templates.webapp.tests import pytest_options
import vasl_templates.webapp.tests.utils as test_utils
from vasl_templates.webapp.tests.utils import init_webapp, get_nationalities, find_child, wait_for
# ---------------------------------------------------------------------
@pytest.mark.skipif( pytest.config.option.short_tests, reason="--short-tests specified" ) #pylint: disable=no-member
@pytest.mark.skipif( pytest_options.short_tests, reason="--short-tests specified" )
def test_vo_reports( webapp, webdriver ): #pylint: disable=too-many-locals
"""Check the vehicle/ordnance reports."""

@ -10,12 +10,13 @@ import uuid
from collections import defaultdict
import lxml.html
import pytest
from selenium.webdriver.support.ui import Select
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
from selenium.common.exceptions import NoSuchElementException, StaleElementReferenceException, WebDriverException
import vasl_templates.webapp.tests
# standard templates
_STD_TEMPLATES = {
"scenario": [
@ -533,7 +534,7 @@ def _get_clipboard() :
in the UI (e.g. clicking a button) and the result appearing in the clipboard, so tests
should use wait_for_clipboard() instead.
"""
if pytest.config.option.use_clipboard: #pylint: disable=no-member
if vasl_templates.webapp.tests.pytest_options.use_clipboard:
global _pyqt_app
from PyQt5.QtWidgets import QApplication
if _pyqt_app is None:
@ -627,7 +628,7 @@ _IE_HTML_TAGS = [ "<i>" ]
def adjust_html( val ):
"""Adjust HTML content for IE."""
if pytest.config.option.webdriver != "ie": #pylint: disable=no-member
if vasl_templates.webapp.tests.pytest_options.webdriver != "ie":
return val
# convert HTML tags to uppercase :-/
for tag in _IE_HTML_TAGS:

@ -193,7 +193,8 @@ def trim_image( img ):
if isinstance( img, str ):
img = Image.open( img )
# trim the screenshot (nb: we assume a white background)
bgd = Image.new( img.mode, img.size, (255,255,255,255) )
img = remove_alpha_from_image( img )
bgd = Image.new( img.mode, img.size, (255,255,255) )
diff = ImageChops.difference( img, bgd )
bbox = diff.getbbox()
return img.crop( bbox )
@ -207,9 +208,7 @@ def get_image_data( img, **kwargs ):
def remove_alpha_from_image( img ):
"""Remove the alpha channel from an image."""
img2 = Image.new( "RGB", img.size, "WHITE" )
img2.paste( img, (0,0), img )
return img2
return img.convert( "RGB" )
# ---------------------------------------------------------------------
@ -304,4 +303,3 @@ def make_formatted_day_of_month( dom ):
class SimpleError( Exception ):
"""Represents a simple error that doesn't require a stack trace (e.g. bad configuration)."""
pass

@ -445,7 +445,7 @@ class VassalShim:
try:
proc = subprocess.Popen( args2, **kwargs )
except FileNotFoundError as ex:
raise SimpleError( "Can't run the VASSAL shim (have you configured Java?): {}".format( ex ) )
raise SimpleError( "Can't run the VASSAL shim (have you configured Java?): {}".format( ex ) ) from ex
try:
proc.wait( timeout )
except subprocess.TimeoutExpired:

@ -2,11 +2,13 @@
import os
import threading
import io
import tempfile
import atexit
import logging
from selenium import webdriver
from PIL import Image
from vasl_templates.webapp import app, globvars
from vasl_templates.webapp.utils import TempFile, SimpleError, trim_image
@ -68,19 +70,19 @@ class WebDriver:
kwargs = { "executable_path": webdriver_path }
if "chromedriver" in webdriver_path:
options = webdriver.ChromeOptions()
options.set_headless( headless=True )
options.headless = True
# OMG! The chromedriver looks for Chrome/Chromium in a hard-coded, fixed location (the default
# installation directory). We offer a way here to override this.
chrome_path = app.config.get( "CHROME_PATH" )
if chrome_path:
options.binary_location = chrome_path
kwargs["chrome_options"] = options
kwargs["options"] = options
self.driver = webdriver.Chrome( **kwargs )
elif "geckodriver" in webdriver_path:
options = webdriver.FirefoxOptions()
options.set_headless( headless=True )
kwargs["firefox_options"] = options
kwargs["log_path"] = app.config.get( "GECKODRIVER_LOG",
options.headless = True
kwargs["options"] = options
kwargs["service_log_path"] = app.config.get( "GECKODRIVER_LOG",
os.path.join( tempfile.gettempdir(), "geckodriver.log" )
)
self.driver = webdriver.Firefox( **kwargs )
@ -107,12 +109,12 @@ class WebDriver:
def get_screenshot( self, html, window_size, large_window_size=None ):
"""Get a preview screenshot of the specified HTML."""
def do_get_screenshot( fname ): #pylint: disable=missing-docstring
self.driver.save_screenshot( fname )
return trim_image( fname )
def do_get_screenshot(): #pylint: disable=missing-docstring
data = self.driver.get_screenshot_as_png()
img = Image.open( io.BytesIO( data ) )
return trim_image( img )
with TempFile( extn=".html", mode="w", encoding="utf-8" ) as html_tempfile, \
TempFile( extn=".png" ) as screenshot_tempfile:
with TempFile( extn=".html", mode="w", encoding="utf-8" ) as html_tempfile:
# NOTE: We could do some funky Javascript stuff to load the browser directly from the string,
# but using a temp file is straight-forward and pretty much guaranteed to work :-/
@ -121,16 +123,15 @@ class WebDriver:
self.driver.get( "file://{}".format( html_tempfile.name ) )
# take a screenshot of the HTML
screenshot_tempfile.close( delete=False )
self.driver.set_window_size( window_size[0], window_size[1] )
img = do_get_screenshot( screenshot_tempfile.name )
img = do_get_screenshot()
retry_ratio = float( app.config.get( "WEBDRIVER_SCREENSHOT_RETRY_RATIO", 0.8 ) )
if img.width > window_size[0]*retry_ratio or img.height > window_size[1]*retry_ratio:
# FUDGE! The webdriver sometimes has trouble when the image is close to the edge of the canvas
# (it gets cropped), so we retry even if we appear to be completely within the canvas.
if large_window_size:
self.driver.set_window_size( large_window_size[0], large_window_size[1] )
img = do_get_screenshot( screenshot_tempfile.name )
img = do_get_screenshot()
return img
def get_snippet_screenshot( self, snippet_id, snippet ):

Loading…
Cancel
Save