Visitar URL original
docfx_yaml: materialize move_markdown_pages cwd list per call (mutable-default leak) by Hisernberg · Pull Request #19044 · googleapis/google-cloud-python · GitHub
Skip to content

docfx_yaml: materialize move_markdown_pages cwd list per call (mutable-default leak) - #19044

Draft
Hisernberg wants to merge 2 commits into
googleapis:mainfrom
Hisernberg:fix/move-markdown-pages-cwd-default
Draft

Hisernberg wants to merge 2 commits into
googleapis:mainfrom
Hisernberg:fix/move-markdown-pages-cwd-default

Conversation

@Hisernberg

@Hisernberg Hisernberg commented Nov 11, 2026 •

Copy link
Copy Markdown

Description

move_markdown_pages() declares cwd: list[str] | None = [] and then mutates cwd in place during recursion (cwd.append(mdfile.name) / cwd.pop() in docfx_yaml/markdown_utils.py). The default [] is therefore a shared list across every top-level call. If an exception escapes between the append and the pop (e.g. a failing file copy mid-recursion), the leftover entry stays in the default list forever, and every later top-level call looks in the wrong markdown directory.

Reproduction (local, stubbed sphinx): a mid-recursion shutil.copy failure on call 1 makes call 2 skip top-level files entirely (cwd still holds the leaked subdirectory). With this change the second call processes top-level files normally.

Fix

Default cwd to None and materialize a fresh list per top-level call, matching the existing list[str] | None annotation (the recursion still receives the same shared list, so sub-directory behavior is unchanged).

Before: second call after a mid-recursion failure -> top-level index.md never copied (cwd leaked).
After: second call works (fresh cwd per call).

AI Generation Disclosure

Developed with AI assistance (agent workflow): found by an AST scan for mutated mutable defaults, reproduced before/after the fix with a functional stub test, and verified.

Release Notes

  • packages/gcp-sphinx-docfx-yaml
    • fix(crawl): avoid leaking cwd state across move_markdown_pages calls

The recursion mutates cwd in place (append/pop). With the shared mutable
default [], a failure between the append and the pop leaves state in the
default list, and every later top-level call then looks in the wrong
markdown directory (reproduced: a mid-recursion copy error on one call
made the next call skip top-level files entirely). Default to None and
materialize a fresh list per top-level call.
@Hisernberg
Hisernberg requested a review from a team as a code owner November 11, 2026 13:15
@google-cla

google-cla Bot commented Nov 11, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request resolves a mutable default argument issue in move_markdown_pages by changing the default value of cwd to None and initializing it inside the function. However, the initialization block was placed before the function's docstring, which prevents Python from recognizing it as a docstring. It is recommended to move this block immediately after the docstring.

Comment on lines +331 to +335
if cwd is None:
# Materialize a fresh list per top-level call: the recursion below
# mutates ``cwd`` in place (append/pop), which would otherwise keep
# state in the shared default across calls.
cwd = []

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

In Python, the docstring must be the very first statement in the function body. Placing the if cwd is None: block before the docstring prevents Python from recognizing it as a docstring (i.e., it won't be assigned to __doc__), which can break documentation generation tools like Sphinx. Please move this initialization block to be immediately after the function's docstring.

@parthea

parthea commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

Hi @Hisernberg, Thanks for providing a fix! Please could you sign the CLA? Once it's signed, please mark the PR as Ready for review. Thanks!

@parthea
parthea marked this pull request as draft November 11, 2026 13:49
The if-block before the docstring prevented it from being recognized
as the function docstring (spotted by gemini-code-assist review).
@Hisernberg

Copy link
Copy Markdown
Author

Moved the cwd initialization after the docstring — good catch, thanks @gemini-code-assist.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

You're welcome! To ensure this fix remains effective and to prevent future regressions, I recommend adding a unit test that simulates a failure during the recursive file processing. This would verify that the cwd state is correctly reset for subsequent calls, ensuring that the mutable default leak is fully addressed.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants