pythonuwsgi

Python idiom `if __name__ == '__main__':` in uwsgi?


What is Python idiom in uwsgi for

if __name__ == '__main__':
   main()

I found here a long string in uwsgi instead of __main__ What __name__ string does uwsgi use?. But it looks like a workaround. Is there better way to call function once, when uwsgi starts my python script?


Solution

  • It depends what you are trying to guard against. There are three use cases I can think of:

    Do something only if running a real server, and not unit tests

    The uwsgi binary provides a module called uwsgi that is otherwise not importable. This is best used for detecting if you are running unit tests or not. See Unit testing Flask app running under uwsgi

    try:
        import uwsgi
    except ImportError:
        UWSGI_SERVER = False
    else:
        UWSGI_SERVER = True
    
    if UWSGI_SERVER:
       do_something()
    else:
       import test_utils
       test_utils.mock_do_somethng()
    

    Do something in a module if it is the main WSGI file

    This implies the above, that if your main module has a uwsgi_file_* module name, then you are running a uwsgi server. It also lets you know which file was run as the main module. That is, the one that contains your application. Maybe you are running a handful of micro-services that all use the same core, but need to be configured slightly differently depending on which service is running.

    File: myapp.py

    import sys
    if __name__ == 'uwsgi_file_myapp':
        assert 'uwsgi_file_myapp' in sys.modules, (
            'other modules can also see what the main module is'
        )
        connect_to_redis()
    

    See What __name__ string does uwsgi use? for more details.

    Do something after uwsgi has forked a worker process

    Useful for doing one-time initialisations per worker process. Such as connecting to a database.

    try:
        import uwsgi
    except ImportError:
        def postfork(func):
            """Dummy decorator for unit tests"""
            return func
    else:
        from uwsgidecorators import postfork
    
    DB = None
    
    @postfork
    def init_db():
        global DB
        from datetime import datetime
        DB = f'some-database connection, set @ {datetime.now().isoformat()}'
    
    def application(env, start_response):
        start_response('200 OK', [('Content-Type','text/html')])
        return [f'{DB=!r}'.encode()]
    

    This program will need to be run with the --master option. eg.

    uwsgi --http :8080 --master --wsgi-file myapp.py