From ba315822eb0a11d4be15a56f029a0107830bc6c8 Mon Sep 17 00:00:00 2001 From: Felix Claessen <30658763+Flix6x@users.noreply.github.com> Date: Thu, 7 Sep 2023 13:58:20 +0200 Subject: [PATCH] Update master for release v0.16.0 (#153) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * @ #135 | update for the next version iteration * @ #134 | allow releases/vX.Y.Z and releases/X.Y.Z to be published as docs * Compatibility with werkzeug 2.2 (#145) Compatibility with Flask>=2.2 * Initialize base_args as class field Only include actual rule args in base_args * Fix compatibility with Werkzeug 2.2 werkzeug.routing.parse_rule was considered an internal detail and has been removed during a refactor. We can now rely on werkzeug.routing.Rule which has a `arguments` field that contains the information we need. However, this field is not populated until the Rule has been added to a Map and this Map has been bound. So, we use a dummy map and bind it to the empty string just to get the arguments field ready for our use. * Rework test matrix, pass more exhaustive requirements to pip - EOL python versions and alpha flask have been removed from test matrix - Add python 3.10 - Only test "branches" of flask and not all bugfix releases * Fix test_base_args The tested view has a route_base with no declared arguments, so we shouldn't expect the base_args to have a nonzero length. * Rewrite test_rule_options This test file mostly tests the same behavior over and over: that the options given to `FlaskView.register`, such as `strict_slashes`, are passed along to `Flask.add_url_rule`. It did this by testing the behavior of the view when calling its endpoints with or without the trailing slash, expecting it to return the same response. However, werkzeug never guaranteed this behavior. The only documented behavior tunable by this option is: "If strict_slashes is enabled (the default), visiting a branch URL without a trailing slash will redirect to the URL with a slash appended." So, with the reimplementation of the routing in werkzeug 2.2, this behavior is lost. Instead of testing the behavior of the view, let's mock `add_url_rule` and check that it's called with `strict_slashes` as `False`. * Fix test_blueprints Flask >=2.2 raises an error when trying to apply changes to an app which has already serviced requests. For this specific test, we can redefine the app. * Pass rule_options to add_url_rules when adding a @route-ed rule * Remove nose which is deprecated, use pytest * docs: add changelog entry and bump version (#151) Signed-off-by: F.N. Claessen --------- Signed-off-by: F.N. Claessen Co-authored-by: hoatle Co-authored-by: Jérôme Tamba --- .github/workflows/lint-test-docs.yaml | 36 ++---- CHANGELOG.md | 9 ++ Makefile | 2 +- dev-setup/README.md | 2 +- docker-compose.yml | 2 +- docs/conf.py | 4 +- flask_classful.py | 26 ++-- requirements.txt | 3 +- run-dev.sh | 4 +- setup.cfg | 3 - test_classful/__init__.py | 9 -- test_classful/test_base_args.py | 38 +++--- test_classful/test_blueprints.py | 71 +++++------ test_classful/test_bp_subdomains.py | 9 +- test_classful/test_common.py | 126 +++++++++---------- test_classful/test_decorators.py | 160 ++++++++++++------------- test_classful/test_default_methods.py | 9 +- test_classful/test_endpoints.py | 15 ++- test_classful/test_excluded_methods.py | 9 +- test_classful/test_inheritance.py | 21 ++-- test_classful/test_init_argument.py | 9 +- test_classful/test_inspect_args.py | 13 +- test_classful/test_method_dashified.py | 13 +- test_classful/test_register.py | 14 ++- test_classful/test_representations.py | 49 ++++---- test_classful/test_route_base.py | 5 +- test_classful/test_route_prefix.py | 7 +- test_classful/test_rule_options.py | 83 ++----------- test_classful/test_subdomains.py | 35 +++--- test_classful/test_trailing_slash.py | 105 ++++++++-------- test_classful/test_view_wrappers.py | 19 ++- test_classful_py3/test_type_hints.py | 19 ++- tox.ini | 5 - 33 files changed, 414 insertions(+), 520 deletions(-) delete mode 100644 setup.cfg delete mode 100644 tox.ini diff --git a/.github/workflows/lint-test-docs.yaml b/.github/workflows/lint-test-docs.yaml index a420158..ed40684 100644 --- a/.github/workflows/lint-test-docs.yaml +++ b/.github/workflows/lint-test-docs.yaml @@ -29,32 +29,14 @@ jobs: strategy: fail-fast: false matrix: - python: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9"] - flask: ["0.12.5", "1.0", "1.0.1", "1.0.2", "1.0.3", "1.0.4", "1.1.0", "1.1.1", - "1.1.2", "1.1.3", "1.1.4", "2.0.0", "2.0.1", "2.0.2"] + python: ["3.7", "3.8", "3.9", "3.10"] + requirements: + - "flask>=1.0,<1.1 werkzeug<2.1 jinja2<3 markupsafe<2.1 itsdangerous<2.1" + - "flask>=1.1,<1.2 markupsafe==2.0.1" + - "flask>=2.0,<2.1" + - "flask>=2.1,<2.2" + - "flask>=2.2,<2.3" experimental: [false] - # include: - # - python: "3.10" - # # known issue: https://github.com/nose-devs/nose/issues/1099 - # experimental: true - exclude: - # excludes flask versions from unsupported python versions - - python: "2.7" - flask: "1.1.3" - - python: "2.7" - flask: "2.0.0" - - python: "2.7" - flask: "2.0.1" - - python: "2.7" - flask: "2.0.2" - - python: "3.5" - flask: "1.1.3" - - python: "3.5" - flask: "2.0.0" - - python: "3.5" - flask: "2.0.1" - - python: "3.5" - flask: "2.0.2" runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 @@ -63,9 +45,9 @@ jobs: run: | docker-compose run --rm dev env: + REQUIREMENTS: ${{ matrix.requirements }} CHECK_STYLE: no DEV_IMAGE: python:${{ matrix.python }} - FLASK: ${{ matrix.flask }} # build and publish docs docs: @@ -92,7 +74,7 @@ jobs: TARGET_FOLDER=develop elif [[ $GIT_BRANCH =~ ^v[0-9.]+[0-9.a-z\-]*$ ]]; then TARGET_FOLDER=${GIT_BRANCH:1} - elif [[ $GIT_BRANCH =~ ^[0-9.]+[0-9.a-z\-]*$ || $GIT_BRANCH =~ ^releases\/[0-9.]+[0-9.a-z\-]*$ ]]; then + elif [[ $GIT_BRANCH =~ ^[0-9.]+[0-9.a-z\-]*$ || $GIT_BRANCH =~ ^releases\/[v0-9.]+[0-9.a-z\-]*$ ]]; then TARGET_FOLDER=$GIT_BRANCH fi echo "\$TARGET_FOLDER: $TARGET_FOLDER" diff --git a/CHANGELOG.md b/CHANGELOG.md index a641d07..b112f71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +2023-08-28 F.N. Claessen +----------------------------------------- + + Version: 0.16.0 + + - Tasks: + * Compatibility with werkzeug 2.2 #145 + + 2021-12-25 Hoat Le -------------------------------------- diff --git a/Makefile b/Makefile index 2a0a07d..0715c4f 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ test-clean: coverage erase test-intg: - coverage run --branch --source=. `which nosetests` -v --exe + coverage run --branch --source=. -m pytest test: | test-clean test-intg diff --git a/dev-setup/README.md b/dev-setup/README.md index f708827..1d12c74 100644 --- a/dev-setup/README.md +++ b/dev-setup/README.md @@ -56,7 +56,7 @@ Stop the watching files by using `Ctrl + c`. ## How to develop -- `$ docker-compose up` will check code style and run tests with defaul Python image. +- `$ docker-compose up` will check code style and run tests with default Python image. There are environment variables to run and check with different versions of Python: diff --git a/docker-compose.yml b/docker-compose.yml index 9b85086..be7724a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ services: working_dir: /opt/app command: sh run-dev.sh environment: - FLASK: ${FLASK:-1.1.1} + REQUIREMENTS: ${REQUIREMENTS:-flask==2.0.0} CHECK_STYLE: ${CHECK_STYLE:-yes} RUN_TEST: ${RUN_TEST:-yes} volumes: diff --git a/docs/conf.py b/docs/conf.py index 3a6aba2..04d0c92 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -49,9 +49,9 @@ # built documents. # # The short X.Y version. -version = '0.15' +version = '0.16' # The full version, including alpha/beta/rc tags. -release = '0.15.0-b1' +release = '0.16.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/flask_classful.py b/flask_classful.py index 5f2c436..4b8c248 100644 --- a/flask_classful.py +++ b/flask_classful.py @@ -12,14 +12,14 @@ import functools import inspect from uuid import UUID -from werkzeug.routing import parse_rule +from werkzeug.routing import Rule, Map from flask import request, make_response from flask.wrappers import ResponseBase import re _py2 = sys.version_info[0] == 2 -__version__ = "0.15.0-b1" +__version__ = "0.16.0" def route(rule, **options): @@ -66,6 +66,7 @@ class FlaskView(object): route_base = None route_prefix = None trailing_slash = True + base_args = [] excluded_methods = [] # specify the class methods to be explicitly excluded from routing creation # TODO(hoatle): make method_dashified=True as default instead, # this is not a compatible change @@ -165,6 +166,7 @@ def register(cls, app, route_base=None, subdomain=None, route_prefix=None, if hasattr(value, "_rule_cache") and name in value._rule_cache: for idx, cached_rule in enumerate(value._rule_cache[name]): rule, options = cached_rule + options.update(rule_options) rule = cls.build_rule(rule) sub, ep, options = cls.parse_options(options) @@ -370,9 +372,8 @@ def build_rule(cls, rule, method=None): rule_parts.append(route_base) if len(rule) > 0: # the case of rule='' empty string rule_parts.append(rule) - ignored_rule_args = ['self'] - if hasattr(cls, 'base_args'): - ignored_rule_args += cls.base_args + + ignored_rule_args = ['self'] + cls.base_args if method and getattr(cls, 'inspect_args', True): argspec = get_true_argspec(method) @@ -400,13 +401,13 @@ def get_route_base(cls): if cls.route_base is not None: route_base = cls.route_base - base_rule = parse_rule(route_base) - # see: https://github.com/teracyhq/flask-classful/issues/50 - if hasattr(cls, 'base_args'): - # thanks to: https://github.com/teracyhq/flask-classful/pull/56#issuecomment-328985183 - cls.base_args = list(set(cls.base_args).union(r[2] for r in base_rule)) - else: - cls.base_args = [r[2] for r in base_rule] + if not route_base.startswith('/'): + route_base = '/' + route_base + base_rule = Rule(route_base) + # Add rule to a dummy map and bind that map so that + # the Rule's arguments field is populated + Map(rules=[base_rule]).bind('') + cls.base_args.extend(base_rule.arguments) else: route_base = cls.default_route_base() @@ -524,4 +525,3 @@ def unpack(value): class DecoratorCompatibilityError(Exception): pass - diff --git a/requirements.txt b/requirements.txt index 83fa719..362eaa4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,5 @@ # test -nose -tox +pytest # code style, coverage coverage diff --git a/run-dev.sh b/run-dev.sh index c758e3c..daed50c 100644 --- a/run-dev.sh +++ b/run-dev.sh @@ -4,8 +4,7 @@ set -eu pipefail make resolve; -pip install Flask==$FLASK; -pip install webargs!=5.0.0; +pip install $REQUIREMENTS; python setup.py install; if [ "$CHECK_STYLE" = "yes" ] || [ "$CHECK_STYLE" = "1" ]; then @@ -13,6 +12,7 @@ if [ "$CHECK_STYLE" = "yes" ] || [ "$CHECK_STYLE" = "1" ]; then fi if [ "$RUN_TEST" = "yes" ] || [ "$RUN_TEST" = "1" ]; then + pip install webargs make test; make report-coverage; fi diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index da714c7..0000000 --- a/setup.cfg +++ /dev/null @@ -1,3 +0,0 @@ -[nosetests] -where=test_classful -py3where=. diff --git a/test_classful/__init__.py b/test_classful/__init__.py index cb06308..e69de29 100644 --- a/test_classful/__init__.py +++ b/test_classful/__init__.py @@ -1,9 +0,0 @@ -import nose - - -if __name__ == "__main__": - # nose.run() - nose.run(env={ - 'NOSE_INCLUDE_EXE': True, - 'NOSE_VERBOSE': 2 - }) diff --git a/test_classful/test_base_args.py b/test_classful/test_base_args.py index 0e4edca..47e5826 100644 --- a/test_classful/test_base_args.py +++ b/test_classful/test_base_args.py @@ -6,7 +6,6 @@ from marshmallow import Schema, fields from webargs.flaskparser import use_args from webargs import fields -from nose.tools import eq_ # we'll make a list to hold some quotes for our app quotes = [ @@ -138,69 +137,68 @@ def put(self, args, id): def test_users_post(): resp = client.post('users/', headers=input_headers, data=json.dumps({'email':'test@example.com'})) - eq_(resp.status_code, 200) - eq_("test@example.com", resp.data.decode('ascii')) + assert resp.status_code == 200 + assert "test@example.com" == resp.data.decode('ascii') def test_users_put(): resp = client.put('users/1/', headers=input_headers, data=json.dumps({'email':'test@example.com'})) - eq_(resp.status_code, 200) - eq_("test@example.com", resp.data.decode('ascii')) + assert resp.status_code == 200 + assert "test@example.com" == resp.data.decode('ascii') def test_users_patch(): resp = client.patch('users/1/', headers=input_headers, data=json.dumps({'email':'test@example.com'})) - eq_(resp.status_code, 200) - eq_("test@example.com", resp.data.decode('ascii')) + assert resp.status_code == 200 + assert "test@example.com" == resp.data.decode('ascii') def test_quotes_index(): resp = client.get("/quotes/") num = len(str(resp.data).split("
")) - eq_(3, num) + assert 3 == num resp = client.get("/quotes") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_quotes_get(): resp = client.get("/quotes/0/") - eq_(quotes[0], resp.data.decode('ascii')) + assert quotes[0] == resp.data.decode('ascii') def test_quotes_put(): resp = client.put("/quotes/1/", headers=input_headers, data=json.dumps(input_data)) - eq_(input_data["text"], resp.data.decode('ascii')) + assert input_data["text"] == resp.data.decode('ascii') def test_quotes_factory(): resp = client.patch("/quotes/1/", headers=input_headers, data=json.dumps(input_data)) - eq_(input_data["text"], resp.data.decode('ascii')) + assert input_data["text"] == resp.data.decode('ascii') def test_quotes2_index(): resp = client.get("/quotes-2/") num = len(str(resp.data).split("
")) - eq_(3, num) + assert 3 == num resp = client.get("/quotes-2") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_quotes2_get(): resp = client.get("/quotes-2/0/") - eq_(quotes[0], resp.data.decode('ascii')) - eq_(UglyNameView.base_args.count(UglyNameView.route_base), 1) + assert quotes[0] == resp.data.decode('ascii') + assert UglyNameView.base_args.count(UglyNameView.route_base) == 0 def test_quotes2_put(): resp = client.put("/quotes-2/1/", headers=input_headers, data=json.dumps(input_data)) - eq_(input_data["text"], resp.data.decode('ascii')) - eq_(UglyNameView.base_args.count(UglyNameView.route_base), 1) + assert input_data["text"] == resp.data.decode('ascii') + assert UglyNameView.base_args.count(UglyNameView.route_base) == 0 # see: https://github.com/teracyhq/flask-classful/pull/56#issuecomment-328985183 def test_unique_elements(): client.put("/quotes-2/1/", headers=input_headers, data=json.dumps(input_data)) - eq_(UglyNameView.base_args.count(UglyNameView.route_base), 1) - + assert UglyNameView.base_args.count(UglyNameView.route_base) == 0 diff --git a/test_classful/test_blueprints.py b/test_classful/test_blueprints.py index 00b2e0d..b5eb5df 100644 --- a/test_classful/test_blueprints.py +++ b/test_classful/test_blueprints.py @@ -2,7 +2,6 @@ from flask import Flask, Blueprint from .view_classes import BasicView, IndexView, JSONifyTestView -from nose.tools import eq_ app = Flask("blueprints") bp = Blueprint("bptest", "bptest") @@ -16,123 +15,125 @@ def test_bp_index(): resp = client.get("/basic/") - eq_(b"Index", resp.data) + assert b"Index" == resp.data def test_bp_get(): resp = client.get("/basic/1234/") - eq_(b"Get 1234", resp.data) + assert b"Get 1234" == resp.data resp = client.get("/basic/1234") print(resp) - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_bp_put(): resp = client.put("/basic/1234/") - eq_(b"Put 1234", resp.data) + assert b"Put 1234" == resp.data resp = client.put("/basic/1234") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_bp_patch(): resp = client.patch("/basic/1234/") - eq_(b"Patch 1234", resp.data) + assert b"Patch 1234" == resp.data resp = client.patch("/basic/1234") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_bp_post(): resp = client.post("/basic/") - eq_(b"Post", resp.data) + assert b"Post" == resp.data def test_bp_delete(): resp = client.delete("/basic/1234/") - eq_(b"Delete 1234", resp.data) + assert b"Delete 1234" == resp.data resp = client.delete("/basic/1234") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_bp_custom_method(): resp = client.get("/basic/custom_method/") - eq_(b"Custom Method", resp.data) + assert b"Custom Method" == resp.data resp = client.get("/basic/custom_method") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_bp_custom_method_with_params(): resp = client.get("/basic/custom_method_with_params/1234/abcd/") - eq_(b"Custom Method 1234 abcd", resp.data) + assert b"Custom Method 1234 abcd" == resp.data resp = client.get("/basic/custom_method_with_params/1234/abcd") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_bp_routed_method(): resp = client.get("/basic/routed/") - eq_(b"Routed Method", resp.data) + assert b"Routed Method" == resp.data def test_bp_multi_routed_method(): resp = client.get("/basic/route1/") - eq_(b"Multi Routed Method", resp.data) + assert b"Multi Routed Method" == resp.data resp = client.get("/basic/route2/") - eq_(b"Multi Routed Method", resp.data) + assert b"Multi Routed Method" == resp.data def test_bp_no_slash(): resp = client.get("/basic/noslash") - eq_(b"No Slash Method", resp.data) + assert b"No Slash Method" == resp.data resp = client.get("/basic/noslash/") # matches get(id) - eq_(b"Get noslash", resp.data) + assert b"Get noslash" == resp.data def test_bp_index_view_index(): resp = client.get("/") - eq_(b"Index", resp.data) + assert b"Index" == resp.data def test_bp_custom_http_method(): resp = client.post("/basic/route3/") - eq_(b"Custom HTTP Method", resp.data) + assert b"Custom HTTP Method" == resp.data def test_bp_url_prefix(): + app = Flask("blueprints") foo = Blueprint('foo', __name__) BasicView.register(foo, route_base="/") app.register_blueprint(foo, url_prefix='/foo') + client = app.test_client() resp = client.get('/foo/') - eq_(b"Index", resp.data) + assert b"Index" == resp.data def test_jsonify_normal_index(): resp = client.get('/jsonify') - eq_(resp.status_code, 200) - eq_(json.loads(resp.data.decode('utf-8')), dict(success=True)) + assert resp.status_code == 200 + assert json.loads(resp.data.decode('utf-8')) == dict(success=True) def test_jsonify_post_custom_status_code(): resp = client.post('/jsonify') - eq_(resp.status_code, 201) - eq_(json.loads(resp.data.decode('utf-8')), dict(success=True)) + assert resp.status_code == 201 + assert json.loads(resp.data.decode('utf-8')) == dict(success=True) def test_jsonify_not_found(): resp = client.get('/jsonify/not-found') - eq_(resp.status_code, 404) - eq_(json.loads(resp.data.decode('utf-8')), dict(success=False)) + assert resp.status_code == 404 + assert json.loads(resp.data.decode('utf-8')) == dict(success=False) def test_custom_header(): resp = client.get('/jsonify/custom-header') - eq_(resp.status_code, 418) - eq_(resp.headers['X-TEAPOT'], '1') - eq_(json.loads(resp.data.decode('utf-8')), dict(success=True)) + assert resp.status_code == 418 + assert resp.headers['X-TEAPOT'] == '1' + assert json.loads(resp.data.decode('utf-8')) == dict(success=True) def test_normal_jsonify(): resp = client.get('/jsonify/normal') - eq_(resp.status_code, 200) - eq_(resp.headers is not None, True) - eq_(json.loads(resp.data.decode('utf-8')), dict(success=True)) + assert resp.status_code == 200 + assert resp.headers is not None + assert json.loads(resp.data.decode('utf-8')) == dict(success=True) diff --git a/test_classful/test_bp_subdomains.py b/test_classful/test_bp_subdomains.py index 9331dc0..e35552e 100644 --- a/test_classful/test_bp_subdomains.py +++ b/test_classful/test_bp_subdomains.py @@ -1,6 +1,5 @@ from flask import Flask, Blueprint from .view_classes import BasicView, SubdomainAttributeView, SubdomainRouteView -from nose.tools import eq_ app = Flask("blueprints") app.config["SERVER_NAME"] = "test.test" @@ -22,19 +21,19 @@ def test_bp_attr_subdomain(): resp = client.get( "/subdomain-attribute/", base_url="http://sub1.test.test") - eq_(b"Index", resp.data) + assert b"Index" == resp.data def test_bp_route_subdomain(): resp = client.get("/subdomain-route/", base_url="http://sub2.test.test") - eq_(b"Index", resp.data) + assert b"Index" == resp.data def test_bp_register_subdomain(): resp = client.get("/basic/", base_url="http://sub3.test.test") - eq_(b"Index", resp.data) + assert b"Index" == resp.data def test_bp_bp_subdomain(): resp = client.get("/basic/", base_url="http://sub4.test.test") - eq_(b"Index", resp.data) + assert b"Index" == resp.data diff --git a/test_classful/test_common.py b/test_classful/test_common.py index b9e28f3..7e1a6c6 100644 --- a/test_classful/test_common.py +++ b/test_classful/test_common.py @@ -1,181 +1,183 @@ from flask import Flask from flask_classful import unpack, get_true_argspec, method, route, DecoratorCompatibilityError from .view_classes import BasicView, IndexView -from nose.tools import eq_, raises +from pytest import raises + app = Flask("common") BasicView.register(app) IndexView.register(app) + client = app.test_client() def test_index(): resp = client.get("/basic/") - eq_(b"Index", resp.data) + assert b"Index" == resp.data def test_get(): resp = client.get("/basic/1234/") - eq_(resp.status_code, 404) - eq_(b"Get 1234", resp.data) + assert resp.status_code == 404 + assert b"Get 1234" == resp.data resp = client.get("/basic/1234") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_put(): resp = client.put("/basic/1234/") - eq_(resp.status_code, 403) - eq_(resp.headers['say'], 'hello') - eq_(b"Put 1234", resp.data) + assert resp.status_code == 403 + assert resp.headers['say'] == 'hello' + assert b"Put 1234" == resp.data resp = client.put("/basic/1234") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_patch(): resp = client.patch("/basic/1234/") - eq_(b"Patch 1234", resp.data) + assert b"Patch 1234" == resp.data resp = client.patch("/basic/1234") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_post(): resp = client.post("/basic/") - eq_(b"Post", resp.data) + assert b"Post" == resp.data resp = client.post("/basic") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_delete(): resp = client.delete("/basic/1234/") - eq_(b"Delete 1234", resp.data) + assert b"Delete 1234" == resp.data resp = client.delete("/basic/1234") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_custom_method(): resp = client.get("/basic/custom_method/") - eq_(b"Custom Method", resp.data) + assert b"Custom Method" == resp.data resp = client.get("/basic/custom_method") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_custom_method_with_params(): resp = client.get("/basic/custom_method_with_params/1234/abcd/") - eq_(b"Custom Method 1234 abcd", resp.data) + assert b"Custom Method 1234 abcd" == resp.data resp = client.get("/basic/custom_method_with_params/1234/abcd") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_routed_method(): resp = client.get("/basic/routed/") - eq_(b"Routed Method", resp.data) + assert b"Routed Method" == resp.data resp = client.get("/basic/routed") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_multi_routed_method(): resp = client.get("/basic/route1/") - eq_(b"Multi Routed Method", resp.data) + assert b"Multi Routed Method" == resp.data resp = client.get("/basic/route1") - eq_(resp.status_code, 308) + assert resp.status_code == 308 resp = client.get("/basic/route2/") - eq_(b"Multi Routed Method", resp.data) + assert b"Multi Routed Method" == resp.data resp = client.get("/basic/route2") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_no_slash(): resp = client.get("/basic/noslash") - eq_(b"No Slash Method", resp.data) + assert b"No Slash Method" == resp.data resp = client.get("/basic/noslash/") # matches get(id) - eq_(b"Get noslash", resp.data) + assert b"Get noslash" == resp.data def test_index_view_index(): resp = client.get("/") - eq_(b"Index", resp.data) + assert b"Index" == resp.data resp = client.get("") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_custom_http_method(): resp = client.post("/basic/route3/") - eq_(b"Custom HTTP Method", resp.data) + assert b"Custom HTTP Method" == resp.data resp = client.post("/basic/route3") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_method_decorator_simple(): resp = client.post("/basic/methoddecorated/") - eq_(b"POST", resp.data) + assert b"POST" == resp.data resp = client.post("/basic/methoddecorated") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_method_decorator_twice(): resp = client.post('/basic/methodtwicedecorated/') - eq_(b"POST", resp.data) + assert b"POST" == resp.data resp = client.patch('/basic/methodtwicedecorated/') - eq_(b"PATCH", resp.data) + assert b"PATCH" == resp.data def test_method_route(): """Test that the @method decorator does not come into play when a route is set explicitly""" resp = client.post('/basic/methodroute') - eq_(resp.status_code, 405) + assert resp.status_code == 405 resp = client.get('/basic/methodroute') - eq_(b"GET", resp.data) + assert b"GET" == resp.data def test_docstrings(): proxy_func = app.view_functions["BasicView:index"] - eq_(proxy_func.__doc__, BasicView.index.__doc__) + assert proxy_func.__doc__ == BasicView.index.__doc__ def test_unpack_tuple(): """Test unpack tuple data""" response, code, headers = unpack(("response", 100, "c")) - eq_("response", response) - eq_(100, code) - eq_("c", headers) + assert "response" == response + assert 100 == code + assert "c" == headers response, code, headers = unpack(('response', 404)) - eq_("response", response) - eq_(404, code) - eq_({}, headers) + assert "response" == response + assert 404 == code + assert {} == headers response, code, headers = unpack(('response')) - eq_("response", response) - eq_(200, code) - eq_({}, headers) + assert "response" == response + assert 200 == code + assert {} == headers def test_unpack_not_tuple(): """Test unpack not tuple data""" response, code, headers = unpack(None) - eq_(None, response) - eq_(200, code) - eq_({}, headers) + assert None == response + assert 200 == code + assert {} == headers response, code, headers = unpack({}) - eq_({}, response) - eq_(200, code) - eq_({}, headers) + assert {} == response + assert 200 == code + assert {} == headers response, code, headers = unpack("string") - eq_("string", response) - eq_(200, code) - eq_({}, headers) + assert "string" == response + assert 200 == code + assert {} == headers response, code, headers = unpack(('response', 1, 2, 3, 4, 5)) - eq_(('response', 1, 2, 3, 4, 5), response) - eq_(200, code) - eq_({}, headers) + assert ('response', 1, 2, 3, 4, 5) == response + assert 200 == code + assert {} == headers -@raises(TypeError) def test_get_true_argspec_raise_error(): """Test get_true_argspec will raise error if method is not correct""" - get_true_argspec(None) + with raises(TypeError): + get_true_argspec(None) def test_get_true_argspec_func(): @@ -193,5 +195,5 @@ def _inner(): response = get_true_argspec(_method) - eq_(None, response) + assert None == response diff --git a/test_classful/test_decorators.py b/test_classful/test_decorators.py index 3984b04..e21918a 100644 --- a/test_classful/test_decorators.py +++ b/test_classful/test_decorators.py @@ -6,7 +6,6 @@ from .view_classes import DecoratedListFunctionAttributesView from .view_classes import DecoratedListMemberFunctionAttributesView from .view_classes import DecoratedAppendClassAttributeView -from nose.tools import eq_ app = Flask("decorated") DecoratedView.register(app) @@ -21,106 +20,106 @@ def test_func_decorator_index(): resp = client.get('/decorated/') - eq_(b"Index", resp.data) + assert b"Index" == resp.data resp = client.get('/decorated') - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_func_decorator_get(): resp = client.get('/decorated/1234/') - eq_(b"Get 1234", resp.data) + assert b"Get 1234" == resp.data resp = client.get('/decorated/1234') - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_recursive_decorator_post(): resp = client.post('/decorated/') - eq_(b"Post", resp.data) + assert b"Post" == resp.data resp = client.post('/decorated') - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_more_recursive_decorator_get(): resp = client.get('/decorated/get_some/') - eq_(b"Get Some", resp.data) + assert b"Get Some" == resp.data resp = client.get('/decorated/get_some') - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_multiple_recursive_decorators_get(): resp = client.get('/decorated/get_this/') - eq_(b"Get This", resp.data) + assert b"Get This" == resp.data resp = client.get('/decorated/get_this') - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_routes_with_recursive_decorators(): resp = client.get('/decorated/mixitup/') - eq_(b"Mix It Up", resp.data) + assert b"Mix It Up" == resp.data resp = client.get('/decorated/mixitup') - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_recursive_with_parameter(): resp = client.get('/decorated/someval/1234/') - eq_(b"Someval 1234", resp.data) + assert b"Someval 1234" == resp.data def test_recursive_with_route_with_parameter(): resp = client.get('/decorated/anotherval/1234/') - eq_(b"Anotherval 1234", resp.data) + assert b"Anotherval 1234" == resp.data def test_params_decorator(): resp = client.get('/decorated/params_decorator_method/') - eq_(b"Params Decorator", resp.data) + assert b"Params Decorator" == resp.data def test_params_decorator_delete(): resp = client.delete('/decorated/1234/') - eq_(b"Params Decorator Delete 1234", resp.data) + assert b"Params Decorator Delete 1234" == resp.data resp = client.delete('/decorated/1234') - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_decorator_bold_list_get(): """Tests that the get route is wrapped in bold""" resp = client.get('/decorated_bold_list_view/1234/') - eq_(b'' in resp.data, True) - eq_(b'' in resp.data, True) - eq_(b'Get 1234', resp.data) + assert b'' in resp.data + assert b'' in resp.data + assert b'Get 1234' == resp.data resp = client.get('/decorated_bold_list_view/1234') - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_decorator_bold_list_index(): """Tests that the index route is wrapped in bold""" resp = client.get('/decorated_bold_list_view/') - eq_(b'' in resp.data, True) - eq_(b'' in resp.data, True) - eq_(b'Index', resp.data) + assert b'' in resp.data + assert b'' in resp.data + assert b'Index' == resp.data def test_decorator_bold_italics_list_get(): """Tests that the get route is wrapped in bold and italics""" resp = client.get('/decorated_bold_italics_list_view/1234/') - eq_(b'' in resp.data, True) - eq_(b'' in resp.data, True) - eq_(b'' in resp.data, True) - eq_(b'' in resp.data, True) - eq_(b'Get 1234', resp.data) + assert b'' in resp.data + assert b'' in resp.data + assert b'' in resp.data + assert b'' in resp.data + assert b'Get 1234' == resp.data resp = client.get('/decorated_bold_italics_list_view/1234') - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_decorator_bold_italics_list_index(): """Tests that the index route is wrapped in bold and italics""" resp = client.get('/decorated_bold_italics_list_view/') - eq_(b'' in resp.data, True) - eq_(b'' in resp.data, True) - eq_(b'' in resp.data, True) - eq_(b'' in resp.data, True) - eq_(b'Index', resp.data) + assert b'' in resp.data + assert b'' in resp.data + assert b'' in resp.data + assert b'' in resp.data + assert b'Index' == resp.data def test_decorator_list_member_index(): @@ -129,27 +128,27 @@ def test_decorator_list_member_index(): italics and paragraph """ resp = client.get('/decorated_list_member_view/') - eq_(b'' in resp.data, True) - eq_(b'' in resp.data, True) - eq_(b'' in resp.data, True) - eq_(b'' in resp.data, True) - eq_(b'

' not in resp.data, True) - eq_(b'

' not in resp.data, True) - eq_(b'Index', resp.data) + assert b'' in resp.data + assert b'' in resp.data + assert b'' in resp.data + assert b'' in resp.data + assert b'

' not in resp.data + assert b'

' not in resp.data + assert b'Index' == resp.data def test_decorator_list_member_get(): """Tests the ordering of decorators""" resp = client.get('/decorated_list_member_view/1234/') - eq_(b'', resp.data[:3]) - eq_(b'', resp.data[3:6]) - eq_(b'

', resp.data[6:9]) - eq_(b'

', resp.data[-12:-8]) - eq_(b'
', resp.data[-8:-4]) - eq_(b'
', resp.data[-4:]) - eq_(b'

Get 1234

', resp.data) + assert b'' == resp.data[:3] + assert b'' == resp.data[3:6] + assert b'

' == resp.data[6:9] + assert b'

' == resp.data[-12:-8] + assert b'
' == resp.data[-8:-4] + assert b'
' == resp.data[-4:] + assert b'

Get 1234

' == resp.data resp = client.get('/decorated_list_member_view/1234') - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_decorator_list_function_attributes_get(): @@ -157,16 +156,15 @@ def test_decorator_list_function_attributes_get(): Verify list of decorators with attributes modify all functions in FlaskView """ resp = client.get('/decorated_list_function_attributes_view/1234/') - eq_(b'Get 1234' in resp.data, True) - eq_(b'Get 1234', resp.data) - eq_(hasattr( - app.view_functions['DecoratedListFunctionAttributesView:get'], - 'eggs'), - True) - eq_('scrambled', - app.view_functions['DecoratedListFunctionAttributesView:get'].eggs) + assert b'Get 1234' in resp.data + assert b'Get 1234' == resp.data + assert hasattr( + app.view_functions['DecoratedListFunctionAttributesView:get'], + 'eggs') + assert 'scrambled' == \ + app.view_functions['DecoratedListFunctionAttributesView:get'].eggs resp = client.get('/decorated_list_function_attributes_view/1234') - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_decorator_list_function_attributes_index(): @@ -174,47 +172,43 @@ def test_decorator_list_function_attributes_index(): Verify list of decorators with attributes modify all functions in FlaskView """ resp = client.get('/decorated_list_function_attributes_view/') - eq_(b'Index' in resp.data, True) - eq_(b'Index', resp.data) - eq_(hasattr( - app.view_functions['DecoratedListFunctionAttributesView:index'], - 'eggs'), - True) - eq_('scrambled', - app.view_functions['DecoratedListFunctionAttributesView:index'].eggs) + assert b'Index' in resp.data + assert b'Index' == resp.data + assert hasattr( + app.view_functions['DecoratedListFunctionAttributesView:index'], + 'eggs') + assert 'scrambled' == \ + app.view_functions['DecoratedListFunctionAttributesView:index'].eggs def test_decorator_list_member_function_attributes_get(): """Verify decorator with attributes does not modify other members""" resp = client.get('/decorated_list_member_function_attributes_view/4321/') - eq_(b'Get 4321' in resp.data, True) - eq_(b'Get 4321', resp.data) - eq_( - hasattr( + assert b'Get 4321' in resp.data + assert b'Get 4321' == resp.data + assert hasattr( app.view_functions[ 'DecoratedListMemberFunctionAttributesView:get' - ], 'eggs'), - False) + ], 'eggs') is False resp = client.get('/decorated_list_member_function_attributes_view/4321') - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_decorator_list_member_function_attributes_index(): """Verify decorator with attributes modify decorated memeber functions""" resp = client.get('/decorated_list_member_function_attributes_view/') - eq_(b'Index' in resp.data, True) - eq_(b'Index', resp.data) - eq_(hasattr( + assert b'Index' in resp.data + assert b'Index' == resp.data + assert hasattr( app.view_functions[ 'DecoratedListMemberFunctionAttributesView:index' - ], 'eggs'), - True) - eq_('scrambled', + ], 'eggs') + assert 'scrambled' == \ app.view_functions[ 'DecoratedListMemberFunctionAttributesView:index' - ].eggs) + ].eggs def test_decorator_append_class_attribute_index(): resp = client.get('/decorated_append_class_attribute_view/') - eq_(b'Index (this is a test)', resp.data) + assert b'Index (this is a test)' == resp.data diff --git a/test_classful/test_default_methods.py b/test_classful/test_default_methods.py index 32459f2..8b695fe 100644 --- a/test_classful/test_default_methods.py +++ b/test_classful/test_default_methods.py @@ -1,6 +1,5 @@ from flask import Flask from .view_classes import DefaultMethodsView, NoDefaultMethodsView -from nose.tools import eq_ app = Flask('default_methods') @@ -11,14 +10,14 @@ def test_default_methods(): client = app.test_client() resp = client.get('/default-methods/foo/') - eq_(b"GET", resp.data) + assert b"GET" == resp.data resp = client.post('/default-methods/foo/') - eq_(b"POST", resp.data) + assert b"POST" == resp.data def test_no_default_methods(): client = app.test_client() resp = client.get('/no-default-methods/foo/') - eq_(b"GET", resp.data) + assert b"GET" == resp.data resp = client.post('/no-default-methods/foo/') - eq_(resp.status_code, 405) + assert resp.status_code == 405 diff --git a/test_classful/test_endpoints.py b/test_classful/test_endpoints.py index 1e7b894..28d362c 100644 --- a/test_classful/test_endpoints.py +++ b/test_classful/test_endpoints.py @@ -1,6 +1,5 @@ from flask import Flask, url_for from .view_classes import BasicView, IndexView, RouteBaseView, VarBaseView -from nose.tools import eq_ app = Flask("common") BasicView.register(app) @@ -14,40 +13,40 @@ def test_index_url(): with app.test_request_context(): url = url_for("IndexView:index") - eq_("/", url) + assert "/" == url def test_basic_index_url(): with app.test_request_context(): url = url_for("BasicView:index") - eq_("/basic/", url) + assert "/basic/" == url def test_custom_endpoint_url(): with app.test_request_context(): url = url_for("basic_endpoint") - eq_("/basic/endpoint/", url) + assert "/basic/endpoint/" == url def test_custom_route_base(): with app.test_request_context(): url = url_for('RouteBaseView:index') - eq_("/base-routed/", url) + assert "/base-routed/" == url def test_variable_route_popped_base(): with app.test_request_context(): url = url_for('VarBaseView:index', route='bar') - eq_('/var-base-route/bar/', url) + assert '/var-base-route/bar/' == url def test_variable_route_base(): with app.test_request_context(): url = url_for('VarBaseView:with_base_arg', route='bar') - eq_('/var-base-route/bar/with_base_arg/', url) + assert '/var-base-route/bar/with_base_arg/' == url def test_variable_route_base_with_local_route_var(): client = app.test_client() resp = client.get('/var-base-route/bar/local/baz') - eq_(resp.data, b"bar baz") + assert resp.data == b"bar baz" diff --git a/test_classful/test_excluded_methods.py b/test_classful/test_excluded_methods.py index 9dbada2..991a04f 100644 --- a/test_classful/test_excluded_methods.py +++ b/test_classful/test_excluded_methods.py @@ -1,7 +1,6 @@ from flask import Flask from flask_classful import FlaskView -from nose.tools import eq_ class NormalMethodsView(FlaskView): @@ -43,16 +42,16 @@ def copy_form_data(self): def test_normal_methods_copy_form_data(): resp = client.get("/normal-methods/copy_form_data/") - eq_(b"copy form data", resp.data) + assert b"copy form data" == resp.data def test_excluded_methods_copy_form_data(): resp = client.get("/excluded-methods/copy_form_data/") - eq_(resp.status_code, 404) + assert resp.status_code == 404 def test_static_method_view(): resp = client.get("/static-method/setup/") - eq_(resp.status_code, 404) + assert resp.status_code == 404 resp = client.get("/static-method/copy_form_data/") - eq_(b"copy form data", resp.data) + assert b"copy form data" == resp.data diff --git a/test_classful/test_inheritance.py b/test_classful/test_inheritance.py index a87b7d4..50b43f3 100644 --- a/test_classful/test_inheritance.py +++ b/test_classful/test_inheritance.py @@ -1,6 +1,5 @@ from flask import Flask from .view_classes import InheritanceView, DecoratedInheritanceView -from nose.tools import eq_ app = Flask('inheritance') InheritanceView.register(app) @@ -11,43 +10,43 @@ def test_index(): resp = client.get('/inheritance/') - eq_(b"Index", resp.data) + assert b"Index" == resp.data def test_override(): resp = client.get("/inheritance/1234/") - eq_(b"Inheritance Get 1234", resp.data) + assert b"Inheritance Get 1234" == resp.data resp = client.get("/inheritance/1234") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_inherited(): resp = client.post('/inheritance/') - eq_(b"Post", resp.data) + assert b"Post" == resp.data def test_with_route(): resp = client.get("/inheritance/with_route") - eq_(b"Inheritance with route", resp.data) + assert b"Inheritance with route" == resp.data def test_override_with_route(): resp = client.delete("/inheritance/1234/delete") - eq_(b"Inheritance Delete 1234", resp.data) + assert b"Inheritance Delete 1234" == resp.data def test_inherited_base_route(): resp = client.get("/inheritance/routed/") - eq_(b"Routed Method", resp.data) + assert b"Routed Method" == resp.data def test_decorated_inherited_mixitup(): resp = client.get("/decorated-inheritance/mixitup/") - eq_(b"Mix It Up", resp.data) + assert b"Mix It Up" == resp.data def test_decorated_inheritance_get(): resp = client.get("/decorated-inheritance/1234/") - eq_(b"Decorated Inheritance Get 1234", resp.data) + assert b"Decorated Inheritance Get 1234" == resp.data resp = client.get("/decorated-inheritance/1234") - eq_(resp.status_code, 308) + assert resp.status_code == 308 diff --git a/test_classful/test_init_argument.py b/test_classful/test_init_argument.py index c84145e..785683d 100644 --- a/test_classful/test_init_argument.py +++ b/test_classful/test_init_argument.py @@ -1,6 +1,5 @@ from flask import Flask from .view_classes import WithInitArgument, WithoutInitArgument -from nose.tools import eq_ import json app = Flask("init_argument") @@ -12,11 +11,11 @@ def test_init_argument_used(): resp = client.get("/with_init_argument/") - eq_("fistro de la praderarrr", json.loads(resp.data.decode('utf-8'))["init_argument"]) - eq_(resp.status_code, 200) + assert "fistro de la praderarrr" == json.loads(resp.data.decode('utf-8'))["init_argument"] + assert resp.status_code == 200 def test_init_argument_not_used(): resp = client.get("/without_init_argument/") - eq_("not sent", json.loads(resp.data.decode('utf-8'))["init_argument"]) - eq_(resp.status_code, 200) + assert "not sent" == json.loads(resp.data.decode('utf-8'))["init_argument"] + assert resp.status_code == 200 diff --git a/test_classful/test_inspect_args.py b/test_classful/test_inspect_args.py index 4bb01db..ce1aafe 100644 --- a/test_classful/test_inspect_args.py +++ b/test_classful/test_inspect_args.py @@ -1,8 +1,9 @@ import sys from flask import Flask from .view_classes import InspectArgsView, NoInspectArgsView, InspectArgsFalseView -from nose.tools import eq_, raises from flask_classful import DecoratorCompatibilityError +from pytest import raises + _py2 = sys.version_info[0] == 2 @@ -19,18 +20,18 @@ def test_inspect_args(): if _py2: expected = b"foo unicode(123) unicode(456) int(678)" - eq_(expected, resp.data) + assert expected == resp.data resp = client.get('/inspect-args/foo/123/456') - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_no_inspect_args(): client = app.test_client() resp = client.get('/no-inspect-args/foo/', query_string={'arg1': 123, 'arg2': 456}) - eq_(b"foo int(123) int(456) int(678)", resp.data) + assert b"foo int(123) int(456) int(678)" == resp.data -@raises(DecoratorCompatibilityError) def test_inspect_args_error(): - InspectArgsFalseView.register(app) + with raises(DecoratorCompatibilityError): + InspectArgsFalseView.register(app) diff --git a/test_classful/test_method_dashified.py b/test_classful/test_method_dashified.py index 240ce12..3dfbeab 100644 --- a/test_classful/test_method_dashified.py +++ b/test_classful/test_method_dashified.py @@ -1,6 +1,5 @@ from flask import Flask from flask_classful import FlaskView -from nose.tools import eq_ class DashifiedDefaultView(FlaskView): @@ -31,21 +30,21 @@ def yet_another_route(self): def test_original_method_dashifield(): - eq_(False, DashifiedDefaultView.method_dashified) - eq_(True, DashifiedAttributeView.method_dashified) - eq_(True, DashifiedAttributeOverrideView.method_dashified) + assert False == DashifiedDefaultView.method_dashified + assert True == DashifiedAttributeView.method_dashified + assert True == DashifiedAttributeOverrideView.method_dashified def test_some_route(): resp = client.get('/dashified-default/some-route/') - eq_(b"some route", resp.data) + assert b"some route" == resp.data def test_another_route(): resp = client.get('/dashified-attribute/another-route/') - eq_(b"another route", resp.data) + assert b"another route" == resp.data def test_yet_another_route(): resp = client.get('/dashified-attribute-override/yet_another_route/') - eq_(b"yet another route", resp.data) + assert b"yet another route" == resp.data diff --git a/test_classful/test_register.py b/test_classful/test_register.py index b20147f..b9ac5d7 100644 --- a/test_classful/test_register.py +++ b/test_classful/test_register.py @@ -1,6 +1,7 @@ from flask import Flask, request -from flask_classful import get_interesting_members, FlaskView -from nose.tools import eq_, raises +from flask_classful import FlaskView +from pytest import raises + class BaseClass(): def put(self): @@ -17,18 +18,19 @@ def put(self): app = Flask('register') ChildClassView.register(app, base_class=BaseClass) -@raises(TypeError) + def test_register_is_not_correct(): - FlaskView.register(app) + with raises(TypeError): + FlaskView.register(app) def test_child_class(): """It can use method of child class normally""" client = app.test_client() resp = client.post('/child-class/') - eq_(b"POST", resp.data) + assert b"POST" == resp.data def test_base_class(): """It filter out the method has in base class""" client = app.test_client() resp = client.put('/child-class/') - eq_(resp.status_code, 405) + assert resp.status_code == 405 diff --git a/test_classful/test_representations.py b/test_classful/test_representations.py index c2dd4a8..cd59db9 100644 --- a/test_classful/test_representations.py +++ b/test_classful/test_representations.py @@ -1,7 +1,6 @@ from flask import Flask, make_response, redirect, request from flask_classful import FlaskView import json -from nose.tools import eq_, ok_ def output_json(data, code, headers=None): @@ -113,49 +112,49 @@ def post(self): def test_index_representation(): resp = client.get("/representation/", headers=input_headers) - eq_(json.dumps([response_1, response_2]), resp.data.decode('ascii')) + assert json.dumps([response_1, response_2]) == resp.data.decode('ascii') def test_get_representation(): resp = client.get("/representation/1/", headers=input_headers) - eq_(json.dumps(response_get), resp.data.decode('ascii')) + assert json.dumps(response_get) == resp.data.decode('ascii') resp = client.get("/representation/1") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_post_representation(): resp = client.post("/representation/", headers=input_headers, data=json.dumps(input_data)) - eq_(resp.status_code, 404, 'should return 404 status code') - eq_(resp.headers['say'], 'hello') - eq_(json.dumps(response_post), resp.data.decode('ascii')) + assert resp.status_code, 404 == 'should return 404 status code' + assert resp.headers['say'] == 'hello' + assert json.dumps(response_post) == resp.data.decode('ascii') def test_put_representation(): resp = client.put("/representation/1/", headers=input_headers, data=json.dumps(input_data)) - eq_(resp.status_code, 403, 'should return 403 status code') - eq_(json.dumps(response_put), resp.data.decode('ascii')) + assert resp.status_code, 403 == 'should return 403 status code' + assert json.dumps(response_put) == resp.data.decode('ascii') resp = client.put("/representation/1", headers=input_headers, data=json.dumps(input_data)) - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_delete_representation(): resp = client.delete("/representation/1/", headers=input_headers) - eq_(json.dumps(response_delete), resp.data.decode('ascii')) + assert json.dumps(response_delete) == resp.data.decode('ascii') resp = client.delete("/representation/1") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_skip_representation_matching_if_response_is_returned(): resp = client.get("/representation/redirect/") - eq_(resp.status_code, 302) - eq_(resp.location, "http://google.com") + assert resp.status_code == 302 + assert resp.location == "http://google.com" def test_representations_no_match_return_string(): @@ -163,9 +162,9 @@ def test_representations_no_match_return_string(): resp = client.get("/representation/mirror/", query_string={'q': 'foobar'}, headers={'Accept': 'foo/bar'}) - eq_(resp.data, b'foobar') - eq_(resp.headers['Content-Type'], 'foo/bar') - eq_(resp.status_code, 201) + assert resp.data == b'foobar' + assert resp.headers['Content-Type'] == 'foo/bar' + assert resp.status_code == 201 def test_default_representation(): @@ -175,10 +174,10 @@ def test_default_representation(): headers={'Accept': 'foo/bar', 'Content-Type': 'application/json'}) - eq_(resp.status_code, 201) - eq_(resp.headers['say'], 'hello') - eq_(resp.data, b'{"foo": "bar"}') - eq_(resp.headers['Content-Type'], 'flask-classful/default') + assert resp.status_code == 201 + assert resp.headers['say'] == 'hello' + assert resp.data == b'{"foo": "bar"}' + assert resp.headers['Content-Type'] == 'flask-classful/default' def test_representation_with_default(): @@ -187,7 +186,7 @@ def test_representation_with_default(): data=json.dumps({'foo': 'bar'}), headers=input_headers) - eq_(resp.status_code, 201) - eq_(resp.headers['say'], 'hello') - eq_(resp.data, b'{"foo": "bar"}') - eq_(resp.headers['Content-Type'], 'application/json') + assert resp.status_code == 201 + assert resp.headers['say'] == 'hello' + assert resp.data == b'{"foo": "bar"}' + assert resp.headers['Content-Type'] == 'application/json' diff --git a/test_classful/test_route_base.py b/test_classful/test_route_base.py index d09b96c..b540c5b 100644 --- a/test_classful/test_route_base.py +++ b/test_classful/test_route_base.py @@ -1,6 +1,5 @@ from flask import Flask from .view_classes import RouteBaseView, RouteBaseViewIsNotLatest -from nose.tools import eq_ app = Flask('route_base') RouteBaseView.register(app, route_base="/rb_test2/") @@ -10,10 +9,10 @@ def test_route_base_override(): client = app.test_client() resp = client.get('/rb_test2/') - eq_(b"Index", resp.data) + assert b"Index" == resp.data def test_route_base_no_view(): """Use class name as route""" client = app.test_client() resp = client.get('/route-base-view-is-not-latest/') - eq_(b"Index", resp.data) + assert b"Index" == resp.data diff --git a/test_classful/test_route_prefix.py b/test_classful/test_route_prefix.py index 03fe399..f4dd361 100644 --- a/test_classful/test_route_prefix.py +++ b/test_classful/test_route_prefix.py @@ -1,6 +1,5 @@ from flask import Flask from .view_classes import BasicView, RoutePrefixView, RouteBaseView -from nose.tools import eq_ app = Flask('route_base') @@ -12,16 +11,16 @@ def test_route_prefix(): client = app.test_client() resp = client.get('/my_prefix/route-prefix/') - eq_(b"Index", resp.data) + assert b"Index" == resp.data def test_route_prefix_override(): client = app.test_client() resp = client.get('/prefix/basic/') - eq_(b"Index", resp.data) + assert b"Index" == resp.data def test_route_prefix_with_route_base(): client = app.test_client() resp = client.get('/prefix/base-routed/') - eq_(b"Index", resp.data) + assert b"Index" == resp.data diff --git a/test_classful/test_rule_options.py b/test_classful/test_rule_options.py index b98745f..5c09c94 100644 --- a/test_classful/test_rule_options.py +++ b/test_classful/test_rule_options.py @@ -1,78 +1,15 @@ -from .view_classes import BasicView, IndexView +from .view_classes import BasicView from flask import Flask -from nose.tools import eq_ +from unittest.mock import patch -app = Flask("rules_options") -BasicView.register(app, strict_slashes=False) -IndexView.register(app, strict_slashes=False) -client = app.test_client() +@patch('flask.Flask.add_url_rule') +def test_rule_options(rule): + app = Flask("rules_options", static_folder=None) + BasicView.register(app, strict_slashes=False) -def test_rule_options_index(): - resp = client.get("/basic/") - eq_(b"Index", resp.data) - - resp = client.get("/basic") - eq_(b"Index", resp.data) - - -def test_rule_options_get(): - resp = client.get("/basic/1234/") - eq_(resp.status_code, 404) - eq_(b"Get 1234", resp.data) - - resp = client.get("/basic/1234") - eq_(resp.status_code, 404) - eq_(b"Get 1234", resp.data) - - -def test_rule_options_put(): - resp = client.put("/basic/1234/") - eq_(resp.status_code, 403) - eq_(resp.headers['say'], 'hello') - eq_(b"Put 1234", resp.data) - - resp = client.put("/basic/1234") - eq_(resp.status_code, 403) - eq_(resp.headers['say'], 'hello') - eq_(b"Put 1234", resp.data) - - -def test_rule_options_patch(): - resp = client.patch("/basic/1234/") - eq_(b"Patch 1234", resp.data) - - resp = client.patch("/basic/1234") - eq_(b"Patch 1234", resp.data) - - -def test_rule_options_post(): - resp = client.post("/basic/") - eq_(b"Post", resp.data) - - resp = client.post("/basic") - eq_(b"Post", resp.data) - - -def test_rule_options_delete(): - resp = client.delete("/basic/1234/") - eq_(b"Delete 1234", resp.data) - - resp = client.delete("/basic/1234") - eq_(b"Delete 1234", resp.data) - -def test_rule_options_custom_method(): - resp = client.get("/basic/custom_method/") - eq_(b"Custom Method", resp.data) - - resp = client.get("/basic/custom_method") - eq_(b"Custom Method", resp.data) - - -def test_rule_options_custom_method_with_params(): - resp = client.get("/basic/custom_method_with_params/1234/abcd/") - eq_(b"Custom Method 1234 abcd", resp.data) - - resp = client.get("/basic/custom_method_with_params/1234/abcd") - eq_(b"Custom Method 1234 abcd", resp.data) + client = app.test_client() + client.get("/basic/") + for args, kwargs in rule.call_args_list: + assert kwargs.get('strict_slashes') is False, (args, kwargs) diff --git a/test_classful/test_subdomains.py b/test_classful/test_subdomains.py index 7595d64..3ead5a1 100644 --- a/test_classful/test_subdomains.py +++ b/test_classful/test_subdomains.py @@ -1,6 +1,5 @@ from flask import Flask from .view_classes import BasicView -from nose.tools import eq_ app = Flask("common") app.config["SERVER_NAME"] = "test.test" @@ -11,70 +10,70 @@ def test_index_subdomain(): resp = client.get("/basic/", base_url="http://basic.test.test") - eq_(b"Index", resp.data) + assert b"Index" == resp.data def test_get(): resp = client.get("/basic/1234/", base_url="http://basic.test.test") - eq_(b"Get 1234", resp.data) + assert b"Get 1234" == resp.data resp = client.get("/basic/1234", base_url="http://basic.test.test") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_put(): resp = client.put("/basic/1234/", base_url="http://basic.test.test") - eq_(b"Put 1234", resp.data) + assert b"Put 1234" == resp.data resp = client.put("/basic/1234", base_url="http://basic.test.test") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_patch(): resp = client.patch("/basic/1234/", base_url="http://basic.test.test") - eq_(b"Patch 1234", resp.data) + assert b"Patch 1234" == resp.data resp = client.patch("/basic/1234", base_url="http://basic.test.test") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_post(): resp = client.post("/basic/", base_url="http://basic.test.test") - eq_(b"Post", resp.data) + assert b"Post" == resp.data def test_delete(): resp = client.delete("/basic/1234/", base_url="http://basic.test.test") - eq_(b"Delete 1234", resp.data) + assert b"Delete 1234" == resp.data resp = client.delete("/basic/1234", base_url="http://basic.test.test") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_custom_method(): resp = client.get("/basic/custom_method/", base_url="http://basic.test.test") - eq_(b"Custom Method", resp.data) + assert b"Custom Method" == resp.data def test_custom_method_with_params(): resp = client.get("/basic/custom_method_with_params/1234/abcd/", base_url="http://basic.test.test") - eq_(b"Custom Method 1234 abcd", resp.data) + assert b"Custom Method 1234 abcd" == resp.data resp = client.get("/basic/custom_method_with_params/1234/abcd", base_url="http://basic.test.test") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_routed_method(): resp = client.get("/basic/routed/", base_url="http://basic.test.test") - eq_(b"Routed Method", resp.data) + assert b"Routed Method" == resp.data def test_multi_routed_method(): resp = client.get("/basic/route1/", base_url="http://basic.test.test") - eq_(b"Multi Routed Method", resp.data) + assert b"Multi Routed Method" == resp.data resp = client.get("/basic/route2/", base_url="http://basic.test.test") - eq_(b"Multi Routed Method", resp.data) + assert b"Multi Routed Method" == resp.data def test_no_slash(): resp = client.get("/basic/noslash", base_url="http://basic.test.test") - eq_(b"No Slash Method", resp.data) + assert b"No Slash Method" == resp.data diff --git a/test_classful/test_trailing_slash.py b/test_classful/test_trailing_slash.py index ad5185b..db8e259 100644 --- a/test_classful/test_trailing_slash.py +++ b/test_classful/test_trailing_slash.py @@ -8,7 +8,6 @@ EnabledNoTrailingSlashView, IndexView ) -from nose.tools import eq_ app = Flask('trailing_slash') BasicView.register(app, trailing_slash=False) @@ -24,184 +23,184 @@ def test_index(): resp = client.get("/basic") - eq_(b"Index", resp.data) + assert b"Index" == resp.data resp = client.get("/basic/") - eq_(resp.status_code, 404) + assert resp.status_code == 404 def test_get(): resp = client.get("/basic/1234") - eq_(b"Get 1234", resp.data) + assert b"Get 1234" == resp.data resp = client.get("/basic/1234/") - eq_(resp.status_code, 404) + assert resp.status_code == 404 def test_put(): resp = client.put("/basic/1234") - eq_(b"Put 1234", resp.data) + assert b"Put 1234" == resp.data resp = client.put("/basic/1234/") - eq_(resp.status_code, 404) + assert resp.status_code == 404 def test_patch(): resp = client.patch("/basic/1234") - eq_(b"Patch 1234", resp.data) + assert b"Patch 1234" == resp.data resp = client.patch("/basic/1234/") - eq_(resp.status_code, 404) + assert resp.status_code == 404 def test_post(): resp = client.post("/basic") - eq_(b"Post", resp.data) + assert b"Post" == resp.data resp = client.post("/basic/") - eq_(resp.status_code, 404) + assert resp.status_code == 404 def test_delete(): resp = client.delete("/basic/1234") - eq_(b"Delete 1234", resp.data) + assert b"Delete 1234" == resp.data resp = client.delete("/basic/1234/") - eq_(resp.status_code, 404) + assert resp.status_code == 404 def test_custom_method(): resp = client.get("/basic/custom_method") - eq_(b"Custom Method", resp.data) + assert b"Custom Method" == resp.data resp = client.get("/basic/custom_method/") - eq_(resp.status_code, 404) + assert resp.status_code == 404 def test_custom_method_with_params(): resp = client.get("/basic/custom_method_with_params/1234/abcd") - eq_(b"Custom Method 1234 abcd", resp.data) + assert b"Custom Method 1234 abcd" == resp.data resp = client.get("/basic/custom_method_with_params/1234/abcd/") - eq_(resp.status_code, 404) + assert resp.status_code == 404 def test_routed_method(): resp = client.get("/basic/routed/") - eq_(b"Routed Method", resp.data) + assert b"Routed Method" == resp.data resp = client.get("/basic/routed") - eq_(resp.status_code, 308) + assert resp.status_code == 308 # TrailingSlashView def test_trailing_index(): resp = client.get("/trailing") - eq_(b"Index", resp.data) + assert b"Index" == resp.data resp = client.get("/trailing/") - eq_(resp.status_code, 404) + assert resp.status_code == 404 def test_trailing_get(): resp = client.get("/trailing/1234") - eq_(b"Get 1234", resp.data) + assert b"Get 1234" == resp.data resp = client.get("/trailing/1234/") - eq_(resp.status_code, 404) + assert resp.status_code == 404 def test_trailing_put(): resp = client.put("/trailing/1234") - eq_(b"Put 1234", resp.data) + assert b"Put 1234" == resp.data resp = client.put("/trailing/1234/") - eq_(resp.status_code, 404) + assert resp.status_code == 404 def test_trailing_patch(): resp = client.patch("/trailing/1234") - eq_(b"Patch 1234", resp.data) + assert b"Patch 1234" == resp.data resp = client.patch("/trailing/1234/") - eq_(resp.status_code, 404) + assert resp.status_code == 404 def test_trailing_post(): resp = client.post("/trailing") - eq_(b"Post", resp.data) + assert b"Post" == resp.data resp = client.post("/trailing/") - eq_(resp.status_code, 404) + assert resp.status_code == 404 def test_trailing_delete(): resp = client.delete("/trailing/1234") - eq_(b"Delete 1234", resp.data) + assert b"Delete 1234" == resp.data resp = client.delete("/trailing/1234/") - eq_(resp.status_code, 404) + assert resp.status_code == 404 def test_trailing_custom_method(): resp = client.get("/trailing/custom_method") - eq_(b"Custom Method", resp.data) + assert b"Custom Method" == resp.data resp = client.get("/trailing/custom_method/") - eq_(resp.status_code, 404) + assert resp.status_code == 404 def test_trailing_custom_method_with_params(): resp = client.get("/trailing/custom_method_with_params/1234/abcd") - eq_(b"Custom Method 1234 abcd", resp.data) + assert b"Custom Method 1234 abcd" == resp.data resp = client.get("/trailing/custom_method_with_params/1234/abcd/") - eq_(resp.status_code, 404) + assert resp.status_code == 404 def test_trailing_routed_method(): resp = client.get("/trailing/routed/") - eq_(b"Routed Method", resp.data) + assert b"Routed Method" == resp.data resp = client.get("/trailing/routed") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_trailing_routed_method2(): resp = client.get("/trailing/routed2") - eq_(b"Routed Method 2", resp.data) + assert b"Routed Method 2" == resp.data resp = client.get("/trailing/routed2/") - eq_(resp.status_code, 404) + assert resp.status_code == 404 # InheritedTrailingSlashView def test_inherited_trailing_slash(): resp = client.get("/inherited/trailing") - eq_(b"Index", resp.data) + assert b"Index" == resp.data resp = client.get("/inherited/trailing/") - eq_(resp.status_code, 404) + assert resp.status_code == 404 # OverrideInheritedTrailingSlashView def test_inherited_trailing_slash_override(): resp = client.get("/override/trailing/") - eq_(b"Index", resp.data) + assert b"Index" == resp.data resp = client.get("/override/trailing") - eq_(resp.status_code, 308) + assert resp.status_code == 308 # EnabledHasTrailingSlashView def test_enabled_has_trailing_slash_view_index(): resp = client.get("/enabled-trailing-yes/") - eq_(b"Index", resp.data) + assert b"Index" == resp.data resp = client.get("/enabled-trailing-yes") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_enabled_has_trailing_slash_view_get(): resp = client.get("/enabled-trailing-yes/1234/") - eq_(b"Get 1234", resp.data) + assert b"Get 1234" == resp.data resp = client.get("/enabled-trailing-yes/1234") - eq_(resp.status_code, 308) + assert resp.status_code == 308 # EnabledNoTrailingSlashView def test_enabled_no_trailing_slash_view_index(): resp = client.get("/enabled-trailing-no/") - eq_(b"Index", resp.data) + assert b"Index" == resp.data resp = client.get("/enabled-trailing-no") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_enabled_no_trailing_slash_view_get(): resp = client.get("/enabled-trailing-no/1234/") - eq_(b"Get 1234", resp.data) + assert b"Get 1234" == resp.data resp = client.get("/enabled-trailing-no/1234") - eq_(resp.status_code, 308) + assert resp.status_code == 308 # IndexView route_base '/' and trailing slash False def test_index_trailing_slash(): resp = client.get("/") - eq_(b"Index", resp.data) + assert b"Index" == resp.data resp = client.get("") - eq_(resp.status_code, 308) + assert resp.status_code == 308 diff --git a/test_classful/test_view_wrappers.py b/test_classful/test_view_wrappers.py index 73cbf5e..9271bd7 100644 --- a/test_classful/test_view_wrappers.py +++ b/test_classful/test_view_wrappers.py @@ -8,7 +8,6 @@ BeforeRequestReturnsView, BeforeViewReturnsView ) -from nose.tools import eq_ app = Flask("wrappers") BeforeRequestView.register(app) @@ -24,39 +23,39 @@ def test_before_request(): resp = client.get("/before-request/") - eq_(b"Before Request", resp.data) + assert b"Before Request" == resp.data def test_before_view(): resp = client.get("/before-view/") - eq_(b"Before View", resp.data) + assert b"Before View" == resp.data def test_after_view(): resp = client.get("/after-view/") - eq_(b"After View", resp.data) + assert b"After View" == resp.data def test_after_request(): resp = client.get("/after-request/") - eq_(b"After Request", resp.data) + assert b"After Request" == resp.data def test_decorated_view(): resp = client.get("/decorated/") - eq_(b"Index", resp.data) + assert b"Index" == resp.data resp = client.get("/decorated/1234/") - eq_(b"Get 1234", resp.data) + assert b"Get 1234" == resp.data resp = client.get("/decorated/1234") - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_before_request_returns(): resp = client.get("/before-request-returns/") - eq_(b"BEFORE", resp.data) + assert b"BEFORE" == resp.data def test_before_view_returns(): resp = client.get("/before-view-returns/") - eq_(b"BEFORE", resp.data) + assert b"BEFORE" == resp.data diff --git a/test_classful_py3/test_type_hints.py b/test_classful_py3/test_type_hints.py index 3974dc4..999c233 100644 --- a/test_classful_py3/test_type_hints.py +++ b/test_classful_py3/test_type_hints.py @@ -1,7 +1,6 @@ from uuid import UUID from flask import Flask from flask_classful import FlaskView, route -from nose.tools import eq_ # python3 only @@ -34,23 +33,23 @@ def uuid(self, arg: UUID): def test_index(): resp = client.get('/typing/') - eq_(b"Index", resp.data) + assert b"Index" == resp.data resp = client.get('/typing') - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_post(): resp = client.post('/typing/123') - eq_(b"Post", resp.data) + assert b"Post" == resp.data resp = client.post('/typing/123/') - eq_(resp.status_code, 405) + assert resp.status_code == 405 def test_patch(): resp = client.patch('/typing/123/') - eq_(b"Patch", resp.data) + assert b"Patch" == resp.data resp = client.patch('/typing/123') - eq_(resp.status_code, 308) + assert resp.status_code == 308 def test_url_converter(): @@ -62,7 +61,7 @@ def test_url_converter(): url = '/typing/{}/{}/' resp = client.get(url.format(type_, wrong_var)) # should not match the endpoint if url variable type mismatches - eq_(resp.status_code, 404) + assert resp.status_code == 404 resp = client.get(url.format(type_, correct_var)) - eq_(resp.status_code, 200) - eq_(bytes(correct_var, 'utf-8'), resp.data) + assert resp.status_code == 200 + assert bytes(correct_var, 'utf-8') == resp.data diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 823ce00..0000000 --- a/tox.ini +++ /dev/null @@ -1,5 +0,0 @@ -[tox] -envlist = python2.6,python2.7,python3.3 -[testenv] -deps=nose -commands=nosetests