Skip to content

chore(bigframes): refactor "generate_bigframes_bigquery.py" - #17904

Open
sycai wants to merge 27 commits into
mainfrom
sycai_generator_refactor
Open

chore(bigframes): refactor "generate_bigframes_bigquery.py"#17904
sycai wants to merge 27 commits into
mainfrom
sycai_generator_refactor

Conversation

@sycai

@sycai sycai commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Changes:

  • Separated file parsing logic from code generation, and modularized the code
  • Replaced nested dictionary with data classes for better modeling of data
  • Let the old generate_bigframes_bigquery.py call the new Python module

The old code generation CLI still works.

I generated all the code files and checked the results. The only thing changed in the output are the relative order of AI and AEAD code

@sycai
sycai requested review from a team as code owners July 27, 2026 02:08
@sycai
sycai requested review from tswast and removed request for a team July 27, 2026 02:08
@sycai sycai changed the title chore (bigframes): refactor "generate_bigframes_bigquery.py" chore(bigframes): refactor "generate_bigframes_bigquery.py" Jul 27, 2026

@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 refactors the BigQuery code generator by modularizing the monolithic generate_bigframes_bigquery.py script into a structured package under bigquery_generator/. The feedback is highly constructive and focuses on improving the refactored code. Key recommendations include fixing the relative script path calculation to preserve descriptive headers in generated files, using relative imports for sibling modules within the new package, explicitly specifying UTF-8 encoding when opening files, adding or correcting type hints (including a type mismatch in render_accessor), and adjusting the sys.path modification to import the generator as a proper package.

Comment thread packages/bigframes/scripts/bigquery_generator/constants.py Outdated
Comment thread packages/bigframes/scripts/bigquery_generator/__main__.py Outdated
Comment thread packages/bigframes/scripts/bigquery_generator/file_generator.py Outdated
Comment thread packages/bigframes/scripts/bigquery_generator/file_generator.py Outdated
Comment thread packages/bigframes/scripts/bigquery_generator/file_generator.py Outdated
Comment thread packages/bigframes/scripts/bigquery_generator/template_renderer.py Outdated
Comment thread packages/bigframes/scripts/bigquery_generator/yaml_parser.py Outdated
Comment thread packages/bigframes/scripts/bigquery_generator/yaml_parser.py Outdated
Comment thread packages/bigframes/scripts/bigquery_generator/yaml_parser.py Outdated
Comment thread packages/bigframes/scripts/generate_bigframes_bigquery.py Outdated
sycai and others added 16 commits July 27, 2026 02:11
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
…r.py

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
…r.py

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
…r.py

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@parthea

parthea commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Please could you merge main into this branch to resolve the GitHub Actions Scan failure? See the fix in #17889

# See the License for the specific language governing permissions and
# limitations under the License.


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.

Since this is the main entrypoint for the script, please include instructions on how to run it in a docstring.

Optionally, when run with -h or --help, also display this newly created docstring.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

File removed. I will make this package un-executable on its own.

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.

Since this is redundant with the __main__.py file you have created, please remove this file altogether and update references in our internal docs such as https://github.com/googleapis/google-cloud-python/blob/main/packages/bigframes/specs/bigframes-bigquery-generator.md with the new way to run the script.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

On the second thought, I want to preserve this file while removing "main.py".

Pros:

] + RUFF_COMMON_ARGS


TEMPLATES: dict[str, jinja2.Template] # Lazily-loaded global variable

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.

It would be helpful to have a comment explaining why we want this to be lazily loaded.

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.

Nit (Optional): We don't have to put all constants here. I would prefer that they be defined closer to where they are used or in a purpose-specific module, such as with the templates logic or list of Python built-ins, but that's mostly just a personal preference.

from . import constants


@dataclasses.dataclass

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.

Ideally we'd use frozen=True on the dataclasses in this file.

Or is there a reason they need to be mutable? If so, let's document that in a comment/docstring.

bq_module: data_models.BQModule,
) -> str:
if not bq_module.functions:
# If there are no function definitions, do not generate an empty file.

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.

I'm guessing the "do not generate an empty file" part happens at a layer above this? From what I can tell here, it's returning an empty string for the file contents. I think this comment could be reworded to make that more clear (e.g. If there are no function definitions, don't generate any boilerplate so that the caller can determine that this file should be skipped.)


def render_tests(bq_module: data_models.BQModule) -> str:
if not bq_module.functions:
# If there are no function definitions, do not generate an empty test file.

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.

Same here regarding a somewhat confusing comment.


def _to_snake_case(name: str) -> str:
# Replace dots with underscores
name = name.replace(".", "_")

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.

Why the dots to underscores part? Could you provide some examples where this logic was necessary? Some parametrized unit tests or doctests could be especiallly helpful.

# Handle CamelCase to snake_case
name = re.sub(r"(?<!^)(?=[A-Z])", "_", name).lower()
# Replace multiple underscores with one
name = re.sub(r"_+", "_", name)

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.

Same here. It would be helpful to see some concrete examples where this was needed.

return name


def _parse_func_arg(arg_data: Any) -> data_models.BQFuncArg:

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.

Nit: parse is sorta the wrong verb here. I imagine parse as the first step of going from unstructured text to some sort of structure. We're somewhere in the (symbol -> type -> resource) phases per the terminology in https://www.cs.mcgill.ca/~cs520/2018/slides/4-ast.pdf More accurate name would be _build_func_arg_ir Likewise for the other functions in this file.

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.

3 participants