Specify wsgi_app in config #1359.

This commit is contained in:
Hasan Ramezni 2017-01-31 01:20:06 +03:30 committed by Hasan Ramezani
parent a232c270fd
commit 57a9e2eb7e
6 changed files with 81 additions and 6 deletions

View File

@ -21,12 +21,15 @@ gunicorn
Basic usage:: Basic usage::
$ gunicorn [OPTIONS] APP_MODULE $ gunicorn [OPTIONS] [WSGI_APP]
Where ``APP_MODULE`` is of the pattern ``$(MODULE_NAME):$(VARIABLE_NAME)``. The Where ``WSGI_APP`` is of the pattern ``$(MODULE_NAME):$(VARIABLE_NAME)``. The
module name can be a full dotted path. The variable name refers to a WSGI module name can be a full dotted path. The variable name refers to a WSGI
callable that should be found in the specified module. callable that should be found in the specified module.
.. versionchanged:: 20.1.0
``WSGI_APP`` is optional if it is defined in a :ref:`config` file.
Example with the test app: Example with the test app:
.. code-block:: python .. code-block:: python

View File

@ -42,6 +42,17 @@ application specific configuration.
Loading the config from a Python module requires the ``python:`` Loading the config from a Python module requires the ``python:``
prefix. prefix.
.. _wsgi-app:
wsgi_app
~~~~~~~~
* ``None``
A WSGI application path in pattern ``$(MODULE_NAME):$(VARIABLE_NAME)``.
.. versionadded:: 20.1.0
Debugging Debugging
--------- ---------

View File

@ -12,6 +12,8 @@ from gunicorn import util
class WSGIApplication(Application): class WSGIApplication(Application):
def init(self, parser, opts, args): def init(self, parser, opts, args):
self.app_uri = None
if opts.paste: if opts.paste:
from .pasterapp import has_logging_config from .pasterapp import has_logging_config
@ -29,11 +31,18 @@ class WSGIApplication(Application):
return return
if not args: if len(args) > 0:
parser.error("No application module specified.") self.cfg.set("default_proc_name", args[0])
self.app_uri = args[0]
self.cfg.set("default_proc_name", args[0]) def load_config(self):
self.app_uri = args[0] super().load_config()
if self.app_uri is None:
if self.cfg.wsgi_app is not None:
self.app_uri = self.cfg.wsgi_app
else:
raise ConfigError("No application module specified.")
def load_wsgiapp(self): def load_wsgiapp(self):
return util.import_app(self.app_uri) return util.import_app(self.app_uri)

View File

@ -560,6 +560,17 @@ class ConfigFile(Setting):
prefix. prefix.
""" """
class WSGIApp(Setting):
name = "wsgi_app"
section = "Config File"
meta = "STRING"
validator = validate_string
default = None
desc = """\
A WSGI application path in pattern ``$(MODULE_NAME):$(VARIABLE_NAME)``.
.. versionadded:: 20.1.0
"""
class Bind(Setting): class Bind(Setting):
name = "bind" name = "bind"

View File

@ -0,0 +1 @@
wsgi_app = "app1:app1"

View File

@ -11,6 +11,7 @@ import pytest
from gunicorn import config from gunicorn import config
from gunicorn.app.base import Application from gunicorn.app.base import Application
from gunicorn.app.wsgiapp import WSGIApplication
from gunicorn.errors import ConfigError from gunicorn.errors import ConfigError
from gunicorn.workers.sync import SyncWorker from gunicorn.workers.sync import SyncWorker
from gunicorn import glogging from gunicorn import glogging
@ -25,6 +26,8 @@ def cfg_file():
return os.path.join(dirname, "config", "test_cfg.py") return os.path.join(dirname, "config", "test_cfg.py")
def alt_cfg_file(): def alt_cfg_file():
return os.path.join(dirname, "config", "test_cfg_alt.py") return os.path.join(dirname, "config", "test_cfg_alt.py")
def cfg_file_with_wsgi_app():
return os.path.join(dirname, "config", "test_cfg_with_wsgi_app.py")
def paster_ini(): def paster_ini():
return os.path.join(dirname, "..", "examples", "frameworks", "pylonstest", "nose.ini") return os.path.join(dirname, "..", "examples", "frameworks", "pylonstest", "nose.ini")
@ -52,6 +55,14 @@ class NoConfigApp(Application):
pass pass
class WSGIApp(WSGIApplication):
def __init__(self):
super().__init__("no_usage", prog="gunicorn_test")
def load(self):
pass
def test_defaults(): def test_defaults():
c = config.Config() c = config.Config()
for s in config.KNOWN_SETTINGS: for s in config.KNOWN_SETTINGS:
@ -353,6 +364,7 @@ def test_invalid_enviroment_variables_config(monkeypatch, capsys):
_, err = capsys.readouterr() _, err = capsys.readouterr()
assert "error: unrecognized arguments: --foo" in err assert "error: unrecognized arguments: --foo" in err
def test_cli_overrides_enviroment_variables_module(monkeypatch): def test_cli_overrides_enviroment_variables_module(monkeypatch):
monkeypatch.setenv("GUNICORN_CMD_ARGS", "--workers=4") monkeypatch.setenv("GUNICORN_CMD_ARGS", "--workers=4")
with AltArgs(["prog_name", "-c", cfg_file(), "--workers", "3"]): with AltArgs(["prog_name", "-c", cfg_file(), "--workers", "3"]):
@ -360,6 +372,34 @@ def test_cli_overrides_enviroment_variables_module(monkeypatch):
assert app.cfg.workers == 3 assert app.cfg.workers == 3
@pytest.mark.parametrize("options, expected", [
(["app:app"], 'app:app'),
(["-c", cfg_file(), "app:app"], 'app:app'),
(["-c", cfg_file_with_wsgi_app(), "app:app"], 'app:app'),
(["-c", cfg_file_with_wsgi_app()], 'app1:app1'),
])
def test_wsgi_app_config(options, expected):
cmdline = ["prog_name"]
cmdline.extend(options)
with AltArgs(cmdline):
app = WSGIApp()
assert app.app_uri == expected
@pytest.mark.parametrize("options", [
([]),
(["-c", cfg_file()]),
])
def test_non_wsgi_app(options, capsys):
cmdline = ["prog_name"]
cmdline.extend(options)
with AltArgs(cmdline):
with pytest.raises(SystemExit):
WSGIApp()
_, err = capsys.readouterr()
assert "Error: No application module specified." in err
@pytest.mark.parametrize("options, expected", [ @pytest.mark.parametrize("options, expected", [
(["myapp:app"], False), (["myapp:app"], False),
(["--reload", "myapp:app"], True), (["--reload", "myapp:app"], True),