Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exhibition widget and a more sane repr for closed UniverseWidget #200

Closed
wants to merge 93 commits into from
Closed
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
34f0b9f
adds a sudo widget
tjduigna Jul 14, 2020
b2d5c2a
trajectory first
tjduigna Jul 14, 2020
cf48423
disclaimer about tensor
tjduigna Jul 14, 2020
15ca9af
dont spam notebook with closed widget repr
tjduigna Jul 14, 2020
79d8618
typo and order
tjduigna Jul 14, 2020
932171d
some poc files and better tsconfig
tjduigna Jul 16, 2020
f69e007
more direct approach
tjduigna Jul 17, 2020
643e8a4
minimal not working example
tjduigna Jul 18, 2020
31328df
typescript scene more or less works
tjduigna Jul 18, 2020
47f0127
a functional scene
tjduigna Jul 18, 2020
9d379d8
hud supports longer text, setup for hud banner updates on selected
tjduigna Jul 19, 2020
ef755a9
stop scope creep
tjduigna Jul 19, 2020
401170c
no sticky banner
tjduigna Jul 19, 2020
ee7bf3c
need references to lights
tjduigna Jul 19, 2020
4f9af09
removes promise chaining
tjduigna Jul 23, 2020
e7d1591
revise resize and selenium script
tjduigna Jul 25, 2020
13d20be
remove logging es module
tjduigna Jul 25, 2020
02d5b5d
Merge branch 'issue-192' of https://github.com/exa-analytics/exatomic…
tjduigna Jul 25, 2020
599cb6e
no test in selenium file
tjduigna Jul 25, 2020
8124029
codacy pls
tjduigna Jul 25, 2020
1d4d787
tuck selenium into func def
tjduigna Jul 25, 2020
dbe7ec7
codacy pls
tjduigna Jul 25, 2020
6a2727b
setup and teardown for selenium script
tjduigna Jul 26, 2020
a904d8a
what about ci
tjduigna Jul 26, 2020
66a2fdc
quotes
tjduigna Jul 26, 2020
d7d01fb
simple case
tjduigna Jul 26, 2020
8753780
install chrome driver in CI
tjduigna Jul 26, 2020
345609d
towards chrome driver
tjduigna Jul 26, 2020
9fcda1f
which where
tjduigna Jul 26, 2020
507e5ce
could it be easy
tjduigna Jul 26, 2020
656fda5
pick up by pytest
tjduigna Jul 26, 2020
9e75c76
guh /usr
tjduigna Jul 26, 2020
1c636df
cleanup
tjduigna Jul 26, 2020
3b0d44d
back to manual chromedriver
tjduigna Jul 26, 2020
3b3005b
maybe a timeout issue
tjduigna Jul 26, 2020
6f66b4e
add xvfb
tjduigna Jul 26, 2020
29dfb47
tidy chromedriver installer
tjduigna Oct 31, 2020
4620524
Merge branch 'issue-206' of https://github.com/exa-analytics/exatomic…
tjduigna Oct 31, 2020
6ed594c
Merge branch 'issue-206' of https://github.com/exa-analytics/exatomic…
tjduigna Oct 31, 2020
7cc37d1
re-vamp test_widget for extensibility
tjduigna Nov 1, 2020
11ccd58
pleasing codacy
tjduigna Nov 1, 2020
790688a
less indent
tjduigna Nov 1, 2020
66e3dee
more flexible driver support
tjduigna Nov 1, 2020
ddf711f
occam pls
tjduigna Nov 1, 2020
bd44f3b
try firefox
tjduigna Nov 1, 2020
9766997
firefox addon
tjduigna Nov 1, 2020
be850ff
tidy travis for both browsers
tjduigna Nov 1, 2020
4b2af6d
firefox latest
tjduigna Nov 1, 2020
792bc1d
dont delete the driver
tjduigna Nov 1, 2020
47705a0
firefox pls
tjduigna Nov 1, 2020
1f289bf
headless pls
tjduigna Nov 7, 2020
a9144b1
Merge branch 'master' of https://github.com/exa-analytics/exatomic in…
tjduigna Nov 7, 2020
9644051
listen to travis docs
tjduigna Nov 7, 2020
da54cbf
escape ampersand
tjduigna Nov 7, 2020
3ec06d5
semi bois
tjduigna Nov 7, 2020
b8be85c
travis pls
tjduigna Nov 7, 2020
3a3c7a3
mac before install debug
tjduigna Nov 7, 2020
d4dea18
double quotes
tjduigna Nov 7, 2020
1c1fcf7
or some double quotes maybe
tjduigna Nov 7, 2020
8a459cc
re-organize before install
tjduigna Nov 7, 2020
b677d30
hold off xvfb to see if progress for mac
tjduigna Nov 7, 2020
fd968cd
single escape space
tjduigna Nov 8, 2020
06435d8
fixes scene growing out of bounds
tjduigna Dec 23, 2020
c3bc7db
handle the exceptions
tjduigna Dec 23, 2020
dcbbdb4
Merge remote-tracking branch 'org/master' into issue-192
tjduigna Dec 23, 2020
88f8028
update mac chrome path and tidy for codacy
tjduigna Dec 23, 2020
ff1d653
more work on mac chrome
tjduigna Dec 23, 2020
d0e1519
try local
tjduigna Dec 23, 2020
949533f
simpler driver approach
tjduigna Dec 23, 2020
3551487
mac pls
tjduigna Dec 23, 2020
6cc52e0
remove xvfb
tjduigna Dec 23, 2020
04ce628
browser path
tjduigna Dec 23, 2020
62475e6
put drivers in PATH
tjduigna Dec 23, 2020
1a164d1
debug the build server
tjduigna Dec 23, 2020
856a547
chrome stable on linux
tjduigna Dec 23, 2020
fe41b2d
handle debug exception and tidy travis
tjduigna Dec 23, 2020
176179b
proper use of browser path
tjduigna Dec 23, 2020
d6f06ad
opps
tjduigna Dec 23, 2020
363b05f
cache miniconda
tjduigna Dec 23, 2020
ebc4359
paths pls
tjduigna Dec 23, 2020
2f7cf9e
hope it doesn't unravel
tjduigna Dec 23, 2020
321cbcb
quotes pls
tjduigna Dec 23, 2020
105c28e
and then
tjduigna Dec 23, 2020
b210723
remove caching
tjduigna Dec 23, 2020
6e1a4e7
really try to find chrome
tjduigna Dec 23, 2020
c7bce5a
spaces...
tjduigna Dec 23, 2020
5e6045b
try pinning node
tjduigna Dec 23, 2020
1371a52
all in on block if syntax in travis
tjduigna Dec 23, 2020
720a33f
collapse after_success logic
tjduigna Dec 23, 2020
fc3a2c0
add selenium to windows build
tjduigna Dec 26, 2020
35d8575
skip test on windows
tjduigna Jan 4, 2021
08b8003
Merge branch 'issue-192' of https://github.com/exa-analytics/exatomic…
tjduigna Jan 4, 2021
dee98ea
pin pandas for now
tjduigna Jan 4, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ matrix:
python: 3.8
env: PYTHONVER=3.8

