Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop support for Python 3.4 #243

Merged
merged 1 commit into from Jul 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 4 additions & 6 deletions .travis.yml
Expand Up @@ -14,16 +14,14 @@ env:
python:
- "3.6"
- "3.5"
- "3.4"
- "2.7"
- "pypy"

install:
- travis_retry pip install -U .
- if [[ $TRAVIS_PYTHON_VERSION == 2* || $TRAVIS_PYTHON_VERSION == 3.4* || $TRAVIS_PYTHON_VERSION == 'pypy' || $TRAVIS_PYTHON_VERSION == '3.3' ]]; then travis_retry pip install -r dev-requirements.txt; fi
# NOTE: aiohttp supports python>=3.5
- if [[ $TRAVIS_PYTHON_VERSION == 3* && $TRAVIS_PYTHON_VERSION != 3.4* ]] ; then travis_retry pip install -r dev-requirements-py3.txt; fi
- travis_retry pip install -U marshmallow"$MARSHMALLOW_VERSION" --pre
- travis_retry pip install -U .
- if [[ $TRAVIS_PYTHON_VERSION == 2* || $TRAVIS_PYTHON_VERSION == 'pypy' ]]; then travis_retry pip install -r dev-requirements.txt; fi
- if [[ $TRAVIS_PYTHON_VERSION == 3* ]] ; then travis_retry pip install -r dev-requirements-py3.txt; fi
- travis_retry pip install -U marshmallow"$MARSHMALLOW_VERSION" --pre


script: invoke test
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Expand Up @@ -10,6 +10,12 @@ Bug fixes:
``webargs.asyncparser`` to fix compatibility with Python 3.7
(:issue:`240`). Thanks :user:`Reskov` for the catch and patch.


Other changes:

* *Backwards-incompatible*: Drop support for Python 3.4 (:issue:`243`). Python 2.7 and
>=3.5 are supported.

3.0.2 (2018-07-05)
******************

Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.rst
Expand Up @@ -82,7 +82,7 @@ To run all tests: ::

$ invoke test

To run tests on Python 2.7, 3.4, 3.5, and 3.6 virtual environments (must have each interpreter installed): ::
To run tests on Python 2.7, 3.5, 3.6, and 3.7 virtual environments (must have each interpreter installed): ::

$ tox

Expand Down
2 changes: 1 addition & 1 deletion README.rst
Expand Up @@ -46,7 +46,7 @@ Install

pip install -U webargs

webargs supports Python >= 2.7 or >= 3.4.
webargs supports Python >= 2.7 or >= 3.5.


Documentation
Expand Down
4 changes: 2 additions & 2 deletions docs/install.rst
@@ -1,7 +1,7 @@
Install
=======

**webargs** requires Python >= 2.7 or >= 3.4. It depends on `marshmallow <https://marshmallow.readthedocs.io/en/latest/>`_ >= 2.7.0.
**webargs** requires Python >= 2.7 or >= 3.5. It depends on `marshmallow <https://marshmallow.readthedocs.io/en/latest/>`_ >= 2.7.0.

From the PyPI
-------------
Expand All @@ -10,7 +10,7 @@ To install the latest version from the PyPI:

::

pip install -U webargs
$ pip install -U webargs


Get the Bleeding Edge Version
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Expand Up @@ -4,4 +4,4 @@ universal = 1
[flake8]
ignore = E127,E128,E265,E302,N803,N804,N806,E731,E402,E266,E305
max-line-length = 100
exclude = .git,.ropeproject,.tox,docs,.git,setup.py,tests/compat.py,build,.direnv
exclude = .git,.ropeproject,.tox,build,.direnv,__pycache__
1 change: 0 additions & 1 deletion setup.py
Expand Up @@ -54,7 +54,6 @@ def read(fname):
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: Implementation :: CPython',
Expand Down
17 changes: 6 additions & 11 deletions tasks.py
Expand Up @@ -10,15 +10,14 @@

@task
def test(ctx, coverage=False, browse=False):
flake(ctx)
import pytest
flake(ctx)
args = []
if coverage:
args.extend(['--cov=webargs', '--cov-report=term', '--cov-report=html'])

