Skip to content
This repository has been archived by the owner on Jan 19, 2022. It is now read-only.

Commit

Permalink
removed RTD debugging code, most api docstrings are complete. the gra…
Browse files Browse the repository at this point in the history
…des2stellar functions still need editing.
  • Loading branch information
pwilkins committed Mar 13, 2015
1 parent 1999899 commit 77021b8
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 41 deletions.
34 changes: 28 additions & 6 deletions README.rst
@@ -1,4 +1,4 @@
# PyLmod
PyLmod
========
:PyLmod: Python implementation of MIT Learning Modules API
:Version: 0.1.0
Expand All @@ -7,11 +7,33 @@
:License: BSD

PyLmod provides a Python library to access the MIT Learning Modules web
service. This service, maintained by MIT Information Systems and Technologies
(IS&T) exposes an API to MIT systems of record for classes, students, and
grades. PyLmod was created to support MIT's
use of OpenedX for residential courses, but the library is open source
to enable easier access for Python application developers at MIT.
service (described below). PyLmod was created to support
MIT's use of OpenedX for residential courses, but the library is open
source to enable easier access to that service for Python application
developers at MIT. PyLmod encapsulates the Learning Modules web service
making it more pythonic and easier to incorporate into Python applications.

The MIT Learning Modules web service, maintained by MIT Information
Systems and Technologies (IS&T), exposes an API to MIT systems of
record for classes, students, and grades. Its documentation for gradebook
and membership is available at these links.

Gradebook module
`https://learning-modules-test.mit.edu/service/gradebook/doc.html
<https://learning-modules-test.mit.edu/service/gradebook/doc.html>`_

Membership module
`https://learning-modules-test.mit.edu/service/membership/doc.html
<https://learning-modules-test.mit.edu/service/membership/doc.html>`_

Getting Started
===============
The Learning Modules web service requires authentication by x.509
certificates. You must create an application certificate and config
the Learning Modules web service to recognize it. This is done directly
through the Learning Modules web interface and is outside the scope
of this guide.


Licensing
=========
Expand Down
5 changes: 1 addition & 4 deletions pylmod/__init__.py
Expand Up @@ -14,17 +14,14 @@
DIST = get_distribution('pylmod')
# Normalize case for Windows systems
DIST_LOC = os.path.normcase(DIST.location)
print('distribution location is <%s>' % DIST_LOC) # debug
HERE = os.path.normcase(__file__)
print('HERE is <%s>' % HERE) # debug
print('DIST.version is <%s>' % DIST.version) # debug
if not HERE.startswith(
os.path.join(DIST_LOC, 'pylmod')
): # pragma: no cover
# not installed, but there is another version that *is*
raise DistributionNotFound
except DistributionNotFound: # pragma: no cover
__version__ = 'Please install this project with setup.py'
__version__ = '0.1.0' # hard coded value until we can debug RTD defect
else:
__version__ = DIST.version

Expand Down
131 changes: 100 additions & 31 deletions pylmod/gradebook.py
Expand Up @@ -18,14 +18,14 @@

