Repository: plotly/dash

Issue:
[BUG] dash doesn't get imported when a file named "org.py", "dash.py", or "test.py" with specific content is present in the current directory // "AttributeError: module 'dash' has no attribute 'Dash'"
**Describe your context**

```
dash (1.9.1)
dash-core-components (1.8.1)
dash-html-components (1.0.2)
dash-renderer (1.2.4)
dash-table (4.6.1)

```

**Describe the bug**

If a file named ``org.py`` is present in the current directory with the following content:

```
import dash_core_components as dcc
```

then dash doesn't import and I get the following message:
```
>>> import dash
Dash was not successfully imported. Make sure you don't have a file named
'dash.py' in your current directory.
```

**Expected behavior**
dash should import without any error.

**Additional info**
- The org.py is never imported
- If I rename the file to a different name dash get imported without any problem.
- The problem is shown also with ``import dash_html_components as html```
- The problem is shown either on Windows and in Linux
- Tested with python3.4, python3.6, python3.8

**Steps to replicate the problem on Linux**
```
$ mkdir mytest
$ cd mytest
$ echo "import dash_core_components as dcc" > org.py
$ python3 -m venv venv
$ . venv/bin/activate
(venv) $ pip install dash
(venv) $ python
Python 3.4.6 (default, Mar 01 2017, 16:52:22) [GCC] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import dash
Dash was not successfully imported. Make sure you don't have a file named
'dash.py' in your current directory.
(venv) $
```

if I rename the file the import works:
```
(venv) $ mv org.py othername.py
(venv) $ python
Python 3.4.6 (default, Mar 01 2017, 16:52:22) [GCC] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import dash
>>>
```



Discussion:
I had the exact same issue with a file named "test.py"

OK this one is very weird... it appears to come from the [pickle module](https://github.com/python/cpython/blob/ec9bc2da421c456e416d991fd1fe79ac33344d9d/Lib/pickle.py#L101-L105):
```py
# Jython has PyStringMap; it's a dict subclass with string keys
try:
    from org.python.core import PyStringMap
except ImportError:
    PyStringMap = None
```

Which you can see if you raise an error inside `org.py` - it *is* trying to import it, to find `org.python.core`

That seems like a terribly hacky bit of code to have living in the Python core, but we'll have to live with that part. This becomes a problem when `org.py` tries to import something that itself needs `dash` (in this case `dash_core_components`) and finds a partially-initialized module. I suppose we could put something unique very early in the dash `__init__.py` (something like `__plotly_dash__ = True`) and short-circuit the "Make sure you don't have a file named 'dash.py' in your current directory." errors if we find it.

I don't see a problem with `test.py` but if we make a generic fix like ^^ it should cover any related oddities.

Exact same issue with test.py
For some reason downgrading to dash 1.12.0 or lower also fixed the issue. I cannot for the life of me find why though.
@meltbox360 can you try raising an exception at the top of `test.py` and post the traceback you see?
```
Traceback (most recent call last):
  File "C:/Users/xxx/PycharmProjects/plotGPS_OSM/Legacy/test6.py", line 14, in <module>
    import dash
  File "C:\Users\xxx\Anaconda3\envs\OSMNX and Dash\lib\site-packages\dash\__init__.py", line 1, in <module>
    from .dash import Dash, no_update  # noqa: F401
  File "C:\Users\xxx\Anaconda3\envs\OSMNX and Dash\lib\site-packages\dash\dash.py", line 15, in <module>
    from future.moves.urllib.parse import urlparse
  File "C:\Users\kprzybys\Anaconda3\envs\OSMNX and Dash\lib\site-packages\future\moves\__init__.py", line 8, in <module>
    import_top_level_modules()
  File "C:\Users\xxx\Anaconda3\envs\OSMNX and Dash\lib\site-packages\future\standard_library\__init__.py", line 810, in import_top_level_modules
    with exclude_local_folder_imports(*TOP_LEVEL_MODULES):
  File "C:\Users\xxx\Anaconda3\envs\OSMNX and Dash\lib\site-packages\future\standard_library\__init__.py", line 781, in __enter__
    module = __import__(m, level=0)
  File "C:\Users\xxx\PycharmProjects\plotGPS_OSM\Legacy\test.py", line 1, in <module>
    raise Exception("TEST")
Exception: TEST

Process finished with exit code 1
```
Good call. I think test is a reserved module name in python see standard_library `__init__.py` ~line 800 probably

```py
TOP_LEVEL_MODULES = ['builtins',
                     'copyreg',
                     'html',
                     'http',
                     'queue',
                     'reprlib',
                     'socketserver',
                     'test',
                     'tkinter',
                     'winreg',
                     'xmlrpc',
                     '_dummy_thread',
                     '_markupbase',
                     '_thread',
                    ]