addons:
chrome: stable

before_install:
- if [[ $TRAVIS_OS_NAME == "osx" ]]; then
/Applications/Google\\ Chrome.app/Contents/MacOS/Google\\ Chrome --headless --disable-gpu --no-sandbox --remote-debugging-port=9222 http://localhost &;
else
google-chrome-stable --headless --disable-gpu --no-sandbox --remote-debugging-port=9222 http://localhost &;
fi;

install:
- if [[ $TRAVIS_OS_NAME == "osx" ]]; then
wget https://repo.continuum.io/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -O miniconda.sh;
Expand All @@ -52,7 +62,7 @@ install:
- conda install -q -c exaanalytics exa>=0.5.24
- conda install -q -c conda-forge six>=1.0 numexpr>=2.0 ipywidgets>=7.0 bokeh scipy>=1.4
- conda install -q -c conda-forge coveralls coverage pytest pytest-cov
- conda install -q -c anaconda h5py
- conda install -q -c anaconda h5py selenium
- if [[ ${TRAVIS_OS_NAME} == "linux" ]] && [[ ${TRAVIS_PULL_REQUEST} == false ]] && [[ ${TRAVIS_PULL_REQUEST_BRANCH} == "" ]] && [[ ${TRAVIS_BRANCH} == "master" ]]; then
conda install -q -c conda-forge sphinx sphinx_rtd_theme ply pandoc pypandoc nbsphinx ipython;
conda install -q conda-build conda-verify anaconda-client twine;
Expand Down
159 changes: 159 additions & 0 deletions auto_widget.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
#!/usr/bin/env python
"""

Assumes the following environment:

export BROWSER=/path/to/chrome/executable

pip install selenium

And that a chromedriver version matching BROWSER
is in the PATH. (See install-chromedriver.sh)

Note:
Hit enter to pass a failure to load extension
and continue the test. Not sure why disable-extensions
does not suppress that pop-up.

"""
import os
import shutil
from uuid import uuid4
from time import sleep
import subprocess as sp

