Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing Flask app running under uwsgi

I’m relatively new to python and am looking for a pythonic way to handle this practice.

I’ve inherited a fairly trivial Python 2.7 Flask app that runs under uwsgi that I want to add some unit tests to. It does some initialization at indentation level 0 that is required when it’s running in uwsgi but needs to be skipped when under test.

I’m given to understand that often python apps use the

if __name__ == '__main__':

pattern to isolate code that should run when the script is run on its own and should not run when it’s imported. In this case, however, both when the script is run under uwsgi and when the script is imported into the unit tests, __name__ is the same; the name of the script, so I can’t use that to differentiate between uwsgi and unit-testing environments.

This sample code illustrates what I'm working with.

In the Flask application (flask_app.py):

import logging
import bcrypt
from flask import Flask, jsonify, abort, make_response, request
from ConfigParser import SafeConfigParser

#  some initialization that only makes sense when running from the uwsgi context on the server
PARSER = SafeConfigParser()
PARSER.read('config.ini')
LOG_FILE = PARSER.get('General', 'logfile')

APP = Flask(__name__)

@APP.route('/', methods=['GET'])
def index
    ...

@APP.route('/<p1>/<p2>', methods=['PUT'])
def put(p1, p2):
    ...

if __name__ == '__main__':
    APP.run(debug = True, host='0.0.0.0')

In the unit tests (tests.py):

import os
import unittest
from flask import json

from flask_app import APP

class FlaskAppTestCase(unittest.TestCase):

    def setUp(self):
        self.APP = APP.test_client()

    def test_GET(self):
        resp = self.APP.get('/')
        assert 'Some Html' in resp.data

    def test_PUT(self):
        resp = self.APP.put('/1/2')
        assert 'Got 1, 2' in resp.data

if __name__ == '__main__':
    unittest.main()

What I was thinking of doing was to move the initialization so that it only runs when flask_app is being executed by uwsgi and not when it's running via tests.py, perhaps by checking name and determining which path to execute based on that, but when I examine the output of print(name) either when running flask_app under uwsgi or by executing tests.py the output is "flask_app", so I can't seem to use that as a discriminator.

Is there an idiomatic way in python to handle this?

like image 830
cori Avatar asked Dec 22 '17 17:12

cori


1 Answers

As it turns out the Python module for uWSGI actually offers a mechanism to determine if the app is being run under uWSGI. The uwsgi module is available for import if you are in a uWSGI context, so I ended up checking whether i could import that module and only executing the initialization code if I could.

#   detect if we're running under uWSGI; only init if we are, not if we're testing
try:
    import uwsgi
    IN_UWSGI = True
except ImportError:
    IN_UWSGI = False

Then wrap the init code with

if IN_UWSGI:

This seems much more reliable then checking the module name of the module that's doing the import, which was the only other thing I could think of to do.

like image 182
cori Avatar answered Oct 03 '22 15:10

cori