Repository: plotly/dash
Pull request #774 (2019-06-15 06:48:54)

Pick up app name from server instance (#771)
*Start with a description of this PR. Then edit the list below to the items that make sense for your PR scope, and check off the boxes as you go!*

## Contributor Checklist

- [X] I have broken down my PR scope into the following TODO tasks
   -  [X] use flask server name for dash app if name not passed in args. Fix https://github.com/plotly/dash/issues/771
- [X] I have run the tests locally and they passed. (refer to testing section in [contributing](../CONTRIBUTING.md))
- [x] I have added tests, or extended existing tests, to cover any new features or bugs fixed in this PR

### optionals

- [X] I have added entry in the `CHANGELOG.md`
- [ ] If this PR needs a follow-up in **dash docs**, **community thread**, I have mentioned the relevant URLS as follow
    -  [ ] this github [#PR number]() updates the dash docs
    -  [ ] here is the show and tell thread in plotly dash community 

### Details

I changed the default name arg value from `__main__` to `None` in order to distinguish "not passing a name" from "setting explicitly the name to `__main__` ". I figured it would be the best course of action to avoid unwanted renaming cases. 


alexcjohnson: Looks great, thanks! Would you mind adding a test, perhaps in https://github.com/plotly/dash/blob/master/tests/unit/test_configs.py, that just instantiates an `app` in various ways and checks that `app.config.name` has the desired value?
alexcjohnson: > I changed the default name arg value from `__main__` to `None` in order to distinguish "not passing a name" from "setting explicitly the name to `__main__` ". I figured it would be the best course of action to avoid unwanted renaming cases.

💯 I don't know why a user would do this, but it should definitely behave the way you've done it!
Batalex: @alexcjohnson I see that https://github.com/plotly/dash/blob/master/tests/unit/test_configs.py still use unitest, am I free to import pytest? `pytest.mark.parametrize` would be useful for this PR -> multiple cases to tests
alexcjohnson: Yes, you are more than welcome to use `pytest`! We'll be converting this and the others the rest of the way soon, just haven't gotten to this file yet.

Patch:
diff --git a/dash/CHANGELOG.md b/dash/CHANGELOG.md
index f10f09459..d9cfb06fc 100644
--- a/dash/CHANGELOG.md
+++ b/dash/CHANGELOG.md
@@ -15,6 +15,8 @@
 
 - [#739](https://github.com/plotly/dash/pull/739) Allow the Flask app to be provided to Dash after object initialization. This allows users to define Dash layouts etc when using the app factory pattern, or any other pattern that inhibits access to the app object. This broadly complies with the flask extension API, allowing Dash to be considered as a Flask extension where it needs to be.
 
+- [#774](https://github.com/plotly/dash/pull/774) Allow the Flask app to set the Dash app name if the name is not provided by users.
+
 - [#722](https://github.com/plotly/dash/pull/722) Assets are served locally by default. Both JS scripts and CSS files are affected. This improves robustness and flexibility in numerous situations, but in certain cases initial loading could be slowed. To restore the previous CDN serving, set `app.scripts.config.serve_locally = False` (and similarly with `app.css`, but this is generally less important).
 
 - Undo/redo toolbar is removed by default, you can enable it with `app=Dash(show_undo_redo=true)`. The CSS hack `._dash-undo-redo:{display:none;}` is no longer needed [#724](https://github.com/plotly/dash/pull/724)
diff --git a/dash/dash.py b/dash/dash.py
index db544be0b..deb28d76f 100644
--- a/dash/dash.py
+++ b/dash/dash.py
@@ -205,7 +205,7 @@ class Dash(object):
     """
     def __init__(
             self,
-            name='__main__',
+            name=None,
             server=True,
             assets_folder='assets',
             assets_url_path='assets',
@@ -239,10 +239,13 @@ class Dash(object):
 
         # We have 3 cases: server is either True (we create the server), False
         # (defer server creation) or a Flask app instance (we use their server)
-        if isinstance(server, bool):
-            self.server = Flask(name) if server else None
-        elif isinstance(server, Flask):
+        if isinstance(server, Flask):
             self.server = server
+            if name is None:
+                name = getattr(server, 'name', '__main__')
+        elif isinstance(server, bool):
+            name = name if name else '__main__'
+            self.server = Flask(name) if server else None
         else:
             raise ValueError('server must be a Flask app or a boolean')
 


Test patch:
diff --git a/tests/unit/test_configs.py b/tests/unit/test_configs.py
index 28417f09f..341be7ad9 100644
--- a/tests/unit/test_configs.py
+++ b/tests/unit/test_configs.py
@@ -1,9 +1,11 @@
 import os
 import unittest
+import pytest
+from flask import Flask
 # noinspection PyProtectedMember
 from dash._configs import (
     pathname_configs, DASH_ENV_VARS, get_combined_config, load_dash_env_vars)
-from dash import exceptions as _exc
+from dash import Dash, exceptions as _exc
 from dash._utils import get_asset_path
 
 
@@ -138,5 +140,17 @@ class TestConfigs(unittest.TestCase):
             self.assertEqual(vars[var], 'false')
 
 
+@pytest.mark.parametrize('name, server, expected', [
+    (None, True, '__main__'),
+    ('test', True, 'test'),
+    ('test', False, 'test'),
+    (None, Flask('test'), 'test'),
+    ('test', Flask('other'), 'test'),
+])
+def test_app_name_server(name, server, expected):
+    app = Dash(name=name, server=server)
+    assert app.config.name == expected
+
+
 if __name__ == '__main__':
     unittest.main()