class GradeBook(Base):
"""
All calls to the LMod service return JSON for all calls. The JSON always
contains
All calls to the LMod service return JSON for all calls. The JSON
always contains these items:
- "status" (1=successful, -1=failed),
- "message" (details about any error condition, or success message),
- the returned data, if applicable.
for example,
and is in this format:
.. code-block:: json
Expand All @@ -51,6 +51,8 @@ def get_gradebook_id(self, gbuuid):
Args:
gbuuid (str): gradebook uuid, i.e. STELLAR:/project/gbngtest
Returns:
json
"""
gradebook = self.get('gradebook', params={'uuid': gbuuid})
if 'data' not in gradebook:
Expand All @@ -73,18 +75,25 @@ def get_assignments(
"""get assignments for a gradebook
return list of assignments for a given gradebook,
specified by a gradebookid. You can control if additional
specified by a gradebook id. You can control if additional
parameters are returned, but the response time with avg_stats
and grading_stats enabled is significantly longer.
Args:
gradebook_id (str): unique identifier
simple (bool):
gradebook_id (str): unique identifier for gradebook, i.e. `2314`
simple (bool): return just assignment names, default=`False`
max_points (bool):
avg_stats (bool)
Max points is a property of the grading scheme for the
assignment rather than a property of the assignment itself,
default=`True`
avg_stats (bool): return average grade, default=`False`
grading_stats (bool):
return grading statistics, i.e. number of approved grades,
unapproved grades, etc., default=`False`
"""
Returns:
json
"""
# These are parameters required for the remote API call, so
# there aren't too many arguments
# pylint: disable=too-many-arguments
Expand Down Expand Up @@ -112,8 +121,8 @@ def get_assignment_by_name(self, assignment_name, assignments=None):
and assignment dict.
Args:
assignment_name (str):
assignments (str):
assignment_name (str): name of assignment
assignments (dict): assignments
Returns:
json
Expand All @@ -136,18 +145,28 @@ def create_assignment( # pylint: disable=too-many-arguments
gradebook_id='',
**kwargs
):
"""Create a new assignment.
"""create a new assignment
create a new assignment
create a new assignment. By default, assignments are are created
under the `Uncategorized` category.
Parameters:
Args:
name (str):
short_name (str):
weight (str):
descriptive assignment name,
i.e. "new NUMERIC SIMPLE ASSIGNMENT"
short_name (str): short, one word, name of assignment, i.e. "SAnew"
weight (str): floating point value for weight, i.e. 1.0
max_points (str):
floating point value for maximum point total, i.e. `100.0`
due_date_str (str):
gradebook_id (str):
due date as string in `mm-dd-yyyy` format, i.e. 08-21-2011
gradebook_id (str): unique identifier for gradebook, i.e. `2314`
kwargs (dict):
dictionary containing additional parameters,
i.e. totalAverage, graderVisible, and categoryId
Returns:
json
"""
data = {
'name': name,
Expand All @@ -166,12 +185,15 @@ def create_assignment( # pylint: disable=too-many-arguments
return response

def delete_assignment(self, assignment_id):
"""
Delete assignment specified by assignment Id
""" delete assignment
delete assignment specified by assignment Id
Args:
assignment_id (str):
assignment_id (str): id of assignment to delete
Returns:
json
"""
return self.delete(
'assignment/{assignmentId}'.format(assignmentId=assignment_id),
Expand All @@ -187,15 +209,35 @@ def set_grade(
):
"""Set numerical grade for student & assignment.
Expecting json representation of a single grade to save. Options
for grade mode are: OVERALL_GRADE = 1, REGULAR_GRADE = 2
To set 'excused' as the grade, enter null for letter and
numeric grade values,
and pass "x" as the specialGradeValue.
ReturnAffectedValues flag determines whether or not to return
student cumulative points, and
impacted assignment category grades (average and student grade)
e.g.: {"studentId":1135,
"assignmentId":4522,
"letterGradeValue":null,
"numericGradeValue":50,
"booleanGradeValue":null,
"specialGradeValue":null,
"mode":2,
"isGradeApproved":false,
"comment":null,
"returnAffectedValues": true }
Args:
assignment_id (str): numerical ID for assignment
student_id (str): numerical ID for student
grade_value (str): numerical grade value
gradebook_id (str): numerical ID for gradebook (optional)
kwargs (dict):
Returns:
Nothing
json
"""
# pylint: disable=too-many-arguments

Expand All @@ -222,18 +264,30 @@ def set_grade(
)

def multi_grade(self, grade_array, gradebook_id=''):
"""Set multiple grades for students.
"""set multiple grades for students
set multiple student grades for a gradebook. The grades are passed
as an array of dictionaries, of student_id and assignment_id of
expecting json representation of an array of grades to save.
Both studentId and assignmentId are required; to set an overall grade,
pass the root assignment id, which can be gotten either by calling
get root assignment id, or looking at the assignmentId passed with
the overall grade info on any student.
Expecting json representation of a list of grades to save.
Options for grade mode are: OVERALL_GRADE = 1, REGULAR_GRADE = 2
To set 'excused' as the grade, enter null for letter and numeric
grade values, and pass "x" as the specialGradeValue.
ReturnAffectedValues flag determines whether or not to return
student cumulative points, and impacted assignment category
grades (average and student grade)
Args:
grade_array (dict): an array of grades to save
gradebook_id (str):
gradebook_id (str): id of gradebook to
Returns:
json
"""
return self.post(
'multiGrades/{gradebookId}'.format(
Expand Down Expand Up @@ -265,6 +319,8 @@ def get_sections(self, gradebook_id='', simple=False):
"groupId": 1293925
}]
Returns:
json
"""
params = dict(includeMembers='false')

Expand All @@ -286,8 +342,7 @@ def get_section_by_name(self, section_name):
section_name (str): section name
Returns:
none
json
"""
sections = self.get_sections()
for section in sections:
Expand All @@ -313,14 +368,19 @@ def get_students(
Args:
gradebook_id (str):
simple (bool):
section_name (str):
include_photo (bool):
if `True`, just return dict with keys email, name,
section, default=`False`
section_name (str): section name
include_photo (bool): include student photo, default=`False`
include_grade_info (bool):
include student's grade info, default=`False`
include_grade_history (bool):
include student's grade history, default=`False`
include_makeup_grades (bool):
include student's makeup grades, default=`False`
Returns:
example return list element:
json
.. code-block:: python
Expand Down Expand Up @@ -404,7 +464,11 @@ def get_student_by_email(self, email, students=None):
as the students argument. Returns studentid, student dict, if found.
Args:
email (str):
students (dict):
Returns:
json
"""
if students is None:
students = self.get_students()
Expand All @@ -423,13 +487,15 @@ def _spreadsheet2gradebook_multi(
Helper function: Transfer grades from spreadsheet using
multiGrades (multiple students at a time). We do this by
creating a large array containing all grades to transfer, then
make one call to the gradebook API.
make one call to the Gradebook API.
Args:
csv_reader:
email_field:
non_assignment_fields:
Returns:
json
"""
# pylint: disable=too-many-locals
assignments = self.get_assignments()
Expand Down Expand Up @@ -522,8 +588,9 @@ def spreadsheet2gradebook(
named "External email"; this will be used as the student's email
address (for looking up and matching studentId).
Columns ID,Username,Full Name,edX email,External email are otherwise
disregarded. All other columns are taken as assignments.
These columns are disregarded: ID, Username, Full Name, edX email,
External email.
All other columns are taken as assignments.
If email_field is specified, then that field name is taken as
the student's email.
Expand All @@ -535,6 +602,8 @@ def spreadsheet2gradebook(
csv_reader (str): filename of csv data, or readable file object
email_field (str): student's email
Returns:
json
"""
non_assignment_fields = [
'ID', 'Username', 'Full Name', 'edX email', 'External email'
Expand Down

0 comments on commit 77021b8

Please sign in to comment.