Repository: pandas-dev/pandas

Issue:
Move json_normalize to pd namespace
This function I think gets a good amount of usage but people tend to import from `pandas.io.json`. ref #27522 I think we should move this to the top level

cc @bhavaniravi 


Discussion:
I totally agree. 
I'd like to contribute to this patch. If I understand correctly, I'll have to import `json_normalize` in `__init__.py`, right?

Are there any additional warnings (future / deprecation) that need to be added for this change?
Start with that and a whatsnew. We may also want to throw a FutureWarning when someone tries importing from pandas.io.json; not sure best way to do that so can maybe just submit first part and we can discuss from there

Resolving patch:
diff --git a/pandas/__init__.py b/pandas/__init__.py
--- a/pandas/__init__.py
+++ b/pandas/__init__.py
@@ -175,6 +175,8 @@
     read_spss,
 )
 
+from pandas.io.json import _json_normalize as json_normalize
+
 from pandas.util._tester import test
 import pandas.testing
 import pandas.arrays
diff --git a/pandas/io/json/__init__.py b/pandas/io/json/__init__.py
--- a/pandas/io/json/__init__.py
+++ b/pandas/io/json/__init__.py
@@ -1,5 +1,5 @@
 from pandas.io.json._json import dumps, loads, read_json, to_json
-from pandas.io.json._normalize import json_normalize
+from pandas.io.json._normalize import _json_normalize, json_normalize
 from pandas.io.json._table_schema import build_table_schema
 
 __all__ = [
@@ -7,6 +7,7 @@
     "loads",
     "read_json",
     "to_json",
+    "_json_normalize",
     "json_normalize",
     "build_table_schema",
 ]
diff --git a/pandas/io/json/_normalize.py b/pandas/io/json/_normalize.py
--- a/pandas/io/json/_normalize.py
+++ b/pandas/io/json/_normalize.py
@@ -8,6 +8,7 @@
 import numpy as np
 
 from pandas._libs.writers import convert_json_to_lines
+from pandas.util._decorators import deprecate
 
 from pandas import DataFrame
 
@@ -108,7 +109,7 @@ def nested_to_record(
     return new_ds
 
 
-def json_normalize(
+def _json_normalize(
     data: Union[Dict, List[Dict]],
     record_path: Optional[Union[str, List]] = None,
     meta: Optional[Union[str, List]] = None,
@@ -332,3 +333,8 @@ def _recursive_extract(data, path, seen_meta, level=0):
             )
         result[k] = np.array(v, dtype=object).repeat(lengths)
     return result
+
+
+json_normalize = deprecate(
+    "pandas.io.json.json_normalize", _json_normalize, "1.0.0", "pandas.json_normalize"
+)


Test patch:
diff --git a/pandas/tests/api/test_api.py b/pandas/tests/api/test_api.py
--- a/pandas/tests/api/test_api.py
+++ b/pandas/tests/api/test_api.py
@@ -170,6 +170,9 @@ class TestPDApi(Base):
         "read_spss",
     ]
 
+    # top-level json funcs
+    funcs_json = ["json_normalize"]
+
     # top-level to_* funcs
     funcs_to = ["to_datetime", "to_numeric", "to_pickle", "to_timedelta"]
 
@@ -209,6 +212,7 @@ def test_api(self):
             + self.funcs
             + self.funcs_option
             + self.funcs_read
+            + self.funcs_json
             + self.funcs_to
             + self.deprecated_funcs_in_future
             + self.deprecated_funcs
diff --git a/pandas/tests/io/json/test_normalize.py b/pandas/tests/io/json/test_normalize.py
--- a/pandas/tests/io/json/test_normalize.py
+++ b/pandas/tests/io/json/test_normalize.py
@@ -3,10 +3,9 @@
 import numpy as np
 import pytest
 
-from pandas import DataFrame, Index
+from pandas import DataFrame, Index, json_normalize
 import pandas.util.testing as tm
 
-from pandas.io.json import json_normalize
 from pandas.io.json._normalize import nested_to_record
 
 
@@ -698,3 +697,10 @@ def test_with_large_max_level(self):
         ]
         output = nested_to_record(input_data, max_level=max_level)
         assert output == expected
+
+    def test_deprecated_import(self):
+        with tm.assert_produces_warning(FutureWarning):
+            from pandas.io.json import json_normalize
+
+            recs = [{"a": 1, "b": 2, "c": 3}, {"a": 4, "b": 5, "c": 6}]
+            json_normalize(recs)