This repository was archived by the owner on Jan 19, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
refactor StellarGradebook code #11
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
03c5d08
refactor StellarGradebook code into Base, Membership, Gradebook, and …
pwilkins eb23b07
removed stellargradebook.py and added get_gradebook_id() to base.py
pwilkins 068b7ff
I resolved all of Ike's style and coding violations. The refactorin…
pwilkins f585a78
fixed all pylint and pep8 errors except for the two no-member errors …
pwilkins 4c41ec8
resolve all review issues.
pwilkins File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,25 @@ | ||
|
||
""" | ||
PyLmod is a module that implements MIT Learning Modules API in python | ||
PyLmod is a module that implements MIT Learning Modules API in Python | ||
""" | ||
import os.path | ||
from pkg_resources import get_distribution, DistributionNotFound | ||
|
||
from pylmod.client import Client | ||
from pylmod.stellargradebook import StellarGradeBook | ||
from pylmod.gradebook import GradeBook | ||
from pylmod.membership import Membership | ||
|
||
try: | ||
_dist = get_distribution('pylmod') | ||
DIST = get_distribution('pylmod') | ||
# Normalize case for Windows systems | ||
dist_loc = os.path.normcase(_dist.location) | ||
here = os.path.normcase(__file__) | ||
if not here.startswith(os.path.join(dist_loc, 'pylmod')): | ||
DIST_LOC = os.path.normcase(DIST.location) | ||
HERE = os.path.normcase(__file__) | ||
if not HERE.startswith(os.path.join(DIST_LOC, 'pylmod')): | ||
# not installed, but there is another version that *is* | ||
raise DistributionNotFound | ||
except DistributionNotFound: | ||
__version__ = 'Please install this project with setup.py' | ||
else: | ||
__version__ = _dist.version | ||
__version__ = DIST.version | ||
|
||
|
||
__all__ = ['Client', 'StellarGradeBook', ] | ||
__all__ = ['Client', 'GradeBook', 'Membership'] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
""" | ||
Python class representing interface to MIT Learning Modules web service. | ||
""" | ||
|
||
import json | ||
import logging | ||
import requests | ||
|
||
|
||
log = logging.getLogger(__name__) # pylint: disable=C0103 | ||
|
||
|
||
class Base(object): | ||
""" | ||
The Base class provides the transport for accessing MIT LM web service. | ||
|
||
The Base class implements the functions that underlie the HTTP calls to | ||
the LM web service. It shouldn't be instantiated directly as it is | ||
inherited by the classes that implement the API. | ||
|
||
Attributes: | ||
cert: The certificate used to authenticate access to LM web service | ||
urlbase: The URL of the LM web service | ||
""" | ||
|
||
GETS = {'academicterms': '', | ||
'academicterm': '/{termCode}', | ||
'gradebook': '?uuid={uuid}'} | ||
|
||
GBUUID = 'STELLAR:/project/mitxdemosite' | ||
TIMEOUT = 200 # connection timeout, seconds | ||
|
||
verbose = True | ||
gradebookid = None | ||
|
||
def __init__( | ||
self, | ||
cert, | ||
urlbase='https://learning-modules.mit.edu:8443/service/gradebook', | ||
): | ||
""" | ||
Initialize Base instance. | ||
|
||
- urlbase: URL base for gradebook API | ||
(still needs certs); default False | ||
""" | ||
# pem with private and public key application certificate for access | ||
self.cert = cert | ||
|
||
self.urlbase = urlbase | ||
self.ses = requests.Session() | ||
self.ses.cert = cert | ||
self.ses.timeout = self.TIMEOUT # connection timeout | ||
self.ses.verify = True # verify site certificate | ||
|
||
log.debug("------------------------------------------------------") | ||
log.info("[PyLmod] init base=%s", urlbase) | ||
|
||
def rest_action(self, func, url, **kwargs): | ||
"""Routine to do low-level REST operation, with retry""" | ||
cnt = 1 | ||
while cnt < 10: | ||
cnt += 1 | ||
try: | ||
return self.rest_action_actual(func, url, **kwargs) | ||
except requests.ConnectionError, err: | ||
log.error( | ||
"[StellarGradeBook] Error - connection error in " | ||
"rest_action, err=%s", err | ||
) | ||
log.info(" Retrying...") | ||
except requests.Timeout, err: | ||
log.exception( | ||
"[StellarGradeBook] Error - timeout in " | ||
"rest_action, err=%s", err | ||
) | ||
log.info(" Retrying...") | ||
raise Exception( | ||
"[StellarGradeBook] rest_action failure: exceed max retries" | ||
) | ||
|
||
def rest_action_actual(self, func, url, **kwargs): | ||
"""Routine to do low-level REST operation""" | ||
log.info('Running request to %s', url) | ||
resp = func(url, timeout=self.TIMEOUT, verify=False, **kwargs) | ||
try: | ||
retdat = json.loads(resp.content) | ||
except Exception: | ||
log.exception(resp.content) | ||
raise | ||
return retdat | ||
|
||
def get(self, service, params=None, **kwargs): | ||
""" | ||
Generic GET operation for retrieving data from Learning Modules API | ||
Example: | ||
gbk.get('students/{gradebookId}', params=params, gradebookId=gbid) | ||
""" | ||
urlfmt = '{base}/' + service + self.GETS.get(service, '') | ||
url = urlfmt.format(base=self.urlbase, **kwargs) | ||
if params is None: | ||
params = {} | ||
return self.rest_action(self.ses.get, url, params=params) | ||
|
||
def post(self, service, data, **kwargs): | ||
""" | ||
Generic POST operation for sending data to Learning Modules API. | ||
data should be a JSON string or a dict. If it is not a string, | ||
it is turned into a JSON string for the POST body. | ||
""" | ||
urlfmt = '{base}/' + service | ||
url = urlfmt.format(base=self.urlbase, **kwargs) | ||
if not (type(data) == str or type(data) == unicode): | ||
data = json.dumps(data) | ||
headers = {'content-type': 'application/json'} | ||
return self.rest_action(self.ses.post, url, data=data, headers=headers) | ||
|
||
def delete(self, service, data, **kwargs): | ||
""" | ||
Generic DELETE operation for Learning Modules API. | ||
""" | ||
urlfmt = '{base}/' + service | ||
url = urlfmt.format(base=self.urlbase, **kwargs) | ||
if not (type(data) == str or type(data) == unicode): | ||
data = json.dumps(data) | ||
headers = {'content-type': 'application/json'} | ||
return self.rest_action( | ||
self.ses.delete, url, data=data, headers=headers | ||
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,30 @@ | ||
""" | ||
Python interface to MIT Learning Module | ||
Contains the Client class for pylmod that exposes all API classes. | ||
""" | ||
import logging | ||
from pylmod.stellargradebook import StellarGradeBook | ||
from pylmod.gradebook import GradeBook | ||
from pylmod.membership import Membership | ||
|
||
log = logging.getLogger(__name__) # pylint: disable=C0103 | ||
|
||
|
||
class Client(StellarGradeBook): # pylint: disable=too-few-public-methods | ||
class Client(GradeBook, Membership): # pylint: disable=too-few-public-methods | ||
""" | ||
Python class representing interface to MIT Learning Modules. | ||
Python class representing interface to MIT Learning Modules API. | ||
|
||
Use Client class to incorporate multiple Learning Modules APIs. | ||
|
||
Example usage: | ||
sg = Client('ichuang-cert.pem') | ||
ats = sg.get('academicterms') | ||
gradebook = Client('ichuang-cert.pem') | ||
ats = gradebook.get('academicterms') | ||
tc = ats['data'][0]['termCode'] | ||
sg.get('academicterm',termCode=tc) | ||
students = sg.get_students() | ||
assignments = sg.get_assignments() | ||
sg.create_assignment('midterm1', 'mid1', 1.0, 100.0, '11-04-2013') | ||
sid, student = sg.get_student_by_email(email) | ||
aid, assignment = sg.get_assignment_by_name('midterm1') | ||
sg.set_grade(aid, sid, 95.2) | ||
sg.spreadsheet2gradebook(datafn) | ||
gradebook.get('academicterm',termCode=tc) | ||
students = gradebook.get_students() | ||
assignments = gradebook.get_assignments() | ||
gradebook.create_assignment('midterm1', 'mid1', 1.0, 100.0, '11-04-2013') | ||
sid, student = gradebook.get_student_by_email(email) | ||
aid, assignment = gradebook.get_assignment_by_name('midterm1') | ||
gradebook.set_grade(aid, sid, 95.2) | ||
gradebook.spreadsheet2gradebook(datafn) | ||
""" | ||
pass |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wouldn't this be different in membership and gradebook? If so, we should probably remove the gradebook here and have the sub classes add in their own specific endpoint base.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be a new issue if you want to get this in
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually had that code in one my previous commits but took it out during one of the churns. I'll add the issue and replace the code.