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

Extend test suite and remove deprecated code #133

Merged
merged 36 commits into from
Feb 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
1b8b9fa
#45: features.rst, add 'HTTP Request' section
jeff1evesque Jul 21, 2016
440c793
#45: features.rst, provide alternative, self contained example
jeff1evesque Jul 21, 2016
b2366f4
#45: features.rst, remove dummy data
jeff1evesque Jul 21, 2016
8f2f2c5
#45: features.rst, add newline at start of code example
jeff1evesque Jul 21, 2016
2b9c745
#45: features.rst, reduce example syntax
jeff1evesque Jul 21, 2016
5a65431
fix conflicts
northernSage Dec 14, 2020
203f01b
Merge branch 'jeff1evesque-feature-45'
northernSage Dec 14, 2020
3a8050f
fix conflicts
northernSage Feb 10, 2021
08331f5
update coverage run instructions to use pytest-cov
northernSage Feb 10, 2021
5e00acb
add changelog entry
northernSage Feb 10, 2021
f7adf17
use pytest command instead of py.test
northernSage Feb 10, 2021
4117810
move deprecation decorator to new _internal.py module
northernSage Feb 10, 2021
0f98eac
update pre-commit hooks
northernSage Feb 10, 2021
587adc9
move LiveServer class from fixtures.py to a separate module
northernSage Feb 10, 2021
b516d0a
move helper functions to _internal.py
northernSage Feb 10, 2021
831910a
update tox.ini and coverage instructions to include imports
northernSage Feb 10, 2021
c4c3191
ommit unused port variable
northernSage Feb 11, 2021
1323b9e
move json response tests to separate module
northernSage Feb 11, 2021
dcc32b6
remove philosophical contemplation of existence
northernSage Feb 11, 2021
2745316
remove deprecation test
northernSage Feb 11, 2021
fc79de0
remove test for deprecated method
northernSage Feb 11, 2021
f20fc85
remove deprecated LiveServer.url
northernSage Feb 11, 2021
ef07a17
update coverage instructions to account for multiprocessing
Feb 16, 2021
1fa0a02
add .swp files to gitignore
northernSage Feb 16, 2021
b4d8b11
add new tests for fixtures and deprecation decorator
northernSage Feb 16, 2021
86e92b5
add test for possible exception in liveserver._stop_cleanly()
northernSage Feb 17, 2021
21a3c1d
remove pytest-cov
northernSage Feb 18, 2021
d9b5d5d
update for werkzeug 2.0.0
northernSage Feb 19, 2021
2ad6507
fix deprecation warning
northernSage Feb 19, 2021
4f69b91
remove old py2 code
northernSage Feb 20, 2021
602884a
remove JSONResponse.json
northernSage Feb 20, 2021
e58a893
adjust test for response overwriting
northernSage Feb 21, 2021
e510985
skip coverage on old compat function
northernSage Feb 21, 2021
1f31a40
update docs
northernSage Feb 23, 2021
7a428aa
update changelog
northernSage Feb 23, 2021
ef09718
fix doc typos
northernSage Feb 23, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
build
sdist
.vscode
*.swp
__pycache__/

# virtualenv
Expand Down
10 changes: 7 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
rev: v3.4.0
hooks:
- id: check-byte-order-marker
- id: trailing-whitespace
Expand All @@ -9,7 +9,7 @@ repos:
args: [--remove]
- id: check-yaml
- repo: https://github.com/asottile/reorder_python_imports
rev: v2.3.5
rev: v2.4.0
hooks:
- id: reorder-python-imports
args: ['--application-directories=.:src', --py3-plus]
Expand All @@ -18,7 +18,7 @@ repos:
hooks:
- id: black
- repo: https://gitlab.com/pycqa/flake8
rev: 3.8.3
rev: 3.8.4
hooks:
- id: flake8
additional_dependencies: [flake8-bugbear]
Expand All @@ -30,3 +30,7 @@ repos:
files: ^(HOWTORELEASE.rst|README.rst)$
language: python
additional_dependencies: [pygments, restructuredtext_lint]
- repo: https://github.com/myint/autoflake.git
rev: v1.4
hooks:
- id: autoflake
4 changes: 2 additions & 2 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ To get a complete report of code sections not being touched by the
test suite run ``pytest`` using ``coverage``.

