Skip to content

Commit

Permalink
Adds flake8 testing to travis
Browse files Browse the repository at this point in the history
This commit adds flake8 testing to Travis and updates the code so that
it passes those style checks. It also adds the Sphinx documentation
build to Travis to check for any invalid references in the
documentation.
  • Loading branch information
jfinkels committed Sep 7, 2016
1 parent 3c3bf73 commit b57ffb3
Show file tree
Hide file tree
Showing 32 changed files with 339 additions and 191 deletions.
25 changes: 22 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ addons:
# operator). Travis claims that version 9.4 is installed by default, but it
# claims that && is unknown unless this addon is here.
postgresql: "9.4"
apt:
packages:
# These are build dependencies for the documentation; LaTeX is required
# for rendering math. These are the required packages for Ubuntu 12.04,
# Travis' current build environment!
- texlive-latex-base
- texlive-latex-extra
- dvipng


before_install:
Expand All @@ -32,14 +40,25 @@ before_install:
else
export REQUIREMENTS=requirements-test-cpython.txt
fi
- pip install --upgrade pip
install:
# Upgrade pip in case the installed version is out of date.
- pip install --upgrade pip
# Install the test requirements.
- pip install -r $REQUIREMENTS
- pip install coveralls
# Install the requirements specific to Travis tests.
- pip install -r requirements-doc.txt
- pip install flake8 coveralls
# Install Flask-Restless so that it is available for the documentation build.
- python setup.py install

script:
coverage run --source=flask_restless setup.py test
# Code style checks.
- find flask_restless/ tests/ examples/ setup.py -type f -name \*.py -print0 | xargs -0 flake8
# Documentation build checks.
- sphinx-build -n -W docs/ build/sphinx/html/
# Unit tests.
- coverage run --source=flask_restless setup.py test

after_success:
coveralls
2 changes: 2 additions & 0 deletions examples/quickstart.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = flask_sqlalchemy.SQLAlchemy(app)


# Create your Flask-SQLALchemy models as usual but with the following
# restriction: they must have an __init__ method that accepts keyword
# arguments for all columns (the constructor in
Expand All @@ -18,6 +19,7 @@ class Person(db.Model):
name = db.Column(db.Unicode)
birth_date = db.Column(db.Date)


class Article(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.Unicode)
Expand Down
4 changes: 2 additions & 2 deletions examples/server_configurations/authentication/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@
import os
import os.path

from flask import Flask, render_template, redirect, url_for
from flask import flash, Flask, render_template, redirect, url_for
from flask_login import current_user, login_user, LoginManager, UserMixin
from flask_restless import APIManager, ProcessingException, NO_CHANGE
from flask_restless import APIManager, ProcessingException
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import PasswordField, SubmitField, TextField, Form

Expand Down
8 changes: 4 additions & 4 deletions examples/server_configurations/custom_serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,15 @@
from marshmallow_jsonapi import fields
from marshmallow_jsonapi import Schema

## Flask application and database configuration ##
# Flask application and database configuration

app = Flask(__name__)
app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

## Flask-SQLAlchemy model definitions ##
# Flask-SQLAlchemy model definitions #


class Person(db.Model):
Expand All @@ -81,7 +81,7 @@ class Article(db.Model):
author = db.relationship(Person, backref=db.backref('articles'))


## Marshmallow schema definitions ##
# Marshmallow schema definitions #

class PersonSchema(Schema):

Expand Down Expand Up @@ -134,7 +134,7 @@ def make_article(self, data):
return Article(**data)


## Serializer and deserializer classes ##
# Serializer and deserializer classes #

class MarshmallowSerializer(DefaultSerializer):

Expand Down
1 change: 1 addition & 0 deletions examples/server_configurations/separate_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = flask_sqlalchemy.SQLAlchemy(app)


# Create your Flask-SQLALchemy models as usual but with the following two
# (reasonable) restrictions:
# 1. They must have a primary key column of type sqlalchemy.Integer or
Expand Down
31 changes: 25 additions & 6 deletions flask_restless/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,6 @@
SQLAlchemy models via the JSON API protocol.
"""
#: The current version of this extension.
#:
#: This should be the same as the version specified in the :file:`setup.py`
#: file.
__version__ = '1.0.0b2-dev'

# The following names are available as part of the public API for
# Flask-Restless. End users of this package can import these names by doing
# ``from flask_restless import APIManager``, for example.
Expand All @@ -38,3 +32,28 @@
from .serialization import simple_serialize_many
from .views import CONTENT_TYPE
from .views import ProcessingException

#: The current version of this extension.
#:
#: This should be the same as the version specified in the :file:`setup.py`
#: file.
__version__ = '1.0.0b2-dev'

__all__ = [
'APIManager',
'collection_name',
'CONTENT_TYPE',
'DefaultDeserializer',
'DefaultSerializer',
'DeserializationException',
'IllegalArgumentError',
'model_for',
'MultipleExceptions',
'primary_key_for',
'ProcessingException',
'SerializationException',
'serializer_for',
'simple_serialize',
'simple_serialize_many',
'url_for',
]
4 changes: 2 additions & 2 deletions flask_restless/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
expect, for example, a SQLAlchemy model actually receive a SQLAlchemy
model.
.. _SQLAlchemy inspection API: https://docs.sqlalchemy.org/en/latest/core/inspection.html
.. _SQLAlchemy inspection API:
https://docs.sqlalchemy.org/en/latest/core/inspection.html
"""
import datetime
Expand Down Expand Up @@ -381,7 +382,6 @@ def string_to_datetime(model, fieldname, value):
return value



