Skip to content

Commit

Permalink
Merge pull request #29 from hfaran/docup
Browse files Browse the repository at this point in the history
Improve docstrings and documentation
  • Loading branch information
hfaran committed Feb 17, 2014
2 parents a256cc0 + 731dcb6 commit d4abfd8
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 42 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@

## Overview

Tornado-JSON is a small extension of Tornado with the intent providing the tools necessary to get a JSON API up and running quickly. See [demos/helloworld/](https://github.com/hfaran/Tornado-JSON/tree/master/demos/helloworld) for a quick example and the [accompanying walkthrough](http://tornado-json.readthedocs.org/en/latest/using_tornado_json.html) in the documentation.
Tornado-JSON is a small extension of [Tornado](http://www.tornadoweb.org/en/stable/) with the intent providing the tools necessary to get a JSON API up and running quickly. See [demos/helloworld/](https://github.com/hfaran/Tornado-JSON/tree/master/demos/helloworld) for a quick example and the [accompanying walkthrough](http://tornado-json.readthedocs.org/en/latest/using_tornado_json.html) in the documentation.

Some of the key features the included modules provide:

* Input and output [JSON Schema](http://json-schema.org/) validation by decorating RequestHandlers
* Input and output [JSON Schema](http://json-schema.org/) validation by decorating RequestHandlers with `io_schema`
* Automated *route generation* with `routes.get_routes(package)`
* *Automated Public API documentation* using schemas and provided descriptions
* Standardized output using the [JSend](http://labs.omniti.com/labs/jsend) specification
Expand Down
15 changes: 8 additions & 7 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ Tornado-JSON
Overview
--------

Tornado-JSON is a small extension of Tornado with the intent providing
the tools necessary to get a JSON API up and running quickly. See
Tornado-JSON is a small extension of
`Tornado <http://www.tornadoweb.org/en/stable/>`__ with the intent
providing the tools necessary to get a JSON API up and running quickly.
See
`demos/helloworld/ <https://github.com/hfaran/Tornado-JSON/tree/master/demos/helloworld>`__
for a quick example and the `accompanying
walkthrough <http://tornado-json.readthedocs.org/en/latest/using_tornado_json.html>`__
Expand All @@ -20,7 +22,7 @@ in the documentation.
Some of the key features the included modules provide:

- Input and output `JSON Schema <http://json-schema.org/>`__ validation
by decorating RequestHandlers
by decorating RequestHandlers with ``io_schema``
- Automated *route generation* with ``routes.get_routes(package)``
- *Automated Public API documentation* using schemas and provided
descriptions
Expand All @@ -33,7 +35,7 @@ Some of the key features the included modules provide:
\ *Warning: Tornado-JSON is still very much a work in progress. No
guarantees on backwards-compatibility made, however, I try not to do
that since, as a user, I hate breaking it at least as much as you. That
being said, use it at your own risk.*\
being said, use it at your own risk.*\

Dependencies
============
Expand All @@ -46,12 +48,11 @@ These dependencies can be satisfied by running
- tornado
- jsonschema


.. |Build Status| image:: https://travis-ci.org/hfaran/Tornado-JSON.png?branch=master
:target: https://travis-ci.org/hfaran/Tornado-JSON
.. |PyPI version| image:: https://badge.fury.io/py/Tornado-JSON.png
:target: http://badge.fury.io/py/Tornado-JSON
.. |Coverage Status| image:: https://coveralls.io/repos/hfaran/Tornado-JSON/badge.png?branch=master
.. |Coverage Status| image:: http://coveralls.io/repos/hfaran/Tornado-JSON/badge.png?branch=master
:target: https://coveralls.io/r/hfaran/Tornado-JSON?branch=master
.. |Stories in Ready| image:: https://badge.waffle.io/hfaran/Tornado-JSON.png?label=ready
.. |Stories in Ready| image:: https://badge.waffle.io/hfaran/Tornado-JSON.png?label=In_Progress
:target: http://waffle.io/hfaran/Tornado-JSON
44 changes: 44 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
Changelog
=========

_
---------

v0.14 - Bugfixes thanks to 100% coverage
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* Fixes related to error-writing in ``io_schema`` and ``APIHandler.write_error``


v0.13 - Add asynchronous compatibility to io_schema
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* Add asynchronous functionality to io_schema


v0.12 - Python3 support
~~~~~~~~~~~~~~~~~~~~~~~

* Python3.3, in addition to Python2.7, is now supported.


v0.11 - Duplicate route bugfix
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* Fixed bug where duplicate routes would be created on existence of multiple HTTP methods.


v0.10 - Route generation with URL patterns
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Route generation will now inspect method signatures in ``APIHandler`` and ``ViewHandler`` subclasses, and construct routes with URL patterns based on the signatures. URL patterns match ``[a-zA-Z0-9_]+``.

**Backwards Compatibility**: ``body`` is no longer provided by ``io_schema`` as the sole argument to HTTP methods. Any existing code using ``body`` can now use ``self.body`` to get the same object.


v0.08 - Input and output example fields
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* Add input_example and output_example fields
* status_code 400 on ValidationError
* Exclude delete from input validation
28 changes: 26 additions & 2 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,27 @@
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to tornado_json's documentation!
Tornado-JSON
========================================

Contents:
Tornado-JSON is a small extension of `Tornado <http://www.tornadoweb.org/en/stable/>`__ with the intent providing
the tools necessary to get a JSON API up and running quickly. See
`demos/helloworld/ <https://github.com/hfaran/Tornado-JSON/tree/master/demos/helloworld>`__
for a quick example and the `accompanying
walkthrough <http://tornado-json.readthedocs.org/en/latest/using_tornado_json.html>`__
in the documentation.

Some of the key features the included modules provide:

- Input and output `JSON Schema <http://json-schema.org/>`__ validation
by decorating RequestHandlers with ``io_schema``
- Automated *route generation* with ``routes.get_routes(package)``
- *Automated Public API documentation* using schemas and provided
descriptions
- Standardized output using the
`JSend <http://labs.omniti.com/labs/jsend>`__ specification

**Contents**:

.. toctree::
:maxdepth: 2
Expand All @@ -15,9 +32,16 @@ Contents:
using_tornado_json
requesthandler_guidelines
docgen
changelog
tornado_json


\ *Warning: Tornado-JSON is still very much a work in progress. No
guarantees on backwards-compatibility made, however, I try not to do
that since, as a user, I hate breaking it at least as much as you. That
being said, use it at your own risk.*\


Indices and tables
==================

Expand Down
2 changes: 1 addition & 1 deletion tornado_json/api_doc_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
def api_doc_gen(routes):
"""
Generates GitHub Markdown formatted API documentation using
provided information from `apid` class-variable
provided information from ``apid`` class-variable
in each handler that provides one.
:type routes: [(url, RequestHandler), ...]
Expand Down
16 changes: 7 additions & 9 deletions tornado_json/requesthandlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@

class BaseHandler(RequestHandler):

"""
BaseHandler for all other RequestHandlers
"""
"""BaseHandler for all other RequestHandlers"""

@property
def db_conn(self):
Expand All @@ -38,11 +36,11 @@ def initialize(self):

class APIHandler(BaseHandler, JSendMixin):

"""
RequestHandler for API calls
- Sets header as application/json
- Provides custom write_error that writes error back as JSON
rather than as the standard HTML template
"""RequestHandler for API calls
- Sets header as ``application/json``
- Provides custom write_error that writes error back as JSON \
rather than as the standard HTML template
"""

def initialize(self):
Expand All @@ -54,7 +52,7 @@ def initialize(self):
def write_error(self, status_code, **kwargs):
"""Override of RequestHandler.write_error
Calls `error()` or `fail()` from JSendMixin depending on which
Calls ``error()`` or ``fail()`` from JSendMixin depending on which
exception was raised with provided reason and status code.
:type status_code: int
Expand Down
28 changes: 14 additions & 14 deletions tornado_json/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@

def get_routes(package):
"""
This will walk `package` and generates routes from any and all
`APIHandler` and `ViewHandler` subclasses it finds. If you need to
This will walk ``package`` and generates routes from any and all
``APIHandler`` and ``ViewHandler`` subclasses it finds. If you need to
customize or remove any routes, you can do so to the list of
returned routes that this generates.
:type package: package
:param package: The package containing RequestHandlers to generate
routes from
:returns: List of routes for all submodules of `package`
:returns: List of routes for all submodules of ``package``
:rtype: [(url, RequestHandler), ... ]
"""
return list(chain(*[get_module_routes(modname) for modname in
Expand All @@ -29,8 +29,8 @@ def gen_submodule_names(package):
:type package: package
:param package: The package to get submodule names of
:returns: Iterator that yields names of all submodules of `package`
:rtype: Iterator that yields `str`
:returns: Iterator that yields names of all submodules of ``package``
:rtype: Iterator that yields ``str``
"""
for importer, modname, ispkg in pkgutil.walk_packages(
path=package.__path__,
Expand All @@ -44,17 +44,17 @@ def get_module_routes(module_name, custom_routes=None, exclusions=None):
Routes are (url, RequestHandler) tuples
:returns: list of routes for `module_name` with respect to `exclusions`
and `custom_routes`. Returned routes are with URLs formatted such
:returns: list of routes for ``module_name`` with respect to ``exclusions``
and ``custom_routes``. Returned routes are with URLs formatted such
that they are forward-slash-separated by module/class level
and end with the lowercase name of the RequestHandler (it will also
remove 'handler' from the end of the name of the handler).
For example, a requesthandler with the name
`helloworld.api.HelloWorldHandler` would be assigned the url
`/api/helloworld`.
Additionally, if a method has extra arguments aside from `self` in
``helloworld.api.HelloWorldHandler`` would be assigned the url
``/api/helloworld``.
Additionally, if a method has extra arguments aside from ``self`` in
its signature, routes with URL patterns will be generated to
match `r"(?P<{}>[a-zA-Z0-9_]+)".format(argname)` for each
match ``r"(?P<{}>[a-zA-Z0-9_]+)".format(argname)`` for each
argument. The aforementioned regex will match ONLY values
with alphanumeric+underscore characters.
:rtype: [(url, RequestHandler), ... ]
Expand Down Expand Up @@ -88,12 +88,12 @@ def is_method(method):
])

def yield_args(module, cls_name, method_name):
"""Get signature of `module.cls_name.method_name`
"""Get signature of ``module.cls_name.method_name``
Confession: This function doesn't actually `yield` the arguments,
Confession: This function doesn't actually ``yield`` the arguments,
just returns a list. Trust me, it's better that way.
:returns: List of arg names from method_name except "self"
:returns: List of arg names from method_name except ``self``
:rtype: list
"""
# method = getattr(getattr(module, cls_name), method_name)
Expand Down
25 changes: 18 additions & 7 deletions tornado_json/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import json
import logging
from functools import wraps
from jsonschema import validate, ValidationError

from tornado import gen
Expand All @@ -11,12 +12,14 @@

class APIError(HTTPError):

"""Equivalent to RequestHandler.HTTPError except for in name"""
"""Equivalent to ``RequestHandler.HTTPError`` except for in name"""


def api_assert(condition, *args, **kwargs):
"""Asserts that `condition` is `True`, else raises an `APIError` with the
provided `args` and `kwargs`
"""Assertion to fail with if not ``condition``
Asserts that ``condition`` is ``True``, else raises an ``APIError``
with the provided ``args`` and ``kwargs``
:type condition: bool
"""
Expand All @@ -27,9 +30,14 @@ def api_assert(condition, *args, **kwargs):
def container(dec):
"""Meta-decorator (for decorating decorators)
Keeps around original decorated function as a property `orig_func`
Credits: http://stackoverflow.com/a/1167248/1798683
Keeps around original decorated function as a property ``orig_func``
:param dec: Decorator to decorate
:type dec: function
:returns: Decorated decorator
"""
# Credits: http://stackoverflow.com/a/1167248/1798683
@wraps(dec)
def meta_decorator(f):
decorator = dec(f)
decorator.orig_func = f
Expand All @@ -42,14 +50,17 @@ def io_schema(rh_method):
"""Decorator for RequestHandler schema validation
This decorator:
- Validates request body against input schema of the method
- Calls the `rh_method` and gets output from it
- Calls the ``rh_method`` and gets output from it
- Validates output against output schema of the method
- Calls `JSendMixin.success` to write the validated output
- Calls ``JSendMixin.success`` to write the validated output
:type rh_method: function
:param rh_method: The RequestHandler method to be decorated
:returns: The decorated method
:raises ValidationError: If input is invalid as per the schema or malformed
:raises TypeError: If the output is invalid as per the schema or malformed
"""

@gen.coroutine
Expand Down

0 comments on commit d4abfd8

Please sign in to comment.