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

Commit

Permalink
PEP8 (pylti#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
frankwiles authored and ryanhiebert committed Mar 3, 2017
1 parent e812fcd commit f7db203
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 76 deletions.
5 changes: 3 additions & 2 deletions src/lti/contrib/django/django_tool_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from lti import ToolProvider
from django.shortcuts import redirect


class DjangoToolProvider(ToolProvider):
'''
ToolProvider that works with Django requests
Expand All @@ -14,8 +15,8 @@ def from_django_request(cls, secret=None, request=None):
params = request.POST.copy()
# django shoves a bunch of other junk in META that we don't care about
headers = dict([(k, request.META[k])
for k in request.META if \
k.upper().startswith('HTTP_') or \
for k in request.META if
k.upper().startswith('HTTP_') or
k.upper().startswith('CONTENT_')])
url = request.build_absolute_uri()
return cls.from_unpacked_request(secret, params, url, headers)
Expand Down
1 change: 1 addition & 0 deletions src/lti/contrib/flask/flask_tool_provider.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from lti import ToolProvider


class FlaskToolProvider(ToolProvider):
'''
ToolProvider that works with Flask requests
Expand Down
25 changes: 16 additions & 9 deletions src/lti/launch_params.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import sys
from collections import defaultdict, MutableMapping
from collections import MutableMapping

from . import DEFAULT_LTI_VERSION

py = sys.version_info
if py < (2, 6, 0): bytes=str
py = sys.version_info
if py < (2, 6, 0):
bytes = str


def touni(s, enc='utf8', err='strict'):
return s.decode(enc, err) if isinstance(s, bytes) else unicode(s)
Expand Down Expand Up @@ -82,12 +84,15 @@ def touni(s, enc='utf8', err='strict'):
'text'
]

LAUNCH_PARAMS = LAUNCH_PARAMS_REQUIRED + \
LAUNCH_PARAMS_RECOMMENDED + \
LAUNCH_PARAMS_RETURN_URL + \
LAUNCH_PARAMS_OAUTH + \
LAUNCH_PARAMS_LIS + \
LAUNCH_PARAMS_CANVAS
LAUNCH_PARAMS = (
LAUNCH_PARAMS_REQUIRED +
LAUNCH_PARAMS_RECOMMENDED +
LAUNCH_PARAMS_RETURN_URL +
LAUNCH_PARAMS_OAUTH +
LAUNCH_PARAMS_LIS +
LAUNCH_PARAMS_CANVAS
)


def valid_param(param):
if param.startswith('custom_') or param.startswith('ext_'):
Expand All @@ -96,12 +101,14 @@ def valid_param(param):
return True
return False


class InvalidLaunchParamError(ValueError):

def __init__(self, param):
message = "{} is not a valid launch param".format(param)
super(Exception, self).__init__(message)


