Skip to content

Commit 5d21c51

Browse files
committed
Add phet laboratories
0 parents  commit 5d21c51

File tree

5 files changed

+231
-0
lines changed

5 files changed

+231
-0
lines changed

.gitignore

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
*.py[cod]
2+
3+
# C extensions
4+
*.so
5+
6+
# Packages
7+
*.egg
8+
*.egg-info
9+
dist
10+
build
11+
eggs
12+
parts
13+
bin
14+
var
15+
sdist
16+
develop-eggs
17+
.installed.cfg
18+
lib
19+
lib64
20+
21+
# Installer logs
22+
pip-log.txt
23+
24+
# Unit test / coverage reports
25+
.coverage
26+
.tox
27+
nosetests.xml
28+
29+
# Translations
30+
*.mo
31+
32+
# Mr Developer
33+
.mr.developer.cfg
34+
.project
35+
.pydevproject

README.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
PhET plug-in
2+
=====================
3+
4+
The `LabManager <http://github.com/gateway4labs/labmanager/>`_ provides an API for
5+
supporting more Remote Laboratory Management Systems (RLMS). This project is the
6+
implementation for the `PhET
7+
http://http://phet.colorado.edu/>`_ virtual laboratories.
8+
9+
Usage
10+
-----
11+
12+
First install the module::
13+
14+
$ pip install git+https://github.com/gateway4labs/rlms_phet.git
15+
16+
Then add it in the LabManager's ``config.py``::
17+
18+
RLMS = ['phet', ... ]
19+
20+
Profit!

