Skip to content

Commit

Permalink
Added support for multiple configurations in one module.
Browse files Browse the repository at this point in the history
  • Loading branch information
idlesign committed Oct 12, 2017
1 parent d837c79 commit ee4392a
Show file tree
Hide file tree
Showing 15 changed files with 287 additions and 150 deletions.
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ uwsgiconf changelog

Unreleased
----------
+ Added support for multiple configurations in one module.
+ Configuration now accepts 'alias' param.
* Nice preset. Threads are now on by default for PythonSection.
+ Sockets and Routers reworked.
Expand Down
33 changes: 24 additions & 9 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,32 @@ Let's make ``uwsgicfg.py``. There we configure it using nice ``PythonSection`` p

.. code-block:: python
from uwsgiconf.config import configure_uwsgi
from uwsgiconf.presets.nice import PythonSection
configuration = PythonSection(
# Load wsgi.py module containing WSGI application.
wsgi_module='/home/idle/myapp/wsgi.py',
def get_configurations():
"""This should return one or more Section or Configuration objects.
In such a way you can configure more than one uWSGI instance in the same place.
Here we'll define just one configuration section, which
will instruct uWSGI to serve WSGI application (from wsgi.py module)
on http://127.0.0.1:8000
"""
section = PythonSection(
wsgi_module='/home/idle/myapp/wsgi.py',
).networking.register_socket(
PythonSection.networking.sockets.http('127.0.0.1:8000'))
return section
# Almost done. One more thing:
configure_uwsgi(get_configurations)
).networking.register_socket(
# Make app available on http://127.0.0.1:8000
PythonSection.networking.sockets.http('127.0.0.1:8000'),
)
1. Now if you want to generate ``myconf.ini`` file and use it for uWSGI manually you can do it with:

Expand Down Expand Up @@ -112,8 +126,9 @@ A couple of examples:
"""
with lock():
# Code under this context manager will be locked using default (0) uWSGI lock.
do()
# Code under this context manager will be locked
# using default (0) uWSGI lock.
do_something()
Expand Down
87 changes: 65 additions & 22 deletions demos/onefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,56 +6,99 @@
uwsgiconf run <path-to-this-file>
* Python 3 is expected.
"""
from functools import partial

from uwsgiconf.config import configure_uwsgi
from uwsgiconf.utils import PY3


def encode(data):
return map(partial(bytes, encoding='utf8'), data) if PY3 else data


def application(env, start_response):
def app_1(env, start_response):
"""This is simple WSGI application that will be served by uWSGI."""

from functools import partial
import random
from uwsgiconf.runtime.environ import uwsgi_env

start_response('200 OK', [('Content-Type','text/html')])

data = [
'<h1>uwsgiconf demo: one file</h1>',

'<div>Some random number for you: %s</div>' % random.randint(1, 99999),

'<div>uWSGI version: %s</div>' % uwsgi_env.get_version(),
'<div>uWSGI request ID: %s</div>' % uwsgi_env.request.id,
]

return map(partial(bytes, encoding='utf8'), data)
return encode(data)


def app_2(env, start_response):
"""This is another simple WSGI application that will be served by uWSGI."""

import random

start_response('200 OK', [('Content-Type','text/html')])

data = [
'<h1>uwsgiconf demo: one file second app</h1>',

'<div>Some random number for you: %s</div>' % random.randint(1, 99999),
]

return encode(data)


def configure():
"""Configure uWSGI."""
"""Configure uWSGI.
This returns several configuration objects, which will be used
to spawn several uWSGI processes.
Applications are on 127.0.0.1 on ports starting from 8000.
"""
import os
from uwsgiconf.presets.nice import PythonSection

FILE = os.path.abspath(__file__)
port = 8000

configurations = []

for idx in range(2):

alias = 'app_%s' % (idx + 1)

section = PythonSection(
# Automatically reload uWSGI if this file is changed.
touch_reload=FILE,

# To differentiate easily.
process_prefix=alias,

# Serve WSGI application (see above) from this very file.
wsgi_module=FILE,

section = PythonSection(
# Automatically reload uWSGI if this file is changed.
touch_reload=FILE,
# Custom WSGI callable for second app.
wsgi_callable=alias,

# Serve WSGI application (see above) from this very file.
wsgi_module=FILE,
# One is just enough, no use in worker on every core
# for this demo.
workers=1,

# One is just enough, no use in worker on every core
# for this demo.
workers=1
).networking.register_socket(
PythonSection.networking.sockets.http('127.0.0.1:%s' % port)
)

).networking.register_socket(
PythonSection.networking.sockets.http('127.0.0.1:8000'),
port += 1

)
configurations.append(
# We give alias for configuration to prevent clashes.
section.as_configuration(alias=alias))

return section
return configurations