from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.chrome.options import Options


PORT = 8889
CONSOLE_PORT = 9222
TOKEN = str(uuid4())
TIMEOUT = 30


def start_notebook_server():
os.makedirs(TOKEN, exist_ok=True)
return sp.Popen(['jupyter', 'notebook', '--no-browser',
f'--NotebookApp.port={PORT}',
f'--NotebookApp.token={TOKEN}'],
stdout=sp.PIPE, stderr=sp.PIPE,
cwd=TOKEN)


def click_by_css(driver, wait, css):
wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, css))
)
[obj] = driver.find_elements_by_css_selector(css)
obj.click()


def run_notebook_widget():
options = Options()

options.binary_location = os.getenv('BROWSER', 'usr/bin/google-chrome-stable')
options.headless = True
options.add_argument('--no-sandbox')
options.add_argument('--disable-gpu')
options.add_argument('--disable-extensions')
options.add_argument('--disable-dev-shm-usage')
options.add_argument(f'--remote-debugging-port={CONSOLE_PORT}')

notebook = f'http://localhost:{PORT}/?token={TOKEN}'
print(notebook)

with webdriver.Chrome(options=options) as driver:
wait = WebDriverWait(driver, TIMEOUT)
driver.get(notebook)

# click on new notebook dropdown
click_by_css(driver, wait, '#new-dropdown-button')
# primary notebook server window
initial_handles = driver.window_handles
# spawns new notebook
click_by_css(driver, wait, '#kernel-python3 > a')

# wait for new notebook
wait.until(
lambda driver: len(initial_handles) != len(driver.window_handles)
)
# switch to new notebook
driver.switch_to.window(driver.window_handles[1])

# select the first input cell
cell = '#notebook-container > div > div.input > div.inner_cell > div.input_area'
click_by_css(driver, wait, cell)

# input some text
run = 'import exatomic; exatomic.widgets.widget_base.Scene()'
ActionChains(driver).send_keys(run).perform()
[cell] = driver.find_elements_by_css_selector(cell)

# execute the cell
(ActionChains(driver).key_down(Keys.SHIFT).key_down(Keys.ENTER)
.key_up(Keys.SHIFT).key_up(Keys.ENTER).perform())
print('should show widget now')

# touch the rendered canvas
scene = ('#notebook-container > div.cell.code_cell.rendered.unselected > div.output_wrapper '
'> div.output > div > div.output_subarea.jupyter-widgets-view > div > canvas')
click_by_css(driver, wait, scene)