.. code-block:: text

$ coverage run -m pytest
$ coverage run --concurrency=multiprocessing -m pytest
$ coverage combine
$ coverage html

Open ``htmlcov/index.html`` in your browser.
Expand Down
7 changes: 7 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
Changelog
=========

1.2.0 (UNRELEASED)
------------------

- Remove deprecated ``:meth:live_server.url``
- fixture ``request_ctx is now deprecated``
and will be removed in the future

1.1.0 (2020-11-08)
------------------

Expand Down
20 changes: 10 additions & 10 deletions docs/features.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ Extension provides some sugar for your tests, such as:

.. note::

User-defined ``json`` attribute/method in application response class does
not overrides. So you can define your own response deserialization method:
User-defined ``json`` attribute/method in application response class will
not be overwritten. So you can define your own response deserialization method:

.. code:: python

Expand Down Expand Up @@ -83,9 +83,9 @@ An instance of ``app.test_client``. Typically refers to

.. hint::

During tests execution the request context has been pushed, e.g.
``url_for``, ``session`` and other context bound objects are available
without context managers.
During test execution a request context will be automatically pushed
for you, so context-bound methods can be conveniently called (e.g.
``url_for``, ``session``.

Example:

Expand Down Expand Up @@ -145,7 +145,7 @@ other headless browsers).
``--no-start-live-server`` - don’t start live server automatically
``````````````````````````````````````````````````````````````````

