Repository: pandas-dev/pandas

Issue:
DEPR: read_gbq, DataFrame.to_gbq
1. These functions are a 1 line call to https://googleapis.dev/python/pandas-gbq/latest/api.html#pandas_gbq.read_gbq and https://googleapis.dev/python/pandas-gbq/latest/api.html#pandas_gbq.to_gbq, so pandas' signatures will always lag behind the full functionality of the underlying library call.
2. We don't have any tests for this functionality nor have the capability to test this
3. It's caused some testing headaches in the past https://github.com/pandas-dev/pandas/pull/53693 https://github.com/pandas-dev/pandas/pull/54200

I think it would be best if we direct user to just use the underlying library in our ecosystem/IO docs


Discussion:
> We don't have any tests for this functionality nor have the capability to test this

i find this reason compelling

Patch:
diff --git a/ci/deps/actions-310.yaml b/ci/deps/actions-310.yaml
index 414ce92552c70..b22f8cb34c814 100644
--- a/ci/deps/actions-310.yaml
+++ b/ci/deps/actions-310.yaml
@@ -39,9 +39,6 @@ dependencies:
   - odfpy>=1.4.1
   - qtpy>=2.3.0
   - openpyxl>=3.1.0
-  # Doesn't install well with pyarrow
-  # https://github.com/pandas-dev/pandas/issues/55525
-  # - pandas-gbq>=0.19.0
   - psycopg2>=2.9.6
   - pyarrow>=10.0.1
   - pymysql>=1.0.2
diff --git a/ci/deps/actions-311-downstream_compat.yaml b/ci/deps/actions-311-downstream_compat.yaml
index 6003728150d0e..ceea734352fca 100644
--- a/ci/deps/actions-311-downstream_compat.yaml
+++ b/ci/deps/actions-311-downstream_compat.yaml
@@ -40,9 +40,6 @@ dependencies:
   - odfpy>=1.4.1
   - qtpy>=2.3.0
   - openpyxl>=3.1.0
-  # Doesn't install well with pyarrow
-  # https://github.com/pandas-dev/pandas/issues/55525
-  # - pandas-gbq>=0.19.0
   - psycopg2>=2.9.6
   - pyarrow>=10.0.1
   - pymysql>=1.0.2
diff --git a/ci/deps/actions-311.yaml b/ci/deps/actions-311.yaml
index 66ba17509516f..1c9f349c2eb28 100644
--- a/ci/deps/actions-311.yaml
+++ b/ci/deps/actions-311.yaml
@@ -39,9 +39,6 @@ dependencies:
   - odfpy>=1.4.1
   - qtpy>=2.3.0
   - openpyxl>=3.1.0
-  # Doesn't install well with pyarrow
-  # https://github.com/pandas-dev/pandas/issues/55525
-  # - pandas-gbq>=0.19.0
   - psycopg2>=2.9.6
   - pyarrow>=10.0.1
   - pymysql>=1.0.2
diff --git a/ci/deps/actions-39-minimum_versions.yaml b/ci/deps/actions-39-minimum_versions.yaml
index 8ea2a8a2f855a..aa8597978ecf7 100644
--- a/ci/deps/actions-39-minimum_versions.yaml
+++ b/ci/deps/actions-39-minimum_versions.yaml
@@ -41,7 +41,6 @@ dependencies:
   - odfpy=1.4.1
   - qtpy=2.3.0
   - openpyxl=3.1.0
-  #- pandas-gbq=0.19.0
   - psycopg2=2.9.6
   - pyarrow=10.0.1
   - pymysql=1.0.2
diff --git a/ci/deps/actions-39.yaml b/ci/deps/actions-39.yaml
index 7ee3f655ea9ec..92b88a34094d2 100644
--- a/ci/deps/actions-39.yaml
+++ b/ci/deps/actions-39.yaml
@@ -39,9 +39,6 @@ dependencies:
   - odfpy>=1.4.1
   - qtpy>=2.3.0
   - openpyxl>=3.1.0
-  # Doesn't install well with pyarrow
-  # https://github.com/pandas-dev/pandas/issues/55525
-  # - pandas-gbq>=0.19.0
   - psycopg2>=2.9.6
   - pyarrow>=10.0.1
   - pymysql>=1.0.2
diff --git a/ci/deps/circle-310-arm64.yaml b/ci/deps/circle-310-arm64.yaml
index bc6354032798d..f81b91fcbae3b 100644
--- a/ci/deps/circle-310-arm64.yaml
+++ b/ci/deps/circle-310-arm64.yaml
@@ -39,9 +39,6 @@ dependencies:
   - odfpy>=1.4.1
   - qtpy>=2.3.0
   - openpyxl>=3.1.0