ignores = []
# aiohttp support python>=3.5
if sys.version_info < (3, 5):
if sys.version_info < (3, ):
ignores += [
os.path.join('tests', 'test_aiohttpparser.py'),
os.path.join('tests', 'test_aiohttpparser_async_functions.py'),
Expand All @@ -36,21 +35,17 @@ def flake(ctx):
"""Run flake8 on codebase."""
cmd = 'flake8 .'
excludes = []
if sys.version_info < (3, 4, 1):
excludes = [
if sys.version_info < (3, ):
excludes += [
os.path.join('webargs', 'async_decorators.py'),
os.path.join('tests', 'test_aiohttpparser_async_functions.py'),
os.path.join('tests', 'apps', 'aiohttp_app.py'),
os.path.join('tests', 'test_aiohttparser.py'),
os.path.join('webargs', 'asyncparser.py'),
os.path.join('webargs', 'async_decorators34.py'),
os.path.join('webargs', 'aiohttpparser.py'),
os.path.join('examples', 'annotations_example.py'),
'build',
]
if sys.version_info < (3, 5, 0):
excludes += [
os.path.join('webargs', 'async_decorators.py'),
os.path.join('tests', 'test_aiohttpparser_async_functions.py'),
]
if excludes:
cmd += ' --exclude={0}'.format(','.join(excludes))
ctx.run(cmd, echo=True)
Expand Down
7 changes: 4 additions & 3 deletions tests/compat.py
@@ -1,13 +1,14 @@
# -*- coding: utf-8 -*-
# flake8: noqa
import sys

PY2 = int(sys.version[0]) == 2

if PY2:
text_type = unicode # flake8: noqa
text_type = unicode
binary_type = str
string_types = (str, unicode) # flake8: noqa
basestring = basestring # flake8: noqa
string_types = (str, unicode)
basestring = basestring
else:
text_type = str
binary_type = bytes
Expand Down
2 changes: 1 addition & 1 deletion tox.ini
@@ -1,5 +1,5 @@
[tox]
envlist =py27,py34,py35,py36,py37
envlist =py27,py35,py36,py37
[testenv]
deps=
-rdev-requirements.txt
Expand Down
67 changes: 0 additions & 67 deletions webargs/async_decorators.py

This file was deleted.

44 changes: 0 additions & 44 deletions webargs/async_decorators34.py

This file was deleted.

75 changes: 64 additions & 11 deletions webargs/asyncparser.py
@@ -1,21 +1,15 @@
# -*- coding: utf-8 -*-
"""Asynchronous request parser. Compatible with Python>=3.4."""
"""Asynchronous request parser. Compatible with Python>=3.5."""
import asyncio
import sys
import collections
import functools
import inspect

import marshmallow as ma
from marshmallow.compat import iteritems
from marshmallow.utils import missing

from webargs import core

PY_34 = sys.version_info < (3, 5)

if PY_34:
from webargs.async_decorators34 import _use_args
else:
from webargs.async_decorators import _use_args

class AsyncParser(core.Parser):
"""Asynchronous variant of `webargs.core.Parser`, where parsing methods may be
Expand All @@ -40,7 +34,7 @@ def _parse_request(self, schema, req, locations):
else:
argdict = schema.fields
parsed = {}
for argname, field_obj in iteritems(argdict):
for argname, field_obj in argdict.items():
if core.MARSHMALLOW_VERSION_INFO[0] < 3:
parsed_value = yield from self.parse_arg(argname, field_obj, req, locations)
# If load_from is specified on the field, try to parse from that key
Expand Down Expand Up @@ -80,7 +74,66 @@ def parse(self, argmap, req=None, locations=None, validate=None, force_all=False
core.fill_in_missing_args(data, schema)
return data

use_args = _use_args
def use_args(self, argmap, req=None, locations=None, as_kwargs=False, validate=None):
"""Decorator that injects parsed arguments into a view function or method.

Receives the same arguments as `webargs.core.Parser.use_args`.
"""
locations = locations or self.locations
request_obj = req
# Optimization: If argmap is passed as a dictionary, we only need
# to generate a Schema once
if isinstance(argmap, collections.Mapping):
argmap = core.argmap2schema(argmap)()

def decorator(func):
req_ = request_obj

if inspect.iscoroutinefunction(func):
@functools.wraps(func)
async def wrapper(*args, **kwargs):
req_obj = req_

# if as_kwargs is passed, must include all args
force_all = as_kwargs

if not req_obj:
req_obj = self.get_request_from_view_args(func, args, kwargs)
# NOTE: At this point, argmap may be a Schema, callable, or dict
parsed_args = await self.parse(argmap,
req=req_obj, locations=locations,
validate=validate, force_all=force_all)
if as_kwargs:
kwargs.update(parsed_args)
return await func(*args, **kwargs)
else:
# Add parsed_args after other positional arguments
new_args = args + (parsed_args, )
return await func(*new_args, **kwargs)
else:
@functools.wraps(func)
def wrapper(*args, **kwargs):
req_obj = req_

# if as_kwargs is passed, must include all args
force_all = as_kwargs

if not req_obj:
req_obj = self.get_request_from_view_args(func, args, kwargs)
# NOTE: At this point, argmap may be a Schema, callable, or dict
parsed_args = yield from self.parse(argmap,
req=req_obj, locations=locations,
validate=validate, force_all=force_all)
if as_kwargs:
kwargs.update(parsed_args)
return func(*args, **kwargs)
else:
# Add parsed_args after other positional arguments
new_args = args + (parsed_args, )
return func(*new_args, **kwargs)
wrapper.__wrapped__ = func
return wrapper
return decorator

def use_kwargs(self, *args, **kwargs):
"""Decorator that injects parsed arguments into a view function or method.
Expand Down