driver.get_screenshot_as_file(f'{TOKEN}/widget.png')

print('interacted with scene')

# shut down the new notebook
menu = '#filelink'
click_by_css(driver, wait, menu)
print('clicked on file menu button')

current_handles = driver.window_handles
close = '#close_and_halt > a'
click_by_css(driver, wait, close)
print('clicked on close and halt')

# may trigger "Leave without saving? alert"
wait.until(EC.alert_is_present())
driver.switch_to.alert.accept()
print('caught alert about unsaved notebook')

# wait until second notebook window is closed
wait.until(
lambda driver: len(current_handles) != len(driver.window_handles)
)

# switch back to server home window
driver.switch_to.window(driver.window_handles[0])
shutdown = '#shutdown'
print('closing notebook server down from UI')
click_by_css(driver, wait, shutdown)
driver.close()
print('closed server home window')


if __name__ == '__main__':
print("""\
Assumes the following environment:

export BROWSER=/path/to/chrome/executable

pip install selenium

May get a "Failed to load extension" pop-up when
starting chrome via selenium. By hitting enter,
the test will continue and should run to completion.
""")
server = start_notebook_server()
try:
sleep(0.2)
run_notebook_widget()
finally:
server.kill()
shutil.rmtree(TOKEN)
61 changes: 61 additions & 0 deletions exatomic/widgets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,64 @@
# Distributed under the terms of the Apache License 2.0

from .widget import TensorContainer, DemoContainer, DemoUniverse, UniverseWidget

def exhibition_widget():
"""An exhibition widget from static resources
that contains enough data to demonstrate numerous pieces
of functionality in the UniverseWidget.

Control each scene individually by selecting active
scenes based on the index of their layout reading
left to right, top to bottom. The Camera tab allows
for linking cameras across scenes. The Fill tab
controls the atomic display model and Axis will display
a unit vector (defaults to the origin).

Returns:
UniverseWidget featuring the application.
scene 0: trajectory animation (Animate tab)
scene 1: orbital isosurfaces (Fields, Contours tabs)
scene 2: NMR shielding tensor (Tensor tab)

Note:
All scenes are active by default and not all required
data are exposed in each scene. Therefore, "unselect"
active scenes in the Active Scenes tab (at least until
there is better exception handling on the JS side).

Note:
This widget provides test cases for marching cubes
(and marching squares) over 3D (2D) scalar fields, animated
trajectories, and plotting parametric surfaces, but
not all at the same time. The aim is to provide a
complex enough test case that covers a good portion of
the JS code so that updates can be checked (albeit in
a time-consuming manner). It may also serve to uncover
python-related bugs related to a UniverseWidget housing
multiple independent UniverseScenes.

Note:
The use of an entire tensor table is not well supported
by the application yet. The aim is to improve functionality
to be similar to the functionality for isosurfaces.

"""
import exatomic
from exatomic import gaussian

trj_file = 'H2O.traj.xyz'
orb_file = 'g09-ch3nh2-631g.out'
nmr_file = 'g16-nitromalonamide-6-31++g-nmr.out'

trj = exatomic.XYZ(
exatomic.base.resource(trj_file)).to_universe()

orb = gaussian.Output(
exatomic.base.resource(orb_file)).to_universe()
orb.add_molecular_orbitals()

nmr = gaussian.Output(
exatomic.base.resource(nmr_file)).to_universe()
nmr.tensor = nmr.nmr_shielding

