Browse Source

docstring in Python code

Davide Alberani 9 years ago
parent
commit
910515b2e7
2 changed files with 113 additions and 13 deletions
  1. 75 2
      backend.py
  2. 38 11
      eventman_server.py

+ 75 - 2
backend.py

@@ -1,6 +1,6 @@
-"""Event Man(ager) backend
+"""Event Man(ager) database backend
 
-Classes and functions used to manage events and attendants.
+Classes and functions used to manage events and attendants database.
 """
 
 import pymongo
@@ -8,15 +8,29 @@ from bson.objectid import ObjectId
 
 
 class EventManDB(object):
+    """MongoDB connector."""
     db = None
     connection = None
 
     def __init__(self, url=None, dbName='eventman'):
+        """Initialize the instance, connecting to the database.
+
+        :param url: URL of the database
+        :type url: str (or None to connect to localhost)
+        """
         self._url = url
         self._dbName = dbName
         self.connect(url)
 
     def connect(self, url=None, dbName=None):
+        """Connect to the database.
+
+        :param url: URL of the database
+        :type url: str (or None to connect to localhost)
+
+        :return: the database we're connected to
+        :rtype: :class:`~pymongo.database.Database`
+        """
         if self.db is not None:
             return self.db
         if url:
@@ -28,12 +42,32 @@ class EventManDB(object):
         return self.db
 
     def get(self, collection, _id):
+        """Get a single document with the specified `_id`.
+
+        :param collection: search the document in this collection
+        :type collection: str
+        :param _id: unique ID of the document
+        :type _id: str or :class:`~bson.objectid.ObjectId`
+
+        :return: the document with the given `_id`
+        :rtype: dict
+        """
         if not isinstance(_id, ObjectId):
             _id = ObjectId(_id)
         results = self.query(collection, {'_id': _id})
         return results and results[0] or {}
 
     def query(self, collection, query=None):
+        """Get multiple documents matching a query.
+
+        :param collection: search for documents in this collection
+        :type collection: str
+        :param query: search for documents with those attributes
+        :type query: dict or None
+
+        :return: list of matching documents
+        :rtype: list
+        """
         db = self.connect()
         query = query or {}
         if'_id' in query and not isinstance(query['_id'], ObjectId):
@@ -44,11 +78,33 @@ class EventManDB(object):
         return results
 
     def add(self, collection, data):
+        """Insert a new document.
+
+        :param collection: insert the document in this collection
+        :type collection: str
+        :param data: the document to store
+        :type data: dict
+
+        :return: the document, as created in the database
+        :rtype: dict
+        """
         db = self.connect()
         _id = db[collection].insert(data)
         return self.get(collection, _id)
 
     def update(self, collection, _id, data):
+        """Update an existing document.
+
+        :param collection: update a document in this collection
+        :type collection: str
+        :param _id: unique ID of the document to be updatd
+        :type _id: str or :class:`~bson.objectid.ObjectId`
+        :param data: the updated information to store
+        :type data: dict
+
+        :return: the document, after the update
+        :rtype: dict
+        """
         db = self.connect()
         data = data or {}
         if '_id' in data:
@@ -56,3 +112,20 @@ class EventManDB(object):
         db[collection].update({'_id': ObjectId(_id)}, {'$set': data})
         return self.get(collection, _id)
 
+    def delete(self, collection, _id_or_query=None, force=False):
+        """Remove one or more documents from a collection.
+
+        :param collection: search the documents in this collection
+        :type collection: str
+        :param _id_or_query: unique ID of the document or query to match multiple documents
+        :type _id_or_query: str or :class:`~bson.objectid.ObjectId` or dict
+        :param force: force the deletion of all documents, when `_id_or_query` is empty
+        :type force: bool
+        """
+        if not _id_or_query and not force:
+            return
+        db = self.connect()
+        if not isinstance(_id_or_query, (ObjectId, dict)):
+            _id_or_query = ObjectId(_id_or_query)
+        db[collection].remove(_id_or_query)
+

+ 38 - 11
eventman_server.py

@@ -18,58 +18,84 @@ from tornado import gen, escape
 import backend
 
 
+class ImprovedEncoder(json.JSONEncoder):
+    """Enhance the default JSON encoder to serialize datetime objects."""
+    def default(self, o):
+        if isinstance(o, (datetime.datetime, datetime.date,
+                datetime.time, datetime.timedelta)):
+            return str(o)
+        return json.JSONEncoder.default(self, o)
+
+json._default_encoder = ImprovedEncoder()
+
+
 class BaseHandler(tornado.web.RequestHandler):
+    """Base class for request handlers."""
     def initialize(self, **kwargs):
+        """Add every passed (key, value) as attributes of the instance."""
         for key, value in kwargs.iteritems():
             setattr(self, key, value)
 
 
 class RootHandler(BaseHandler):
+    """Handler for the / path."""
     angular_app_path = os.path.join(os.path.dirname(__file__), "angular_app")
+
     @gen.coroutine
     def get(self):
+        # serve the ./angular_app/index.html file
         with open(self.angular_app_path + "/index.html", 'r') as fd:
             self.write(fd.read())
 
 
-class ImprovedEncoder(json.JSONEncoder):
-    def default(self, o):
-        if isinstance(o, datetime.datetime):
-            return str(o)
-        return json.JSONEncoder.default(self, o)
-
-json._default_encoder = ImprovedEncoder()
-
-
 class CollectionHandler(BaseHandler):
+    """Base class for handlers that need to interact with the database backend.
+    
+    Introduce basic CRUD operations."""
+    # set of documents we're managing (a collection in MongoDB or a table in a SQL database)
     collection = None
 
     @gen.coroutine
     def get(self, id_=None):
         if id_ is not None:
+            # read a single document
             self.write(self.db.get(self.collection, id_))
         else:
+            # return an object containing the list of all objects in the collection;
+            # e.g.: {'events': [{'_id': 'obj1-id, ...}, {'_id': 'obj2-id, ...}, ...]}
+            # Please, never return JSON lists that are not encapsulated in an object,
+            # to avoid XSS vulnerabilities.
             self.write({self.collection: self.db.query(self.collection)})
 
     @gen.coroutine
     def post(self, id_=None, **kwargs):
         data = escape.json_decode(self.request.body or {})
         if id_ is None:
+            # insert a new document
             newData = self.db.add(self.collection, data)
         else:
+            # update an existing document
             newData = self.db.update(self.collection, id_, data)
         self.write(newData)
 
+    # PUT is handled by the POST method
     put = post
 
+
 class PersonsHandler(CollectionHandler):
+    """Handle requests for Persons."""
     collection = 'persons'
 
+
 class EventsHandler(CollectionHandler):
+    """Handle requests for Events."""
     collection = 'events'
 
 
-def main():
+def run():
+    """Run the Tornado web application."""
+    # command line arguments; can also be written in a configuration file,
+    # specified with the --config argument.
     define("port", default=5242, help="run on the given port", type=int)
     define("data", default=os.path.join(os.path.dirname(__file__), "data"),
             help="specify the directory used to store the data")
@@ -82,6 +108,7 @@ def main():
             callback=lambda path: tornado.options.parse_config_file(path, final=False))
     tornado.options.parse_command_line()
 
+    # database backend connector
     db_connector = backend.EventManDB(url=options.mongodbURL, dbName=options.dbName)
     init_params = dict(db=db_connector)
 
@@ -100,5 +127,5 @@ def main():
 
 
 if __name__ == '__main__':
-    main()
+    run()