Use doc strings for resource and method docs. Tweak some docs. Switch to 100 length lines.

This commit is contained in:
jakedt 2014-03-11 15:20:03 -04:00
parent 978d68f0e0
commit 220649e579
3 changed files with 43 additions and 51 deletions

View file

@ -56,10 +56,9 @@ def method_metadata(func, name):
nickname = partial(add_method_metadata, 'nickname') nickname = partial(add_method_metadata, 'nickname')
def query_parameter(name, help_str, type=reqparse.text_type, def query_param(name, help_str, type=reqparse.text_type, default=None,
default=None, choices=(), required=False): choices=(), required=False):
def add_param(func): def add_param(func):
logger.debug('%s', func)
if '__api_query_params' not in dir(func): if '__api_query_params' not in dir(func):
func.__api_query_params = [] func.__api_query_params = []
func.__api_query_params.append({ func.__api_query_params.append({
@ -78,8 +77,6 @@ def parse_args(func):
@wraps(func) @wraps(func)
def wrapper(self, *args, **kwargs): def wrapper(self, *args, **kwargs):
if '__api_query_params' not in dir(func): if '__api_query_params' not in dir(func):
logger.debug('No query params defined.')
logger.debug('%s', func)
abort(400) abort(400)
parser = reqparse.RequestParser() parser = reqparse.RequestParser()
@ -139,9 +136,8 @@ def validate_json_request(schema_name):
def log_action(kind, user_or_orgname, metadata={}, repo=None): def log_action(kind, user_or_orgname, metadata={}, repo=None):
performer = current_user.db_user() performer = current_user.db_user()
model.log_action(kind, user_or_orgname, performer=performer, model.log_action(kind, user_or_orgname, performer=performer, ip=request.remote_addr,
ip=request.remote_addr, metadata=metadata, repository=repo) metadata=metadata, repository=repo)
import endpoints.api.legacy import endpoints.api.legacy

View file

@ -29,11 +29,12 @@ def swagger_route_data():
endpoint_method = app.view_functions[rule.endpoint] endpoint_method = app.view_functions[rule.endpoint]
if 'view_class' in dir(endpoint_method): if 'view_class' in dir(endpoint_method):
view_class = endpoint_method.view_class
operations = [] operations = []
method_names = list(rule.methods.difference(['HEAD', 'OPTIONS'])) method_names = list(rule.methods.difference(['HEAD', 'OPTIONS']))
for method_name in method_names: for method_name in method_names:
method = getattr(endpoint_method.view_class, method_name.lower(), None) method = getattr(view_class, method_name.lower(), None)
parameters = [] parameters = []
for param in rule.arguments: for param in rule.arguments:
@ -49,16 +50,15 @@ def swagger_route_data():
if req_schema_name: if req_schema_name:
parameters.append({ parameters.append({
'paramType': 'body', 'paramType': 'body',
'name': 'request_body', 'name': 'body',
'description': 'Request body contents.', 'description': 'Request body contents.',
'dataType': req_schema_name, 'dataType': req_schema_name,
'required': True, 'required': True,
}) })
schema = endpoint_method.view_class.schemas[req_schema_name] schema = view_class.schemas[req_schema_name]
models[req_schema_name] = schema models[req_schema_name] = schema
logger.debug('method dir: %s', dir(method))
if '__api_query_params' in dir(method): if '__api_query_params' in dir(method):
for param_spec in method.__api_query_params: for param_spec in method.__api_query_params:
new_param = { new_param = {
@ -79,13 +79,14 @@ def swagger_route_data():
'method': method_name, 'method': method_name,
'nickname': method_metadata(method, 'nickname'), 'nickname': method_metadata(method, 'nickname'),
'type': 'void', 'type': 'void',
'summary': method.__doc__ if method.__doc__ else '',
'parameters': parameters, 'parameters': parameters,
}) })
swagger_path = PARAM_REGEX.sub(r'{\2}', rule.rule) swagger_path = PARAM_REGEX.sub(r'{\2}', rule.rule)
apis.append({ apis.append({
'path': swagger_path, 'path': swagger_path,
'description': 'Resource description.', 'description': view_class.__doc__ if view_class.__doc__ else "",
'operations': operations, 'operations': operations,
}) })
@ -96,10 +97,9 @@ def swagger_route_data():
'resourcePath': '/', 'resourcePath': '/',
'info': { 'info': {
'title': 'Quay.io API', 'title': 'Quay.io API',
'description': ('This API allows you to perform many of the operations ' 'description': ('This API allows you to perform many of the operations required to work '
'required to work with Quay.io repositories, users, and ' 'with Quay.io repositories, users, and organizations. You can find out more '
'organizations. You can find out more at ' 'at <a href="https://quay.io">Quay.io</a>.'),
'<a href="https://quay.io">Quay.io</a>.'),
'termsOfServiceUrl': 'https://quay.io/tos', 'termsOfServiceUrl': 'https://quay.io/tos',
'contact': 'support@quay.io', 'contact': 'support@quay.io',
}, },
@ -110,6 +110,8 @@ def swagger_route_data():
@resource('/v1/discovery') @resource('/v1/discovery')
class DiscoveryResource(Resource): class DiscoveryResource(Resource):
"""Ability to inspect the API for usage information and documentation."""
@nickname('discovery') @nickname('discovery')
def get(self): def get(self):
""" List all of the API endpoints available in the swagger API format."""
return swagger_route_data() return swagger_route_data()

View file

@ -5,12 +5,10 @@ from flask.ext.restful import Resource, reqparse, abort
from flask.ext.login import current_user from flask.ext.login import current_user
from data import model from data import model
from endpoints.api import (truthy_bool, format_date, nickname, log_action, from endpoints.api import (truthy_bool, format_date, nickname, log_action, validate_json_request,
validate_json_request, require_repo_read, require_repo_read, RepositoryParamResource, resource, query_param,
RepositoryParamResource, resource, query_parameter,
parse_args) parse_args)
from auth.permissions import (ReadRepositoryPermission, from auth.permissions import (ReadRepositoryPermission, ModifyRepositoryPermission,
ModifyRepositoryPermission,
AdministerRepositoryPermission) AdministerRepositoryPermission)
@ -19,11 +17,12 @@ logger = logging.getLogger(__name__)
@resource('/v1/repository') @resource('/v1/repository')
class RepositoryList(Resource): class RepositoryList(Resource):
"""Operations for creating and listing repositories."""
schemas = { schemas = {
'NewRepo': { 'NewRepo': {
'id': 'NewRepo', 'id': 'NewRepo',
'type': 'object', 'type': 'object',
'description': 'Description of a new repository.', 'description': 'Description of a new repository',
'required': [ 'required': [
'repository', 'repository',
'visibility', 'visibility',
@ -31,11 +30,11 @@ class RepositoryList(Resource):
'properties': { 'properties': {
'repository': { 'repository': {
'type': 'string', 'type': 'string',
'description': 'Repository name.', 'description': 'Repository name',
}, },
'visibility': { 'visibility': {
'type': 'string', 'type': 'string',
'description': 'Visibility which the repository will start with.', 'description': 'Visibility which the repository will start with',
'enum': [ 'enum': [
'public', 'public',
'private', 'private',
@ -43,13 +42,12 @@ class RepositoryList(Resource):
}, },
'namespace': { 'namespace': {
'type': 'string', 'type': 'string',
'description': ('Namespace in which the repository should be ' 'description': ('Namespace in which the repository should be created. If omitted, the '
'created. If omitted, the username of the caller is' 'username of the caller is used'),
'used.'),
}, },
'description': { 'description': {
'type': 'string', 'type': 'string',
'description': 'Markdown encoded description for the repository.', 'description': 'Markdown encoded description for the repository',
}, },
} }
} }
@ -58,6 +56,7 @@ class RepositoryList(Resource):
@nickname('createRepo') @nickname('createRepo')
@validate_json_request('NewRepo') @validate_json_request('NewRepo')
def post(self): def post(self):
"""Create a new repository."""
owner = current_user.db_user() owner = current_user.db_user()
req = request.get_json() req = request.get_json()
namespace_name = req['namespace'] if 'namespace' in req else owner.username namespace_name = req['namespace'] if 'namespace' in req else owner.username
@ -78,9 +77,8 @@ class RepositoryList(Resource):
repo.description = req['description'] repo.description = req['description']
repo.save() repo.save()
log_action('create_repo', namespace_name, log_action('create_repo', namespace_name, {'repo': repository_name,
{'repo': repository_name, 'namespace': namespace_name}, 'namespace': namespace_name}, repo=repo)
repo=repo)
return jsonify({ return jsonify({
'namespace': namespace_name, 'namespace': namespace_name,
'name': repository_name 'name': repository_name
@ -90,20 +88,17 @@ class RepositoryList(Resource):
@nickname('listRepos') @nickname('listRepos')
@parse_args @parse_args
@query_parameter('page', 'Offset page number. (int)', type=int) @query_param('page', 'Offset page number. (int)', type=int)
@query_parameter('limit', 'Limit on the number of results (int)', type=int) @query_param('limit', 'Limit on the number of results (int)', type=int)
@query_parameter('namespace', ('Namespace to use when querying for org ' @query_param('namespace', 'Namespace to use when querying for org repositories.', type=str)
'repositories.'), type=str) @query_param('public', 'Whether to include public repositories.', type=truthy_bool, default=True)
@query_parameter('public', 'Whether to include public repositories.', @query_param('private', 'Whether to inlcude private repositories.', type=truthy_bool,
type=truthy_bool, default=True) default=True)
@query_parameter('private', 'Whether to inlcude private repositories.', @query_param('sort', 'Whether to sort the results.', type=truthy_bool, default=False)
type=truthy_bool, default=True) @query_param('count', 'Whether to include a count of the total number of results available.',
@query_parameter('sort', 'Whether to sort the results.', type=truthy_bool, type=truthy_bool, default=False)
default=False)
@query_parameter('count', ('Whether to include a count of the total number '
'of results available.'), type=truthy_bool,
default=False)
def get(self, args): def get(self, args):
"""Fetch the list of repositories under a variety of situations."""
def repo_view(repo_obj): def repo_view(repo_obj):
return { return {
'namespace': repo_obj.namespace, 'namespace': repo_obj.namespace,
@ -120,15 +115,12 @@ class RepositoryList(Resource):
repo_count = None repo_count = None
if args['count']: if args['count']:
repo_count = model.get_visible_repository_count(username, repo_count = model.get_visible_repository_count(username, include_public=args['public'],
include_public=args['public'],
namespace=args['namespace']) namespace=args['namespace'])
response['count'] = repo_count response['count'] = repo_count
repo_query = model.get_visible_repositories(username, limit=args['limit'], repo_query = model.get_visible_repositories(username, limit=args['limit'], page=args['page'],
page=args['page'], include_public=args['public'], sort=args['sort'],
include_public=args['public'],
sort=args['sort'],
namespace=args['namespace']) namespace=args['namespace'])
response['repositories'] = [repo_view(repo) for repo in repo_query] response['repositories'] = [repo_view(repo) for repo in repo_query]
@ -153,9 +145,11 @@ def image_view(image):
@resource('/v1/repository/<path:repository>') @resource('/v1/repository/<path:repository>')
class Repository(RepositoryParamResource): class Repository(RepositoryParamResource):
"""Operations for managing a specific repository."""
@require_repo_read @require_repo_read
@nickname('getRepo') @nickname('getRepo')
def get(self, namespace, repository): def get(self, namespace, repository):
"""Fetch the specified repository."""
logger.debug('Get repo: %s/%s' % (namespace, repository)) logger.debug('Get repo: %s/%s' % (namespace, repository))
def tag_view(tag): def tag_view(tag):