[Tutor] Help on Software Design decisions

Juan C. juan0christian at gmail.com
Tue Nov 29 12:17:42 EST 2016


On Tue, Nov 29, 2016 at 7:12 AM, Alan Gauld via Tutor <tutor at python.org>
wrote:
> I just noticed the last bit.
> Is this a client side API or a server side API?
> In other words are you building a set of services on the
> server or are you building a module that makes it easy
> for client side programs to access the server? I had
> assumed the first but your responses make me think it
> is probably the second.

Client side. I'm building a python package to make it easier for my
programs to get data from Moodle.

> OK, In that case you possibly want to call your class
> Users since you seem to intend to fetch all User objects at once?
> Or is the User ID doing double duty as a security token for
> the server and as a key into the data? Or should it look like:

I just need username and password to login, nothing else. I'm passing
'program_id' as an argument to make it easier for me, but I intend to
automatically get it in the future.


Here's my working code:

package moodle/

user.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from .program import Program
import requests


class User:
   _AUTH_URL = 'http://lms.university.edu/moodle/login/index.php'

   def __init__(self, username, password, program_id):
      self.username = username
      self.password = password
      session = requests.session()
      session.post(self._AUTH_URL, {"username": username, "password":
password})
      self.program = Program(program_id=program_id, session=session)

   def __str__(self):
      return self.username + ':' + self.password

   def __repr__(self):
      return '<User %s>' % self.username

   def __eq__(self, other):
      if isinstance(other, self):
         return self.username == other.username
      else:
         return False

==========

program.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from .unit import Unit
from bs4 import BeautifulSoup


class Program:
   _PATH = 'http://lms.university.edu/moodle/course/index.php?categoryid='

   def __init__(self, program_id, session):
      response = session.get(self._PATH + str(program_id))
      soup = BeautifulSoup(response.text, 'html.parser')

      self.name = soup.find('ul',
class_='breadcrumb').find_all('li')[-2].text.replace('/', '').strip()
      self.id = program_id
      self.units = [Unit(int(item['data-categoryid']), session) for item in
soup.find_all('div', {'class': 'category'})]

   def __str__(self):
      return self.name

   def __repr__(self):
      return '<Program %s (%s)>' % (self.name, self.id)

   def __eq__(self, other):
      if isinstance(other, self):
         return self.id == other.id
      else:
         return False

==========

unit.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from .course import Course
from bs4 import BeautifulSoup


class Unit:
   _PATH = 'http://lms.university.edu/moodle/course/index.php?categoryid='

   def __init__(self, unit_id, session):
      response = session.get(self._PATH + str(unit_id))
      soup = BeautifulSoup(response.text, 'html.parser')

      self.name = soup.find('ul',
class_='breadcrumb').find_all('li')[-1].text.replace('/', '').strip()
      self.id = unit_id
      self.courses = [Course(int(item['data-courseid']), session) for item
in soup.find_all('div', {'class': 'coursebox'})]

   def __str__(self):
      return self.name

   def __repr__(self):
      return '<Unit %s (%s)>' % (self.name, self.id)

   def __eq__(self, other):
      if isinstance(other, self):
         return self.id == other.id
      else:
         return False

==========

course.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-


from .assignment import Assignment
import re
from bs4 import BeautifulSoup


class Course:
   _PATH = 'http://lms.university.edu/moodle/course/view.php?id='

   def __init__(self, course_id, session):
      response = session.get(self._PATH + str(course_id))
      soup = BeautifulSoup(response.text, 'html.parser')

      self.name = soup.find('h1').text
      self.id = course_id
      self.assignments = [Assignment(int(item['href'].split('id=')[-1]),
session) for item in
         soup.find_all('a', href=re.compile(r'http://lms
\.university\.edu/moodle/mod/assign/view.php\?id=.*'))]

   def __str__(self):
      return self.name

   def __repr__(self):
      return '<Course %s (%s)>' % (self.name, self.id)

   def __eq__(self, other):
      if isinstance(other, self):
         return self.id == other.id
      else:
         return False

==========

assignment.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from bs4 import BeautifulSoup


class Assignment:
   _PATH = 'http://lms.university.edu/moodle/mod/assign/view.php?id='

   def __init__(self, assignment_id, session):
      response = session.get(self._PATH + str(assignment_id))
      soup = BeautifulSoup(response.text, 'html.parser')

      self.name = soup.find('h2').text
      self.id = assignment_id

   def __str__(self):
      return self.name

   def __repr__(self):
      return '<Assignment %s (%s)>' % (self.name, self.id)

   def __eq__(self, other):
      if isinstance(other, self):
         return self.id == other.id
      else:
         return False

==========

test.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from moodle.user import User

my_user = User('john.smith', '3uper$secret', 12)

print(my_user)  # print: john.smith:3uper$secret

print(my_user.program)  # print: Computer Science

print(my_user.program.units)  # print: [<Unit Math Fundamentals (59)>,
<Unit Programming (102)>]

print(my_user.program.units[-1].courses)  # print: [<Course Programming
Logic (666)>, <Course Data Modeling (667)>, <Course Python 1 (668)>,
<Course Python 2 (669)>, <Course Project (670)>]

print(my_user.program.units[-1].courses[-1].assignments)  #
print: [<Assignment A1 [mandatory] (40817)>, <Assignment A2 (40824)>,
<Assignment A3 [mandatory] (40831)>, <Assignment A4 (40838)>, <Assignment
A5 [mandatory] (40845)>, <Assignment Final Assignment [mandatory] (40882)>]


More information about the Tutor mailing list