def get_model(instance):
"""Returns the model class of which the specified object is an instance."""
return type(instance)
Expand Down
2 changes: 1 addition & 1 deletion flask_restless/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
DEFAULT_URL_PREFIX = '/api'

if sys.version_info < (3, ):
STRING_TYPES = (str, unicode)
STRING_TYPES = (str, unicode) # noqa
else:
STRING_TYPES = (str, )

Expand Down
8 changes: 8 additions & 0 deletions flask_restless/search/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,11 @@
from .drivers import create_filters
from .drivers import search
from .drivers import search_relationship

__all__ = [
'create_filters',
'FilterCreationError',
'FilterParsingError',
'search',
'search_relationship',
]
13 changes: 13 additions & 0 deletions flask_restless/serialization/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,16 @@
from .serializers import simple_serialize_many
from .serializers import simple_relationship_serialize
from .serializers import simple_relationship_serialize_many

__all__ = [
'DefaultDeserializer',
'DefaultSerializer',
'DeserializationException',
'JsonApiDocument',
'MultipleExceptions',
'SerializationException',
'simple_relationship_serialize',
'simple_relationship_serialize_many',
'simple_serialize',
'simple_serialize_many',
]
9 changes: 6 additions & 3 deletions flask_restless/serialization/deserializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ def deserialize(self, document):
**This method is not implemented in this base class; subclasses
must override this method.**
.. _Resource Objects: http://jsonapi.org/format/#document-structure-resource-objects
.. _Resource Objects:
http://jsonapi.org/format/#document-structure-resource-objects
"""
raise NotImplementedError
Expand All @@ -92,7 +93,8 @@ def deserialize_many(self, document):
**This method is not implemented in this base class; subclasses
must override this method.**
.. _Resource Objects: http://jsonapi.org/format/#document-structure-resource-objects
.. _Resource Objects:
http://jsonapi.org/format/#document-structure-resource-objects
"""
raise NotImplementedError
Expand Down Expand Up @@ -203,7 +205,8 @@ def deserialize(self, document):
*Implementation note:* everything in the document other than the
``data`` element is ignored.
.. _Resource Objects: http://jsonapi.org/format/#document-structure-resource-objects
.. _Resource Objects:
http://jsonapi.org/format/#document-structure-resource-objects
"""
if 'data' not in document:
Expand Down
3 changes: 2 additions & 1 deletion flask_restless/serialization/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ def create_relationship(model, instance, relation):
created for the primary model, `model`, or the model of the
relation.
.. _Relationships: http://jsonapi.org/format/#document-resource-object-relationships
.. _Relationships:
http://jsonapi.org/format/#document-resource-object-relationships
"""
result = {}
Expand Down
8 changes: 8 additions & 0 deletions flask_restless/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,11 @@
from .resources import API
from .relationships import RelationshipAPI
from .function import FunctionAPI