g4l_rlms_phet.py

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# -*-*- encoding: utf-8 -*-*-
2+
3+
import re
4+
import sys
5+
from bs4 import BeautifulSoup
6+
import json
7+
import datetime
8+
import uuid
9+
import hashlib
10+
import urllib2
11+
12+
from flask.ext.wtf import TextField, PasswordField, Required, URL, ValidationError
13+
14+
from labmanager.forms import AddForm, RetrospectiveForm, GenericPermissionForm
15+
from labmanager.rlms import register, Laboratory
16+
from labmanager.rlms.base import BaseRLMS, BaseFormCreator, Capabilities, Versions
17+
18+
def get_module(version):
19+
"""get_module(version) -> proper module for that version
20+
21+
Right now, a single version is supported, so this module itself will be returned.
22+
When compatibility is required, we may change this and import different modules.
23+
"""
24+
# TODO: check version
25+
return sys.modules[__name__]
26+
27+
class PhETAddForm(AddForm):
28+
29+
def __init__(self, add_or_edit, *args, **kwargs):
30+
super(PhETAddForm, self).__init__(*args, **kwargs)
31+
self.add_or_edit = add_or_edit
32+
33+
@staticmethod
34+
def process_configuration(old_configuration, new_configuration):
35+
return new_configuration
36+
37+
class PhETPermissionForm(RetrospectiveForm):
38+
pass
39+
40+
class PhETLmsPermissionForm(PhETPermissionForm, GenericPermissionForm):
41+
pass
42+
43+
class PhETFormCreator(BaseFormCreator):
44+
45+
def get_add_form(self):
46+
return PhETAddForm
47+
48+
def get_permission_form(self):
49+
return PhETPermissionForm
50+
51+
def get_lms_permission_form(self):
52+
return PhETLmsPermissionForm
53+
54+
FORM_CREATOR = PhETFormCreator()
55+
56+
class RLMS(BaseRLMS):
57+
58+
def __init__(self, configuration):
59+
self.configuration = json.loads(configuration or '{}')
60+
61+
def get_version(self):
62+
return Versions.VERSION_1
63+
64+
def get_capabilities(self):
65+
return [ Capabilities.WIDGET ]
66+
67+
def test(self):
68+
json.loads(self.configuration)
69+
# TODO
70+
return None
71+
72+
def get_laboratories(self):
73+
index_html = urllib2.urlopen("https://phet.colorado.edu/en/simulations/index").read()
74+
soup = BeautifulSoup(index_html)
75+
76+
laboratories = []
77+
78+
for h2 in soup.find_all("h2"):
79+
parent_identifier = h2.parent.get('id')
80+
# Just checking that the format has not changed
81+
if parent_identifier and len(parent_identifier) == 1 and parent_identifier in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
82+
for link in h2.parent.find_all("a"):
83+
link_href = 'https://phet.colorado.edu%s' % link.get('href')
84+
name = link.find("span").text
85+
laboratories.append(Laboratory(name = name, laboratory_id = link_href))
86+
87+
return laboratories
88+
89+
def reserve(self, laboratory_id, username, institution, general_configuration_str, particular_configurations, request_payload, user_properties, *args, **kwargs):
90+
91+
laboratory_html = urllib2.urlopen(laboratory_id).read()
92+
soup = BeautifulSoup(laboratory_html)
93+
94+
url = ""
95+
96+
# If there's a "Run in HTML5" button
97+
html5_url = soup.find("a", class_="sim-button", text=re.compile("HTML5"))
98+
99+
if html5_url:
100+
# Then that's the URL
101+
url = html5_url.get("href")
102+
else:
103+
# Otherwise, if there is a embeddable-text
104+
embed_text = soup.find(id="embeddable-text").text
105+
106+
# Then, check what's inside:
107+
embed_soup = BeautifulSoup(embed_text)
108+
109+
# If it's an iframe, the src is the URL
110+
iframe_tag = embed_soup.find("iframe")
111+
if iframe_tag:
112+
url = iframe_tag.get("src")
113+
else:
114+
# Otherwise, the link is the URL
115+
a_tag = embed_soup.find("a")
116+
url = a_tag.get("href")
117+
118+
return {
119+
'reservation_id' : url,
120+
'load_url' : url
121+
}
122+
123+
def load_widget(self, reservation_id, widget_name):
124+
return {
125+
'url' : reservation_id
126+
}
127+
128+
def list_widgets(self, laboratory_id):
129+
default_widget = dict( name = 'default', description = 'Default widget' )
130+
return [ default_widget ]
131+
132+
register("PhET", ['1.0'], __name__)
133+
134+
def main():
135+
rlms = RLMS("{}")
136+
laboratories = rlms.get_laboratories()
137+
print len(laboratories)
138+
print
139+
print laboratories[:10]
140+
print
141+
for lab in laboratories[:5]:
142+
print rlms.reserve(lab.laboratory_id, 'tester', 'foo', '', '', '', '')
143+
144+
145+
if __name__ == '__main__':
146+
main()

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
beautifulsoup4==4.3.2

setup.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#-*-*- encoding: utf-8 -*-*-
2+
from setuptools import setup
3+
4+
classifiers=[
5+
"Development Status :: 3 - Alpha",
6+
"Environment :: Web Environment",
7+
"Intended Audience :: Developers",
8+
"License :: Freely Distributable",
9+
"Operating System :: OS Independent",
10+
"Programming Language :: Python",
11+
"Programming Language :: Python :: 2",
12+
"Topic :: Internet :: WWW/HTTP",
13+
"Topic :: Software Development :: Libraries :: Application Frameworks",
14+
]
15+
16+
cp_license="MIT"
17+
install_requires=["beautifulsoup4"]
18+
19+
setup(name='g4l_rlms_phet',
20+
version='0.1',
21+
description="PhET plug-in in the gateway4labs project",
22+
classifiers=classifiers,
23+
author='Pablo Orduña',
24+
author_email='[email protected]',
25+
url='http://github.com/gateway4labs/rlms_phet/',
26+
install_requires=install_requires,
27+
license=cp_license,
28+
py_modules=['g4l_rlms_phet'],
29+
)

0 commit comments

Comments
 (0)