return exatomic.UniverseWidget(trj, orb, nmr)
7 changes: 7 additions & 0 deletions exatomic/widgets/tests/test_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@
H 0.0 0.0 0.35
'''

class TestExhibitionWidget(TestCase):

def test_exhibition_widget(self):
import exatomic
w = exatomic.widgets.exhibition_widget()
self.assertEqual(len(w.scenes), 3)

class TestDemoContainer(TestCase):
def setUp(self):
self.box = DemoContainer()
Expand Down
3 changes: 3 additions & 0 deletions exatomic/widgets/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,9 @@ def _axis(b):

return mainopts

def __repr__(self):
return self.__class__.__name__ + f'({len(self.scenes)},closed)'

def __init__(self, *unis, **kwargs):
scenekwargs = kwargs.pop('scenekwargs', {})
#scenekwargs.update({'uni': True, 'test': False})
Expand Down
20 changes: 20 additions & 0 deletions exatomic/widgets/widget_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,26 @@
_vboxlo, _bboxlo, _ListDict,
Folder, GUIBox, gui_field_widgets)

@register
class Scene(DOMWidget):
_model_module_version = Unicode(__js_version__).tag(sync=True)
_view_module_version = Unicode(__js_version__).tag(sync=True)
_view_module = Unicode('exatomic').tag(sync=True)
_model_module = Unicode('exatomic').tag(sync=True)
_model_name = Unicode('SceneModel').tag(sync=True)
_view_name = Unicode('SceneView').tag(sync=True)
_inited = Bool(False).tag(sync=True)
flag = Bool(True).tag(sync=True)


def close(self):
self.send({'type': 'close'})
super().close()

def _handle_custom_msg(self, msg, callback):
if msg['type'] == 'init':
self._inited = True


@register
class ExatomicScene(DOMWidget):
Expand Down
58 changes: 58 additions & 0 deletions install-chromedriver.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/usr/bin/env bash

echo """
Installer script to set up chromedriver for selenium.
First installs some linux dependencies for this script.
Then installs google-chrome-stable from google repository.
Uses that version of chrome to install chromedriver into PATH.
This should work for linux systems to run headless selenium
tests against chrome.

On WSL, however, installing chrome this way does not work in
headless mode. You can still run the selenium tests by pointing
to the chrome executable path from Windows.

Note:
WSL environment should look something like:
tjduigna marked this conversation as resolved.
Show resolved Hide resolved

export DISPLAY=:0
export BROWSER=/mnt/c/Program\ Files\ \(x86\)/Google/Chrome/Application/chrome.exe
"""

ON_WSL=1 # 1 if on WSL
CHROME_WINDOWS_MAJOR_VER=84 # check your chrome version

# ======

CHROME_DRIVER_ARTIFACT=chromedriver_linux64.zip
CHROME_DRIVER_DEST=/usr/local/bin/chromedriver
CHROME_DEB=google-chrome-stable_current_amd64.deb

# Clean workspace
rm ./${CHROME_DRIVER_ARTIFACT}
sudo rm ${CHROME_DRIVER_DEST}
rm ./${CHROME_DEB}

# Install dependencies
sudo apt-get install -y openjdk-8-jre-headless xvfb libxi6 libgconf-2-4

if [[ "${ON_WSL}" == 0 ]]; then
# Download chrome if normal linux
wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
wget https://dl.google.com/linux/direct/${CHROME_DEB}
sudo dpkg -i ${CHROME_DEB}
sudo apt -f install
sudo dpkg -i ${CHROME_DEB}
CHROME_DRIVER_VERSION=$(google-chrome-stable --version | cut -d ' ' -f 3)
else
CHROME_SUFFIX="_${CHROME_WINDOWS_MAJOR_VER}"
CHROME_DRIVER_VERSION=$(curl -sS https://chromedriver.storage.googleapis.com/LATEST_RELEASE${CHROME_SUFFIX})
fi

# Install chromedriver
wget -N https://chromedriver.storage.googleapis.com/${CHROME_DRIVER_VERSION}/${CHROME_DRIVER_ARTIFACT} -P ./
unzip ./${CHROME_DRIVER_ARTIFACT} -d ./
rm ./${CHROME_DRIVER_ARTIFACT}
sudo mv -f ./chromedriver ${CHROME_DRIVER_DEST}
sudo chown root:root ${CHROME_DRIVER_DEST}
sudo chmod 0755 ${CHROME_DRIVER_DEST}
Loading