__all__ = [
'API',
'CONTENT_TYPE',
'FunctionAPI',
'ProcessingException',
'RelationshipAPI',
]
49 changes: 26 additions & 23 deletions flask_restless/views/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,12 +218,12 @@ def _is_msie8or9():
our best guess based on the information provided.
"""
if request.user_agent is None or request.user_agent.browser != 'msie' \
or request.user_agent.version is None:
return False
# request.user_agent.version comes as a string, so we have to parse it
version = lambda ua: tuple(int(d) for d in ua.version.split('.'))
return (request.user_agent is not None and
request.user_agent.version is not None and
request.user_agent.browser == 'msie' and
(8, 0) <= version(request.user_agent) < (10, 0))
version = tuple(map(int, request.user_agent.version.split('.')))
return (8, 0) <= version < (10, 0)


def un_camel_case(s):
Expand Down Expand Up @@ -323,7 +323,8 @@ def requires_json_api_accept(func):
def get(self, *args, **kw):
return '...'
.. _Server Responsibilities: http://jsonapi.org/format/#content-negotiation-servers
.. _Server Responsibilities:
http://jsonapi.org/format/#content-negotiation-servers
"""
@wraps(func)
Expand Down Expand Up @@ -916,17 +917,17 @@ class Paginated(object):
>>> for rel, url in paginated.pagination_links.items():
... print(rel, url)
...
first http://example.com/api/person?page[size]=3&page[number]=1
last http://example.com/api/person?page[size]=3&page[number]=4
prev http://example.com/api/person?page[size]=3&page[number]=1
next http://example.com/api/person?page[size]=3&page[number]=3
first http://localhost/api/person?page[size]=3&page[number]=1
last http://localhost/api/person?page[size]=3&page[number]=4
prev http://localhost/api/person?page[size]=3&page[number]=1
next http://localhost/api/person?page[size]=3&page[number]=3
>>> for link in paginated.header_links:
... print(link)
...
<http://example.com/api/person?page[size]=3&page[number]=1>; rel="first"
<http://example.com/api/person?page[size]=3&page[number]=4>; rel="last"
<http://example.com/api/person?page[size]=3&page[number]=1>; rel="prev"
<http://example.com/api/person?page[size]=3&page[number]=3>; rel="next"
<http://localhost/api/person?page[size]=3&page[number]=1>; rel="first"
<http://localhost/api/person?page[size]=3&page[number]=4>; rel="last"
<http://localhost/api/person?page[size]=3&page[number]=1>; rel="prev"
<http://localhost/api/person?page[size]=3&page[number]=3>; rel="next"
"""

Expand Down Expand Up @@ -1333,9 +1334,6 @@ def __init__(self, session, model, preprocessors=None, postprocessors=None,
#: serialization.
self.serializer = serializer

#: A custom serialization function for linkage objects.
#self.serialize_relationship = simple_relationship_serialize

#: A custom deserialization function for primary resources; see
#: :ref:`serialization` for more information.
#:
Expand Down Expand Up @@ -1368,12 +1366,13 @@ def __init__(self, session, model, preprocessors=None, postprocessors=None,
# database integrity errors. However, in order to rollback the session,
# we need to have a session object available to roll back. Therefore we
# need to manually decorate each of the view functions here.
decorate = lambda name, f: setattr(self, name, f(getattr(self, name)))
for method in ['get', 'post', 'patch', 'delete']:
# Check if the subclass has the method before trying to decorate
# it.
if hasattr(self, method):
decorate(method, catch_integrity_errors(self.session))
wrapper = catch_integrity_errors(self.session)
old_method = getattr(self, method)
setattr(self, method, wrapper(old_method))

def collection_processor_type(self, *args, **kw):
"""The suffix for the pre- and postprocessor identifiers for
Expand Down Expand Up @@ -1683,7 +1682,8 @@ def _get_collection_helper(self, resource=None, relation_name=None,
#
# - a collection of primary resources (as in `GET /person`),
# - a to-many relation (as in `GET /person/1/articles`),
# - a to-many relationship (as in `GET /person/1/relationships/articles`)
# - a to-many relationship (as in
# `GET /person/1/relationships/articles`)
#
items = paginated.items
# This covers the relationship object case...
Expand Down Expand Up @@ -1744,9 +1744,11 @@ def _get_collection_helper(self, resource=None, relation_name=None,
# as in `GET /people`, or a to-many relation, as in `GET
# /people/1/comments`.
if resource is None:
links = linker.generate_links(None, None, None, None, False, False)
links = linker.generate_links(None, None, None, None, False,
False)
else:
links = linker.generate_links(resource, None, None, False, False)
links = linker.generate_links(resource, None, None, False,
False)
result['links'].update(links)

# Create the metadata for the response, like headers and
Expand Down Expand Up @@ -1807,7 +1809,8 @@ def resources_to_include(self, instance):
which resources, other than the primary resource or resources, will be
included in a compound document response.
.. _Inclusion of Related Resources: http://jsonapi.org/format/#fetching-includes
.. _Inclusion of Related Resources:
http://jsonapi.org/format/#fetching-includes
"""
# Add any links requested to be included by URL parameters.
Expand Down
1 change: 0 additions & 1 deletion flask_restless/views/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
# License version 3 and under the 3-clause BSD license. For more
# information, see LICENSE.AGPL and LICENSE.BSD.
"""Helper functions for view classes."""
from sqlalchemy.exc import OperationalError
from sqlalchemy.inspection import inspect as sqlalchemy_inspect
from sqlalchemy.sql import func

Expand Down
4 changes: 2 additions & 2 deletions flask_restless/views/relationships.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,8 +289,8 @@ def patch(self, resource_id, relation_name):
detail = ('No resource of type {0} found'
' with ID {1}').format(type_, id_)
return error_response(404, detail=detail)
if (isinstance(replacement, list)
and any(value is None for value in replacement)):
if isinstance(replacement, list) \
and any(value is None for value in replacement):
not_found = (rel for rel, value in zip(data, replacement)
if value is None)
detail = 'No resource of type {0} found with ID {1}'
Expand Down
Loading

0 comments on commit b57ffb3

Please sign in to comment.