-  # Doesn't install well with pyarrow
-  # https://github.com/pandas-dev/pandas/issues/55525
-  # - pandas-gbq>=0.19.0
   - psycopg2>=2.9.6
   - pyarrow>=10.0.1
   - pymysql>=1.0.2
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 6b52b52ce5e13..3f35e88cf543a 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -457,7 +457,6 @@
         "dateutil": ("https://dateutil.readthedocs.io/en/latest/", None),
         "matplotlib": ("https://matplotlib.org/stable/", None),
         "numpy": ("https://numpy.org/doc/stable/", None),
-        "pandas-gbq": ("https://pandas-gbq.readthedocs.io/en/latest/", None),
         "py": ("https://pylib.readthedocs.io/en/latest/", None),
         "python": ("https://docs.python.org/3/", None),
         "scipy": ("https://docs.scipy.org/doc/scipy/", None),
diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst
index efa4a52993a90..51d035d0d2c4b 100644
--- a/doc/source/whatsnew/v2.2.0.rst
+++ b/doc/source/whatsnew/v2.2.0.rst
@@ -262,6 +262,7 @@ For example:
 Other Deprecations
 ^^^^^^^^^^^^^^^^^^
 - Changed :meth:`Timedelta.resolution_string` to return ``h``, ``min``, ``s``, ``ms``, ``us``, and ``ns`` instead of ``H``, ``T``, ``S``, ``L``, ``U``, and ``N``, for compatibility with respective deprecations in frequency aliases (:issue:`52536`)
+- Deprecated :func:`read_gbq` and :meth:`DataFrame.to_gbq`. Use ``pandas_gbq.read_gbq`` and ``pandas_gbq.to_gbq`` instead https://pandas-gbq.readthedocs.io/en/latest/api.html (:issue:`55525`)
 - Deprecated :meth:`Index.format`, use ``index.astype(str)`` or ``index.map(formatter)`` instead (:issue:`55413`)
 - Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_clipboard`. (:issue:`54229`)
 - Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_csv` except ``path_or_buf``. (:issue:`54229`)