By default the server is starting automatically whenever you reference
By default the server will start automatically whenever you reference
``live_server`` fixture in your tests. But starting live server imposes some
high costs on tests that need it when they may not be ready yet. To prevent
that behaviour pass ``--no-start-live-server`` into your default options (for
Expand Down Expand Up @@ -188,9 +188,11 @@ in your project's ``pytest.ini`` file)::
addopts = --live-server-port=5000


``request_ctx`` - request context
``request_ctx`` - request context (Deprecated)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

**This fixture is deprecated and will be removed in the future.**

The request context which contains all request relevant information.

.. hint::
Expand Down Expand Up @@ -228,7 +230,7 @@ Common request methods are available through the internals of the `Flask API`_.
Specifically, the API creates the default `flask.Flask.test_client`_ instance,
which works like a regular `Werkzeug test client`_.

Example:
Examples:

.. code:: python

Expand All @@ -247,8 +249,6 @@ Example:

assert res.status_code == 200

Example:

.. code:: python

def test_get_request(client, live_server):
Expand Down
4 changes: 2 additions & 2 deletions docs/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ Define your application fixture in ``conftest.py``:
Step 3. Run your test suite
---------------------------

Use the ``py.test`` command to run your test suite::
Use the ``pytest`` command to run your test suite::

py.test
pytest

.. note:: Test discovery.

Expand Down
35 changes: 35 additions & 0 deletions pytest_flask/_internal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import functools
import warnings


def deprecated(reason):
"""Decorator which can be used to mark function or method as deprecated.
It will result a warning being emmitted when the function is called."""

def decorator(func):
@functools.wraps(func)
def deprecated_call(*args, **kwargs):
warnings.simplefilter("always", DeprecationWarning)
warnings.warn(reason, DeprecationWarning, stacklevel=2)
warnings.simplefilter("default", DeprecationWarning)
return func(*args, **kwargs)

return deprecated_call

return decorator


def _rewrite_server_name(server_name, new_port):
"""Rewrite server port in ``server_name`` with ``new_port`` value."""
sep = ":"
if sep in server_name:
server_name, _ = server_name.split(sep, 1)
return sep.join((server_name, new_port))


def _determine_scope(*, fixture_name, config):
return config.getini("live_server_scope")


def _make_accept_header(mimetype):
return [("Accept", mimetype)]
150 changes: 15 additions & 135 deletions pytest_flask/fixtures.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,15 @@
#!/usr/bin/env python
import functools
import logging
import multiprocessing
import os
import signal
import socket
import time
import warnings

import pytest
from flask import _request_ctx_stack


def deprecated(reason):
"""Decorator which can be used to mark function or method as deprecated.
It will result a warning being emmitted when the function is called.
"""

def decorator(func):
@functools.wraps(func)
def deprecated_call(*args, **kwargs):
warnings.simplefilter("always", DeprecationWarning)
warnings.warn(reason, DeprecationWarning, stacklevel=2)
warnings.simplefilter("default", DeprecationWarning)
return func(*args, **kwargs)

return deprecated_call

return decorator
from ._internal import _determine_scope
from ._internal import _make_accept_header
from ._internal import _rewrite_server_name
from ._internal import deprecated
from .live_server import LiveServer


@pytest.fixture
Expand Down Expand Up @@ -58,114 +40,7 @@ def test_login(self):
request.cls.client = client


class LiveServer:
"""The helper class used to manage a live server. Handles creation and
stopping application in a separate process.

:param app: The application to run.
:param host: The host where to listen (default localhost).
:param port: The port to run application.
:param wait: The timeout after which test case is aborted if
application is not started.
"""

def __init__(self, app, host, port, wait, clean_stop=False):
self.app = app
self.port = port
self.host = host
self.wait = wait
self.clean_stop = clean_stop
self._process = None

def start(self):
"""Start application in a separate process."""

def worker(app, host, port):
app.run(host=host, port=port, use_reloader=False, threaded=True)

self._process = multiprocessing.Process(
target=worker, args=(self.app, self.host, self.port)
)
self._process.daemon = True
self._process.start()

keep_trying = True
start_time = time.time()
while keep_trying:
elapsed_time = time.time() - start_time
if elapsed_time > self.wait:
pytest.fail(
"Failed to start the server after {!s} "
"seconds.".format(self.wait)
)
if self._is_ready():
keep_trying = False

def _is_ready(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.connect((self.host, self.port))
except socket.error:
ret = False
else:
ret = True
finally:
sock.close()
return ret

@deprecated(
reason=(
'The "live_server.url" method is deprecated and will '
"be removed in the future. Please use "
'the "flask.url_for" function instead.',
)
)
def url(self, url=""):
"""Returns the complete url based on server options."""
return "http://{host!s}:{port!s}{url!s}".format(
host=self.host, port=self.port, url=url
)

def stop(self):
"""Stop application process."""
if self._process:
if self.clean_stop and self._stop_cleanly():
return
if self._process.is_alive():
# If it's still alive, kill it
self._process.terminate()

def _stop_cleanly(self, timeout=5):
"""Attempts to stop the server cleanly by sending a SIGINT signal and waiting for
``timeout`` seconds.

:return: True if the server was cleanly stopped, False otherwise.
"""
try:
os.kill(self._process.pid, signal.SIGINT)
self._process.join(timeout)
return True
except Exception as ex:
logging.error("Failed to join the live server process: %r", ex)
return False

def __repr__(self):
return "<LiveServer listening at %s>" % self.url()


def _rewrite_server_name(server_name, new_port):
"""Rewrite server port in ``server_name`` with ``new_port`` value."""
sep = ":"
if sep in server_name:
server_name, port = server_name.split(sep, 1)
return sep.join((server_name, new_port))


def determine_scope(*, fixture_name, config):
return config.getini("live_server_scope")


@pytest.fixture(scope=determine_scope)
@pytest.fixture(scope=_determine_scope)
def live_server(request, app, pytestconfig):
"""Run application in a separate process.

Expand Down Expand Up @@ -223,6 +98,15 @@ def request_ctx(app):
"""The request context which contains all request relevant information,
e.g. `session`, `g`, `flashes`, etc.
"""
warnings.warn(
"In Werzeug 2.0.0, the Client request methods "
"(client.get, client.post) always return an instance of TestResponse. This "
"class provides a reference to the request object through 'response.request' "
"The fixture 'request_ctx' is deprecated and will be removed in the future, using TestResponse.request "
"is the prefered way.",
DeprecationWarning,
stacklevel=2,
)
return _request_ctx_stack.top


Expand All @@ -231,10 +115,6 @@ def mimetype(request):
return request.param


def _make_accept_header(mimetype):
return [("Accept", mimetype)]


@pytest.fixture
def accept_mimetype(mimetype):
return _make_accept_header(mimetype)
Expand Down
Loading