class LaunchParams(MutableMapping):
"""
Represents the params for an LTI launch request. Provides dict-like
Expand Down
5 changes: 3 additions & 2 deletions src/lti/outcome_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
'post_request'
]


class OutcomeRequest(object):
'''
Class for consuming & generating LTI Outcome Requests.
Expand Down Expand Up @@ -136,8 +137,8 @@ def post_outcome_request(self, **kwargs):
'OutcomeRequest does not have all required attributes')

header_oauth = OAuth1(self.consumer_key, self.consumer_secret,
signature_type=SIGNATURE_TYPE_AUTH_HEADER,
force_include_body=True, **kwargs)
signature_type=SIGNATURE_TYPE_AUTH_HEADER,
force_include_body=True, **kwargs)

headers = {'Content-type': 'application/xml'}
resp = requests.post(self.lis_outcome_service_url, auth=header_oauth,
Expand Down
3 changes: 2 additions & 1 deletion src/lti/tool_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
ROLES_STUDENT = ['student', 'learner']
ROLES_INSTRUCTOR = ['instructor', 'faculty', 'staff']


class ToolBase(object):

def __init__(self, consumer_key=None, consumer_secret=None, params=None):
Expand Down Expand Up @@ -69,7 +70,7 @@ def get_ext_param(self, key):
def to_params(self):
params = dict(self.launch_params)
# stringify any list values
for k,v in params.items():
for k, v in params.items():
if isinstance(v, list):
params[k] = ','.join(v)
return params
134 changes: 83 additions & 51 deletions src/lti/tool_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,29 @@
from .utils import InvalidLTIConfigError

VALID_ATTRIBUTES = [
'title',
'description',
'launch_url',
'secure_launch_url',
'icon',
'secure_icon',
'cartridge_bundle',
'cartridge_icon',
'vendor_code',
'vendor_name',
'vendor_description',
'vendor_url',
'vendor_contact_email',
'vendor_contact_name'
'title',
'description',
'launch_url',
'secure_launch_url',
'icon',
'secure_icon',
'cartridge_bundle',
'cartridge_icon',
'vendor_code',
'vendor_name',
'vendor_description',
'vendor_url',
'vendor_contact_email',
'vendor_contact_name'
]

NSMAP = {
'blti': 'http://www.imsglobal.org/xsd/imsbasiclti_v1p0',
'xsi': "http://www.w3.org/2001/XMLSchema-instance",
'lticp': 'http://www.imsglobal.org/xsd/imslticp_v1p0',
'lticm': 'http://www.imsglobal.org/xsd/imslticm_v1p0',
}
}


class ToolConfig(object):
'''
Expand Down Expand Up @@ -112,7 +113,7 @@ def process_xml(self, xml):
'''
Parse tool configuration data out of the Common Cartridge LTI link XML.
'''
root = objectify.fromstring(xml, parser = etree.XMLParser())
root = objectify.fromstring(xml, parser=etree.XMLParser())
# Parse all children of the root node
for child in root.getchildren():
if 'title' in child.tag:
Expand Down Expand Up @@ -175,17 +176,22 @@ def process_xml(self, xml):

self.set_ext_params(platform, properties)

def recursive_options(self,element,params):
def recursive_options(self, element, params):
for key, val in sorted(params.items()):
if isinstance(val, dict):
options_node = etree.SubElement(element,
'{%s}%s' %(NSMAP['lticm'], 'options'), name =
key)
options_node = etree.SubElement(
element,
'{%s}%s' % (NSMAP['lticm'], 'options'),
name=key,
)
for key, val in sorted(val.items()):
self.recursive_options(options_node,{key:val})
self.recursive_options(options_node, {key: val})
else:
param_node = etree.SubElement(element, '{%s}%s'
%(NSMAP['lticm'], 'property'), name = key)
param_node = etree.SubElement(
element,
'{%s}%s' % (NSMAP['lticm'], 'property'),
name=key,
)
param_node.text = val

def to_xml(self, opts=defaultdict(lambda: None)):
Expand All @@ -195,60 +201,86 @@ def to_xml(self, opts=defaultdict(lambda: None)):
if not self.launch_url or not self.secure_launch_url:
raise InvalidLTIConfigError('Invalid LTI configuration')


root = etree.Element('cartridge_basiclti_link', attrib = {
'{%s}%s' %(NSMAP['xsi'], 'schemaLocation'): 'http://www.imsglobal.org/xsd/imslticc_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticc_v1p0.xsd http://www.imsglobal.org/xsd/imsbasiclti_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imsbasiclti_v1p0p1.xsd http://www.imsglobal.org/xsd/imslticm_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticm_v1p0.xsd http://www.imsglobal.org/xsd/imslticp_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticp_v1p0.xsd',
'xmlns': 'http://www.imsglobal.org/xsd/imslticc_v1p0'
}, nsmap = NSMAP)
root = etree.Element(
'cartridge_basiclti_link',
attrib={
'{%s}%s' % (NSMAP['xsi'], 'schemaLocation'): 'http://www.imsglobal.org/xsd/imslticc_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticc_v1p0.xsd http://www.imsglobal.org/xsd/imsbasiclti_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imsbasiclti_v1p0p1.xsd http://www.imsglobal.org/xsd/imslticm_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticm_v1p0.xsd http://www.imsglobal.org/xsd/imslticp_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticp_v1p0.xsd',
'xmlns': 'http://www.imsglobal.org/xsd/imslticc_v1p0',
},
nsmap=NSMAP,
)

for key in ['title', 'description', 'launch_url', 'secure_launch_url']:
option = etree.SubElement(root, '{%s}%s' %(NSMAP['blti'], key))
option = etree.SubElement(root, '{%s}%s' % (NSMAP['blti'], key))
option.text = getattr(self, key)

vendor_keys = ['name', 'code', 'description', 'url']
if any('vendor_' + key for key in vendor_keys) or\
self.vendor_contact_email:
vendor_node = etree.SubElement(root, '{%s}%s'
%(NSMAP['blti'], 'vendor'))
vendor_node = etree.SubElement(
root,
'{%s}%s' % (NSMAP['blti'], 'vendor'),
)
for key in vendor_keys:
if getattr(self, 'vendor_' + key) != None:
v_node = etree.SubElement(vendor_node,
'{%s}%s' %(NSMAP['lticp'], key))
if getattr(self, 'vendor_' + key) is not None:
v_node = etree.SubElement(
vendor_node,
'{%s}%s' % (NSMAP['lticp'], key),
)
v_node.text = getattr(self, 'vendor_' + key)
if getattr(self, 'vendor_contact_email'):
v_node = etree.SubElement(vendor_node,
'{%s}%s' %(NSMAP['lticp'], 'contact'))
c_name = etree.SubElement(v_node,
'{%s}%s' %(NSMAP['lticp'], 'name'))
v_node = etree.SubElement(
vendor_node,
'{%s}%s' % (NSMAP['lticp'], 'contact'),
)
c_name = etree.SubElement(
v_node,
'{%s}%s' % (NSMAP['lticp'], 'name'),
)
c_name.text = self.vendor_contact_name
c_email = etree.SubElement(v_node,
'{%s}%s' %(NSMAP['lticp'], 'email'))
c_email = etree.SubElement(
v_node,
'{%s}%s' % (NSMAP['lticp'], 'email'),
)
c_email.text = self.vendor_contact_email

# Custom params
if len(self.custom_params) != 0:
custom_node = etree.SubElement(root, '{%s}%s' %(NSMAP['blti'],
'custom'))
custom_node = etree.SubElement(
root,
'{%s}%s' % (NSMAP['blti'], 'custom'),
)
for (key, val) in sorted(self.custom_params.items()):
c_node = etree.SubElement(custom_node, '{%s}%s'
%(NSMAP['lticm'], 'property'))
c_node = etree.SubElement(
custom_node,
'{%s}%s' % (NSMAP['lticm'], 'property'),
)
c_node.set('name', key)
c_node.text = val

# Extension params
if len(self.extensions) != 0:
for (key, params) in sorted(self.extensions.items()):
extension_node = etree.SubElement(root, '{%s}%s' %(NSMAP['blti'],
'extensions'), platform = key)
self.recursive_options(extension_node,params)
extension_node = etree.SubElement(
root,
'{%s}%s' % (NSMAP['blti'], 'extensions'),
platform=key,
)
self.recursive_options(extension_node, params)

if getattr(self, 'cartridge_bundle'):
identifierref = etree.SubElement(root, 'cartridge_bundle',
identifierref = self.cartridge_bundle)
identifierref = etree.SubElement(
root,
'cartridge_bundle',
identifierref=self.cartridge_bundle,
)

if getattr(self, 'cartridge_icon'):
identifierref = etree.SubElement(root, 'cartridge_icon',
identifierref = self.cartridge_icon)
identifierref = etree.SubElement(
root,
'cartridge_icon',
identifierref=self.cartridge_icon,
)

declaration = b'<?xml version="1.0" encoding="UTF-8"?>'
return declaration + etree.tostring(root, encoding='utf-8')
8 changes: 3 additions & 5 deletions src/lti/tool_consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from .launch_params import LAUNCH_PARAMS_REQUIRED
from .utils import parse_qs, InvalidLTIConfigError


class ToolConsumer(ToolBase):

def __init__(self, consumer_key, consumer_secret,
Expand Down Expand Up @@ -40,13 +41,10 @@ def generate_launch_request(self, **kwargs):

if not self.has_required_params():
raise InvalidLTIConfigError(
'Consumer\'s launch params missing one of ' \
'Consumer\'s launch params missing one of '
+ str(LAUNCH_PARAMS_REQUIRED)
)

# if 'oauth_consumer_key' not in self.launch_params:
# self.launch_params['oauth_consumer_key'] = self.consumer_key

params = self.to_params()
r = Request('POST', self.launch_url, data=params).prepare()
sign = OAuth1(self.consumer_key, self.consumer_secret,
Expand All @@ -65,6 +63,6 @@ def set_config(self, config):
'''
Set launch data from a ToolConfig.
'''
if self.launch_url == None:
if self.launch_url is None:
self.launch_url = config.launch_url
self.launch_params.update(config.custom_params)
9 changes: 5 additions & 4 deletions src/lti/tool_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from urllib import urlencode
from urlparse import urlsplit, urlunsplit, parse_qsl


class ToolProvider(ToolBase):
'''
Implements the LTI Tool Provider.
Expand Down Expand Up @@ -68,7 +69,7 @@ def is_outcome_service(self):
Check if the Tool Launch expects an Outcome Result.
'''
return self.launch_params.get('lis_outcome_service_url') and \
self.launch_params.get('lis_result_sourcedid')
self.launch_params.get('lis_result_sourcedid')

def username(self, default=None):
'''
Expand Down Expand Up @@ -112,7 +113,7 @@ def build_return_url(self):
original.fragment
))

def post_replace_result(self, score, outcome_opts=defaultdict(lambda:None), result_data=None):
def post_replace_result(self, score, outcome_opts=defaultdict(lambda: None), result_data=None):
'''
POSTs the given score to the Tool Consumer with a replaceResult.
Expand All @@ -128,13 +129,13 @@ def post_replace_result(self, score, outcome_opts=defaultdict(lambda:None), resu
'''
return self.new_request(outcome_opts).post_replace_result(score, result_data)

def post_delete_result(self,outcome_opts=defaultdict(lambda:None)):
def post_delete_result(self, outcome_opts=defaultdict(lambda: None)):
'''
POSTs a delete request to the Tool Consumer.
'''
return self.new_request(outcome_opts).post_delete_result()

def post_read_result(self,outcome_opts=defaultdict(lambda:None)):
def post_read_result(self, outcome_opts=defaultdict(lambda: None)):
'''
POSTs the given score to the Tool Consumer with a replaceResult, the
returned OutcomeResponse will have the score.
Expand Down
Loading

0 comments on commit f7db203

Please sign in to comment.