```

Still have no idea why this works with 1.12.0 and before though.
I also have no idea if what I said above is true. Relatively new to python and haven't learned it too well yet.
Thanks @meltbox360 that's perfect. Haha `with exclude_local_folder_imports(*TOP_LEVEL_MODULES)` obviously didn't accomplish its goal, as `test` is in your local folder 🤔 It's also puzzling to me why I don't see the same issue with `test` via `future`, maybe `exclude_local_folder_imports` does the right thing on Mac but not on Windows? Anyway normally it should be fine to make a module named `test`. There does seem to be a [built-in `test` module](https://docs.python.org/3.8/library/test.html) but the docs strongly discourage its use so I have no idea why `future` would reference it. But this is indeed the same issue as `org` so should the same fix should work.
rename file **test.py** to something else

for it was caused by my file name which i named "test.py".
For folks googling, I believe this error also appears in the form `"AttributeError: module 'dash' has no attribute 'Dash'"`
**Tested Version = `1.16.3`**
https://pypi.org/project/dash/1.16.3/

In my case, there is no `org.py`, `test.py`, or `dash.py`, but my service does have `test/__init__.py`.

When I rename `test/` to `tests/`, the error goes away. There was also a separate, unrelated dependency that I was installing that included its own `test` package in its wheel, thus still allowing `import test` to do something, and therefore prevent `import dash`.

Basically, for me to get functional I needed to ensure the application cannot perform `import test`, at which point `import dash` works.
Could this be prevented by just making dash to check if there is any `test.py`, or `test` folder, or `org.py` etc. in the folder where the application starts? And then raise and Exception with notification that your app will not work if you have files/folders named like this? 
Same issue with my script named `code.py`

Resolving patch:
diff --git a/dash/__init__.py b/dash/__init__.py
--- a/dash/__init__.py
+++ b/dash/__init__.py
@@ -1,7 +1,11 @@
-from .dash import Dash, no_update  # noqa: F401
-from . import dependencies  # noqa: F401
-from . import development  # noqa: F401
-from . import exceptions  # noqa: F401
-from . import resources  # noqa: F401
-from .version import __version__  # noqa: F401
-from ._callback_context import callback_context  # noqa: F401
+# pylint: disable=C0413
+# __plotly_dash is for the "make sure you don't have a dash.py" check
+# must come before any other imports.
+__plotly_dash = True
+from .dash import Dash, no_update  # noqa: F401,E402
+from . import dependencies  # noqa: F401,E402
+from . import development  # noqa: F401,E402
+from . import exceptions  # noqa: F401,E402
+from . import resources  # noqa: F401,E402
+from .version import __version__  # noqa: F401,E402
+from ._callback_context import callback_context  # noqa: F401,E402


Test patch:
diff --git a/tests/integration/dash/dash_import_test.py b/tests/integration/dash/dash_import_test.py
new file mode 100644
--- /dev/null
+++ b/tests/integration/dash/dash_import_test.py
@@ -0,0 +1,15 @@
+# NOTE: this is NOT a pytest test. Just run it as a regular Python script.
+# pytest does some magic that makes the issue we're trying to test disappear.
+
+import types
+import os
+
+import dash
+
+assert isinstance(dash, types.ModuleType), "dash can be imported"
+
+this_dir = os.path.dirname(__file__)
+with open(os.path.join(this_dir, "../../../dash/version.py")) as fp:
+    assert dash.__version__ in fp.read(), "version is consistent"
+
+assert getattr(dash, "Dash").__name__ == "Dash", "access to main Dash class is valid"
diff --git a/tests/integration/dash/org.py b/tests/integration/dash/org.py
new file mode 100644
--- /dev/null
+++ b/tests/integration/dash/org.py
@@ -0,0 +1,3 @@
+# used implicitly by dash_import_test
+# to test https://github.com/plotly/dash/issues/1143
+import dash_core_components as dcc  # noqa: F401
diff --git a/tests/unit/dash/test_dash_import.py b/tests/unit/dash/test_dash_import.py
deleted file mode 100644
--- a/tests/unit/dash/test_dash_import.py
+++ /dev/null
@@ -1,14 +0,0 @@
-import importlib
-import types
-
-
-def test_dddi001_dash_import_is_correct():
-    imported = importlib.import_module("dash")
-    assert isinstance(imported, types.ModuleType), "dash can be imported"
-
-    with open("./dash/version.py") as fp:
-        assert imported.__version__ in fp.read(), "version is consistent"
-
-    assert (
-        getattr(imported, "Dash").__name__ == "Dash"
-    ), "access to main Dash class is valid"
diff --git a/tests/unit/test_import.py b/tests/unit/test_import.py
deleted file mode 100644
--- a/tests/unit/test_import.py
+++ /dev/null
@@ -1,14 +0,0 @@
-import importlib
-import types
-
-
-def test_dash_import_is_correct():
-    imported = importlib.import_module("dash")
-    assert isinstance(imported, types.ModuleType), "dash can be imported"
-
-    with open("./dash/version.py") as fp:
-        assert imported.__version__ in fp.read(), "version is consistent"
-
-    assert (
-        getattr(imported, "Dash").__name__ == "Dash"
-    ), "access to main Dash class is valid"