Repository: plotly/plotly.py

Issue:
With newer versions of orjson, users need to specify the json engine explicitly (bug?)
Hey

I found out I get an
`AttributeError: partially initialized module 'orjson' has no attribute 'OPT_NON_STR_KEYS'`
if I don't specify this
`plotly.io.json.config.default_engine = 'orjson'`
when using orjson v3.6.6 (latest as of 25jan2022)

Also, additional note for whoever might have this issue: you don't need to uninstall orjson if you don't want to use it. just set the engine to 'json' explicitly. 

I'm using orjson because of the performance claims, although I ran some tests switching between the 2 engines and they seem to yield the same results: using go.Candlestick with 10000 candlesticks and some 4-5 indicators, getting ~0.8sec in each case for creating the plot. My purpose is to improve the dash server performace, but it seems it makes no difference (the web page still renders slower than the ticker even with 600 candles)





Discussion:
+1
+1. App is presenting problems after a while. Not sure what's going on.
+1. Happens to me when I use streamlit's `st.plotly_chart` (plotly v5.18.0)
File "/.venv/lib/python3.11/site-packages/plotly/io/_json.py", line 146, in to_json_plotly
opts = orjson.OPT_NON_STR_KEYS | orjson.OPT_SERIALIZE_NUMPY

This line of code may cause this issue
A fix may be using a regular import rather than using importlib to manage this package.
To reproduce using Dash:
1. `pip install orjson`
2. Make a Dash app
3. Trigger reload

If you look at network requests, it'll show this exact error.

Resolving patch:
diff --git a/packages/python/plotly/_plotly_utils/optional_imports.py b/packages/python/plotly/_plotly_utils/optional_imports.py
--- a/packages/python/plotly/_plotly_utils/optional_imports.py
+++ b/packages/python/plotly/_plotly_utils/optional_imports.py
@@ -2,6 +2,7 @@
 Stand-alone module to provide information about whether optional deps exist.
 
 """
+
 from importlib import import_module
 import logging
 import sys
@@ -19,10 +20,9 @@ def get_module(name, should_load=True):
     :return: (module|None) If import succeeds, the module will be returned.
 
     """
-    if name in sys.modules:
-        return sys.modules[name]
     if not should_load:
-        return None
+        return sys.modules.get(name, None)
+
     if name not in _not_importable:
         try:
             return import_module(name)
@@ -32,3 +32,5 @@ def get_module(name, should_load=True):
             _not_importable.add(name)
             msg = f"Error importing optional module {name}"
             logger.exception(msg)
+
+    return None


Test patch:
diff --git a/packages/python/plotly/test_requirements/requirements_38_core.txt b/packages/python/plotly/test_requirements/requirements_38_core.txt
--- a/packages/python/plotly/test_requirements/requirements_38_core.txt
+++ b/packages/python/plotly/test_requirements/requirements_38_core.txt
@@ -1,3 +1,3 @@
 requests==2.25.1
 tenacity==6.2.0
-pytest==6.2.3
+pytest==8.1.1
diff --git a/packages/python/plotly/test_requirements/requirements_38_optional.txt b/packages/python/plotly/test_requirements/requirements_38_optional.txt
--- a/packages/python/plotly/test_requirements/requirements_38_optional.txt
+++ b/packages/python/plotly/test_requirements/requirements_38_optional.txt
@@ -5,7 +5,7 @@ numpy==1.20.2
 xarray==0.17.0
 statsmodels
 Pillow==8.2.0
-pytest==6.2.3
+pytest==8.1.1
 pytz==2021.1
 ipython[all]==7.22.0
 ipywidgets==8.0.2