diff --git a/pandas/core/frame.py b/pandas/core/frame.py
index d2a9e9b1ba31f..c3696be0579b0 100644
--- a/pandas/core/frame.py
+++ b/pandas/core/frame.py
@@ -2134,6 +2134,10 @@ def to_gbq(
         """
         Write a DataFrame to a Google BigQuery table.
 
+        .. deprecated:: 2.2.0
+
+           Please use ``pandas_gbq.to_gbq`` instead.
+
         This function requires the `pandas-gbq package
         <https://pandas-gbq.readthedocs.io>`__.
 
diff --git a/pandas/io/gbq.py b/pandas/io/gbq.py
index ee71f5af12d09..350002bf461ff 100644
--- a/pandas/io/gbq.py
+++ b/pandas/io/gbq.py
@@ -5,8 +5,10 @@
     TYPE_CHECKING,
     Any,
 )
+import warnings
 
 from pandas.compat._optional import import_optional_dependency
+from pandas.util._exceptions import find_stack_level
 
 if TYPE_CHECKING:
     import google.auth
@@ -43,6 +45,10 @@ def read_gbq(
     """
     Load data from Google BigQuery.
 
+    .. deprecated:: 2.2.0
+
+       Please use ``pandas_gbq.read_gbq`` instead.
+
     This function requires the `pandas-gbq package
     <https://pandas-gbq.readthedocs.io>`__.
 
@@ -178,6 +184,13 @@ def read_gbq(
     ...                  dialect="standard"
     ...                  )  # doctest: +SKIP
     """
+    warnings.warn(
+        "read_gbq is deprecated and will be removed in a future version. "
+        "Please use pandas_gbq.read_gbq instead: "
+        "https://pandas-gbq.readthedocs.io/en/latest/api.html#pandas_gbq.read_gbq",
+        FutureWarning,
+        stacklevel=find_stack_level(),
+    )
     pandas_gbq = _try_import()
 
     kwargs: dict[str, str | bool | int | None] = {}
@@ -219,6 +232,13 @@ def to_gbq(
     progress_bar: bool = True,
     credentials: google.auth.credentials.Credentials | None = None,
 ) -> None:
+    warnings.warn(
+        "to_gbq is deprecated and will be removed in a future version. "
+        "Please use pandas_gbq.to_gbq instead: "
+        "https://pandas-gbq.readthedocs.io/en/latest/api.html#pandas_gbq.to_gbq",
+        FutureWarning,
+        stacklevel=find_stack_level(),
+    )
     pandas_gbq = _try_import()
     pandas_gbq.to_gbq(
         dataframe,


Test patch:
diff --git a/pandas/tests/io/test_gbq.py b/pandas/tests/io/test_gbq.py
new file mode 100644
index 0000000000000..b2b212ceb2c41
--- /dev/null
+++ b/pandas/tests/io/test_gbq.py
@@ -0,0 +1,14 @@
+import pandas as pd
+import pandas._testing as tm
+
+
+def test_read_gbq_deprecated():
+    with tm.assert_produces_warning(FutureWarning):
+        with tm.external_error_raised(Exception):
+            pd.read_gbq("fake")
+
+
+def test_to_gbq_deprecated():
+    with tm.assert_produces_warning(FutureWarning):
+        with tm.external_error_raised(Exception):
+            pd.DataFrame(range(1)).to_gbq("fake")
diff --git a/pandas/tests/test_downstream.py b/pandas/tests/test_downstream.py
index 41b4aa97c56f3..fe5bd33e15f15 100644
--- a/pandas/tests/test_downstream.py
+++ b/pandas/tests/test_downstream.py
@@ -161,11 +161,6 @@ def test_seaborn():
     seaborn.stripplot(x="day", y="total_bill", data=tips)
 
 
-def test_pandas_gbq():
-    # Older versions import from non-public, non-existent pandas funcs
-    pytest.importorskip("pandas_gbq", minversion="0.10.0")
-
-
 def test_pandas_datareader():
     pytest.importorskip("pandas_datareader")
 
diff --git a/scripts/tests/data/deps_expected_random.yaml b/scripts/tests/data/deps_expected_random.yaml
index 2c1f987e8101a..8fed09d88612d 100644
--- a/scripts/tests/data/deps_expected_random.yaml
+++ b/scripts/tests/data/deps_expected_random.yaml
@@ -37,7 +37,6 @@ dependencies:
   - numexpr>=2.7.3
   - openpyxl>=3.0.7
   - odfpy>=1.4.1
-  - pandas-gbq>=0.15.0
   - psycopg2>=2.8.6
   - pyarrow<11, >=7.0.0
   - pymysql>=1.0.2
diff --git a/scripts/tests/data/deps_minimum.toml b/scripts/tests/data/deps_minimum.toml
index 9856d230c3de1..c74ad3d17a4a9 100644
--- a/scripts/tests/data/deps_minimum.toml
+++ b/scripts/tests/data/deps_minimum.toml
@@ -61,7 +61,7 @@ timezone = ['tzdata>=2022.1']
 computation = ['scipy>=1.7.1', 'xarray>=0.21.0']
 fss = ['fsspec>=2021.07.0']
 aws = ['s3fs>=2021.08.0']
-gcp = ['gcsfs>=2021.07.0', 'pandas-gbq>=0.15.0']
+gcp = ['gcsfs>=2021.07.0']
 excel = ['odfpy>=1.4.1', 'openpyxl>=3.0.7', 'python-calamine>=0.1.6', 'pyxlsb>=1.0.8', 'xlrd>=2.0.1', 'xlsxwriter>=1.4.3']
 parquet = ['pyarrow>=7.0.0']
 feather = ['pyarrow>=7.0.0']
@@ -94,7 +94,6 @@ all = ['beautifulsoup4>=5.9.3',
        'numexpr>=2.7.3',
        'odfpy>=1.4.1',
        'openpyxl>=3.0.7',
-       'pandas-gbq>=0.15.0',
        'psycopg2>=2.8.6',
        'pyarrow>=7.0.0',
        'pymysql>=1.0.2',
diff --git a/scripts/tests/data/deps_unmodified_random.yaml b/scripts/tests/data/deps_unmodified_random.yaml
index f3772d9e20a1b..e560dd50c41d4 100644
--- a/scripts/tests/data/deps_unmodified_random.yaml
+++ b/scripts/tests/data/deps_unmodified_random.yaml
@@ -37,7 +37,6 @@ dependencies:
   - numexpr>=2.7.3
   - openpyxl>=3.0.7
   - odfpy>=1.4.1
-  - pandas-gbq>=0.15.0
   - psycopg2
   - pyarrow<11, >=7.0.0
   - pymysql>=1.0.2