configuration = configure()
configure_uwsgi(configure)
13 changes: 0 additions & 13 deletions docs/source/hints.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,6 @@ You can try the following trick (from directory containing ``venv/`` and ``uwsgi
$ venv/bin/uwsgiconf run
Install with CLI
----------------
*I'm unable to run CLI because of a strange error, what should I do?*

**uwsgiconf** expects ``click`` package available for CLI but won't install this dependency by default.

Use the following command to install **uwsgiconf** with ``click``:

.. code-block:: bash
$ pip install uwsgiconf[cli]
Unknown config directive
------------------------

Expand Down
65 changes: 48 additions & 17 deletions docs/source/quickstart.rst
Original file line number Diff line number Diff line change
@@ -1,38 +1,69 @@
Quickstart
==========


Install
-------

You can get and install **uwsgiconf** from PyPI using ``pip``:

.. code-block:: bash
$ pip install uwsgiconf
CLI
~~~

**uwsgiconf** expects ``click`` package available for CLI but won't install this dependency by default.

Use the following command to install **uwsgiconf** with ``click``:

.. code-block:: bash
$ pip install uwsgiconf[cli]
Using a preset to run Python web application
--------------------------------------------

Let's make ``uwsgicfg.py``. There we configure it using nice ``PythonSection`` preset to run our web app.

.. code-block:: python
from uwsgiconf.config import configure_uwsgi
from uwsgiconf.presets.nice import PythonSection
configuration = PythonSection(
# Reload uWSGI when this file is updated.
touch_reload=__file__,
def get_configurations():
"""This should return one or more Section or Configuration objects.
In such a way you can configure more than one uWSGI instance in the same place.
"""
section = PythonSection(
# Reload uWSGI when this file is updated.
touch_reload=__file__,
params_python=dict(
# Let's add something into Python path.
search_path='/home/idle/apps/',
),
wsgi_module='/home/idle/myapp/wsgi.py',
params_python=dict(
# We'll run our app using virtualenv.
python_home='/home/idle/venv/',
search_path='/home/idle/apps/',
),
# If your uWSGI has no basic plugins embedded
# (i.e. not from PyPI) you can give uwsgiconf a hint:
# embedded_plugins=False,
# Load wsgi.py module from myapp package.
wsgi_module='myapp.wsgi',
).networking.register_socket(
# Make app available at http://127.0.0.1:8000
PythonSection.networking.sockets.http('127.0.0.1:8000'))
# If your uWSGI has no basic plugins embedded
# (i.e. not from PyPI) you can give uwsgiconf a hint:
# embedded_plugins=False,
return section
).networking.register_socket(
# Make app available at http://127.0.0.1:8000
PythonSection.networking.sockets.http('127.0.0.1:8000'),
)
# Almost done. One more thing:
configure_uwsgi(get_configurations)
Now we are ready to use this configuration:
Expand Down
23 changes: 13 additions & 10 deletions tests/confs/dummy.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
from uwsgiconf.config import Section, Configuration
from uwsgiconf.config import Section, Configuration, configure_uwsgi


print("this line won't print")

not_conf1 = lambda: []

not_conf2 = [1, 2]
def get_config():

configuration = [
configuration = [

Configuration([
Section(),
Section('conf1_2').env('A', 'B')
], alias='uwsgicgf_test1'),
Configuration([
Section(),
Section('conf1_2').env('A', 'B')
], alias='uwsgicgf_test1'),

Section().env('D', 'E'),
]
Section().env('D', 'E'),
]
return configuration


configure_uwsgi(get_config)
5 changes: 3 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import subprocess
from os import environ

import pytest
import subprocess

from uwsgiconf.settings import ENV_FORCE_STUB

# Force stub to allow shallow testing.
environ['UWSGI_FORCE_STUB'] = '1'
environ[ENV_FORCE_STUB] = '1'


@pytest.fixture(scope='session')
Expand Down
2 changes: 2 additions & 0 deletions tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

def test_section_basics(assert_lines):

assert_lines('set-placeholder = one=two', Section().set_placeholder('one', 'two'))

my_section = Section()

assert_lines('automatically generated', my_section, stamp=True)
Expand Down
20 changes: 1 addition & 19 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import pytest

from uwsgiconf.utils import UwsgiRunner, parse_command_plugins_output, ConfModule, get_uwsgi_stub_attrs_diff
from uwsgiconf.exceptions import ConfigurationError, UwsgiconfException
from uwsgiconf.exceptions import UwsgiconfException


SAMPLE_OUT_PLUGINS_MANY = '''
Expand Down Expand Up @@ -59,24 +59,6 @@ def test_runner(mock_popen):
def test_conf_module_compile():
fpath = os.path.join(os.path.dirname(__file__), 'confs', 'dummy.py')

# no attr
module = ConfModule(fpath)
module.confs_attr_name = 'faked'
with pytest.raises(ConfigurationError):
confs = module.configurations

# empty
module = ConfModule(fpath)
module.confs_attr_name = 'not_conf1'
with pytest.raises(ConfigurationError):
confs = module.configurations

# invalid objects
module = ConfModule(fpath)
module.confs_attr_name = 'not_conf2'
with pytest.raises(ConfigurationError):
confs = module.configurations

# invalid objects
module = ConfModule(fpath)
assert module.configurations
Expand Down
2 changes: 1 addition & 1 deletion uwsgiconf/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def run(conf, only):
spawned = config.spawn_uwsgi(only)

for alias, pid in spawned:
click.secho("Spawned uWSGI for '%s' configuration. PID %s" % (alias, pid), fg='green')
click.secho("Spawned uWSGI for configuration aliased '%s'. PID %s" % (alias, pid), fg='green')


@base.command()
Expand Down

0 comments on commit ee4392a

Please sign in to comment.