Skip to content

Commit 1abfcdd

Browse files
docs(bigquery): fix table rendering in markdown docs (#18294)
This monkeypatch is an isolated workaround in docs/conf.py while a permanent upstream fix is not scheduled in gcp-sphinx-docfx-yaml. Fixes table formatting in the generated Markdown reference documentation for `google-cloud-bigquery`. When building Markdown documentation via `sphinx-markdown-builder`, table cell paragraphs unconditionally emit trailing newlines. This breaks single-line GitHub Flavored Markdown (GFM) table rows, causing cell padding to be interpreted as 4-space indented code blocks on reference doc pages. This change adds a targeted patch in `docs/conf.py` that suppresses newlines when exiting paragraphs inside table cells, restoring valid GFM table syntax. before: screen/3oup25c57irb8 after: screen/4GqUXF7gs4p6GZV (render locally with `nox -s doxfx`) stage: https://clouddocs.devsite.corp.google.com/python/docs/reference/bigquery/latest Fixes #<522853190> 🦕 --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent 17858bb commit 1abfcdd

2 files changed

Lines changed: 116 additions & 1 deletion

File tree

packages/google-cloud-bigquery/docs/conf.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424
# All configuration values have a default; values that are commented out
2525
# serve to show the default.
2626

27-
import sys
2827
import os
2928
import shlex
29+
import sys
3030

3131
# If extensions (or modules to document with autodoc) are in another directory,
3232
# add these directories to sys.path here. If the directory is relative to the
@@ -37,6 +37,24 @@
3737
# See also: https://github.com/docascode/sphinx-docfx-yaml/issues/85
3838
sys.path.insert(0, os.path.abspath("."))
3939

40+
# TODO(b/559711363): Propagate table formatting fix across all google-cloud-* libraries.
41+
try:
42+
import sphinx_markdown_builder.markdown_writer as _smb_writer
43+
44+
_orig_depart_paragraph = _smb_writer.MarkdownTranslator.depart_paragraph
45+
46+
def _table_safe_depart_paragraph(self, node):
47+
if getattr(self, "table_entries", None):
48+
return
49+
return _orig_depart_paragraph(self, node)
50+
51+
_smb_writer.MarkdownTranslator.depart_paragraph = _table_safe_depart_paragraph
52+
_smb_writer.MarkdownTranslator.depart_compact_paragraph = (
53+
_table_safe_depart_paragraph
54+
)
55+
except ImportError:
56+
pass
57+
4058
__version__ = ""
4159

4260
# -- General configuration ------------------------------------------------
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import pathlib
16+
import runpy
17+
import sys
18+
import types
19+
from unittest import mock
20+
21+
import pytest
22+
23+
24+
def test_docs_conf_executes_successfully():
25+
docs_dir = pathlib.Path(__file__).parent.parent.parent / "docs"
26+
conf_path = docs_dir / "conf.py"
27+
if not conf_path.exists():
28+
pytest.skip("docs/conf.py not found")
29+
30+
res = runpy.run_path(str(conf_path))
31+
32+
assert res.get("project") == "google-cloud-bigquery"
33+
34+
35+
@pytest.fixture
36+
def fake_translator_and_mock():
37+
docs_dir = pathlib.Path(__file__).parent.parent.parent / "docs"
38+
conf_path = docs_dir / "conf.py"
39+
if not conf_path.exists():
40+
pytest.skip("docs/conf.py not found")
41+
42+
mock_orig_depart = mock.MagicMock(return_value="original_output")
43+
44+
class FakeTranslator:
45+
depart_paragraph = mock_orig_depart
46+
depart_compact_paragraph = mock_orig_depart
47+
48+
fake_module = types.ModuleType("sphinx_markdown_builder.markdown_writer")
49+
fake_module.MarkdownTranslator = FakeTranslator
50+
51+
with mock.patch.dict(
52+
sys.modules,
53+
{
54+
"sphinx_markdown_builder": types.ModuleType("sphinx_markdown_builder"),
55+
"sphinx_markdown_builder.markdown_writer": fake_module,
56+
},
57+
):
58+
runpy.run_path(str(conf_path))
59+
60+
return FakeTranslator, mock_orig_depart
61+
62+
63+
def test_depart_paragraph_suppresses_newlines_inside_table_cells(
64+
fake_translator_and_mock,
65+
):
66+
FakeTranslator, mock_orig_depart = fake_translator_and_mock
67+
translator = FakeTranslator()
68+
translator.table_entries = ["cell"]
69+
node = mock.MagicMock()
70+
71+
res_paragraph = FakeTranslator.depart_paragraph(translator, node)
72+
res_compact = FakeTranslator.depart_compact_paragraph(translator, node)
73+
74+
assert res_paragraph is None
75+
assert res_compact is None
76+
mock_orig_depart.assert_not_called()
77+
78+
79+
def test_depart_paragraph_delegates_outside_table_cells(
80+
fake_translator_and_mock,
81+
):
82+
FakeTranslator, mock_orig_depart = fake_translator_and_mock
83+
translator = FakeTranslator()
84+
node = mock.MagicMock()
85+
86+
res_paragraph = FakeTranslator.depart_paragraph(translator, node)
87+
res_compact = FakeTranslator.depart_compact_paragraph(translator, node)
88+
89+
assert res_paragraph == "original_output"
90+
assert res_compact == "original_output"
91+
assert mock_orig_depart.call_count == 2
92+
mock_orig_depart.assert_has_calls(
93+
[
94+
mock.call(translator, node),
95+
mock.call(translator, node),
96+
]
97+
)

0 commit comments

Comments
 (0)