Skip to content

Conversation

@jac0626
Copy link
Collaborator

@jac0626 jac0626 commented Nov 25, 2025

close #1359

Summary by Sourcery

Generate and embed a static Python package version during the build process.

New Features:

  • Add automatic reading of the generated _version.py file in setup.py to set the package version.

Bug Fixes:

  • Ensure setuptools_scm correctly determines the version when pyproject.toml resides in a subdirectory, falling back to a default version if detection fails.

Enhancements:

  • Improve the Python build preparation script to consistently generate a version string using a defined version and local scheme.

@sourcery-ai
Copy link

sourcery-ai bot commented Nov 25, 2025

Reviewer's Guide

This PR wires the setuptools_scm-generated version into the Python package by generating a robust _version.py during the build script and reading it from setup.py, including safe fallbacks when version derivation fails.

Sequence diagram for Python package version generation and usage

sequenceDiagram
    actor Developer
    participant prepare_python_build_sh
    participant python3_version_snippet
    participant setuptools_scm
    participant filesystem
    participant setup_py

    Developer->>prepare_python_build_sh: run
    prepare_python_build_sh->>python3_version_snippet: execute inline Python
    python3_version_snippet->>setuptools_scm: get_version(root, version_scheme, local_scheme)
    alt version_resolved
        setuptools_scm-->>python3_version_snippet: version string
    else error_or_failure
        setuptools_scm-->>python3_version_snippet: raise exception
        python3_version_snippet->>python3_version_snippet: set version = 0.0.0
    end
    python3_version_snippet->>filesystem: write python/pyvsag/_version.py with __version__
    filesystem-->>prepare_python_build_sh: _version.py created

    Developer->>setup_py: run setup
    setup_py->>filesystem: locate python/pyvsag/_version.py
    alt version_file_exists
        setup_py->>filesystem: read _version.py
        filesystem-->>setup_py: __version__ definition
        setup_py->>setup_py: exec file into namespace
        setup_py->>setup_py: version = ns.__version__
    else version_file_missing
        setup_py->>setup_py: version = 0.0.0
    end
    setup_py-->>Developer: package built with resolved version
Loading

File-Level Changes

Change Details Files
Read the statically generated package version from pyvsag/_version.py inside setup.py and pass it to setup().
  • Imported os and sys (though sys is currently unused) to support filesystem operations in setup.py.
  • Added a helper function _read_version() that locates python/pyvsag/_version.py relative to setup.py, executes it in an isolated namespace, and returns the version value if present.
  • Provided a defensive fallback in _read_version() that returns '0.0.0' if the version file does not exist.
  • Updated the setup() call to pass version=_read_version() so the package version is explicitly set at build time.
python/setup.py
Make the version generation script robust and independent from pyproject.toml location by explicitly configuring setuptools_scm and adding a fallback version.
  • Kept installing setuptools_scm but changed the inline Python to import os and wrap get_version() in a try/except.
  • Configured setuptools_scm.get_version() with explicit root='.' and custom version_scheme='release-branch-semver' and local_scheme='no-local-version' to ensure correct version resolution even when pyproject.toml is in a subdirectory.
  • Added a fallback to set version = '0.0.0' if setuptools_scm.get_version() raises an exception, preventing the build from failing due to version resolution issues.
  • Continued to write python/pyvsag/_version.py with version set to the resolved or fallback version and log the generated version to stdout.
scripts/python/prepare_python_build.sh

Assessment against linked issues

Issue Objective Addressed Explanation
#1359 Generate the correct Python package version during wheel builds (by fixing the version generation logic in the prepare_python_build.sh script).
#1359 Ensure setup.py uses the generated version when building the wheel so that the wheel metadata contains the correct version.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@gemini-code-assist
Copy link

Summary of Changes

Hello @jac0626, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request refines the package versioning mechanism by introducing a more robust way to generate and read the package version during the build process. It ensures that the Python package's version is consistently derived from source control metadata and made available to setup.py through a generated file, addressing potential issues with version resolution in complex project structures.

Highlights

  • Version Generation: The prepare_python_build.sh script now explicitly configures setuptools_scm with root, version_scheme, and local_scheme parameters to ensure accurate version derivation, especially when pyproject.toml is in a subdirectory. It also includes error handling, falling back to '0.0.0' if version generation fails.
  • Version Reading in setup.py: The setup.py file has been updated to include a new function, _read_version(), which reads the package version from a dynamically generated python/pyvsag/_version.py file. This ensures that the setup() function uses a consistent and pre-determined version, with a fallback to '0.0.0' if the version file is not found.
  • Robustness: Both the version generation and reading processes now include error handling and fallback mechanisms, making the build process more resilient to potential issues with version discovery.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@jac0626 jac0626 self-assigned this Nov 25, 2025
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • The imported sys module in python/setup.py is unused and can be removed to keep the file minimal.
  • In prepare_python_build.sh, the broad except Exception: around setuptools_scm.get_version could mask real issues; consider catching only expected errors and/or emitting a clear warning when falling back to 0.0.0.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The imported `sys` module in `python/setup.py` is unused and can be removed to keep the file minimal.
- In `prepare_python_build.sh`, the broad `except Exception:` around `setuptools_scm.get_version` could mask real issues; consider catching only expected errors and/or emitting a clear warning when falling back to `0.0.0`.

## Individual Comments

### Comment 1
<location> `python/setup.py:15` </location>
<code_context>
+        ns = {}
+        with open(_version_file) as f:
+            exec(f.read(), ns)
+        return ns.get('__version__')
+    return '0.0.0'
+
</code_context>

<issue_to_address>
**suggestion:** Provide a default when '__version__' is missing to avoid returning None.

If `_version.py` loads but `__version__` is missing or malformed, `ns.get('__version__')` returns `None`, so `setup(version=None, ...)` is used. This is inconsistent with the `'0.0.0'` fallback when the file is missing and can hide version-generation issues. Consider `ns.get('__version__', '0.0.0')` so all failure modes use a clear default.

Suggested implementation:

```python
        ns = {}
        with open(_version_file) as f:
            exec(f.read(), ns)
        return ns.get('__version__', '0.0.0')
    return '0.0.0'

```

From the snippet you shared, it looks like `_read_version` is duplicated and the `return` statements are missing in both copies. You should ensure that:
1) There is only a single definition of `_read_version` in `python/setup.py`.
2) That definition includes the full logic:
   - Compute `here` and `_version_file`.
   - If the file exists, load it into `ns` and `return ns.get('__version__', '0.0.0')`.
   - If the file does not exist, `return '0.0.0'`.
If any other code currently expects `_read_version` to possibly return `None`, update those call sites (if any) to no longer rely on that behavior, since it will now always return a string version.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@jac0626 jac0626 added the kind/bug Something isn't working label Nov 25, 2025
Copy link

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

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 introduces a mechanism to statically generate a version file during the build preparation and then read this version in setup.py. The changes are logical, but I have a few suggestions for improvement. In setup.py, the use of exec() to read the version file poses a security risk and should be replaced with safer file parsing, like using regular expressions. I've also noted an unused import. In prepare_python_build.sh, the exception handling for version generation is too broad and should be more specific, and there's also an unused import in the Python snippet. Addressing these points will improve the security, robustness, and cleanliness of the code.

Comment on lines +11 to +15
if os.path.exists(_version_file):
ns = {}
with open(_version_file) as f:
exec(f.read(), ns)
return ns.get('__version__')
return '0.0.0'

Choose a reason for hiding this comment

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

high

Using exec() on file contents can be a security risk as it can execute arbitrary code. Additionally, if _version.py exists but does not define __version__, ns.get('__version__') will return None, which might cause issues in setup(). A safer and more robust approach is to parse the file using a regular expression. This avoids exec and correctly handles the case where the version string is not found in the file by falling back to the default version.

Suggested change
if os.path.exists(_version_file):
ns = {}
with open(_version_file) as f:
exec(f.read(), ns)
return ns.get('__version__')
return '0.0.0'
if os.path.exists(_version_file):
with open(_version_file) as f:
content = f.read()
match = re.search(r'__version__ = "([^"]+)"', content)
if match:
return match.group(1)
return '0.0.0'

python/setup.py Outdated
Comment on lines 1 to 2
import os
import sys

Choose a reason for hiding this comment

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

medium

The sys module is imported but not used and can be removed. To support using regular expressions for parsing the version file (as suggested in another comment), the re module should be imported instead.

Suggested change
import os
import sys
import os
import re

python3 -c "
import setuptools_scm
version = setuptools_scm.get_version()
import os

Choose a reason for hiding this comment

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

medium

The os module is imported but not used within this Python code block. It can be removed to keep the code clean.

version_scheme='release-branch-semver',
local_scheme='no-local-version'
)
except Exception:

Choose a reason for hiding this comment

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

medium

Catching a broad Exception is generally discouraged as it can mask unexpected errors. It's better to catch a more specific exception. setuptools_scm.get_version() raises a LookupError when it cannot determine the version. You should catch LookupError instead.

Suggested change
except Exception:
except LookupError:

@jac0626 jac0626 force-pushed the minimal-fix-versioning branch 4 times, most recently from 0d1d4d9 to b446cea Compare November 25, 2025 13:36
@codecov
Copy link

codecov bot commented Nov 26, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.

@@            Coverage Diff             @@
##             main    #1375      +/-   ##
==========================================
+ Coverage   91.72%   92.43%   +0.71%     
==========================================
  Files         320      322       +2     
  Lines       17874    20089    +2215     
==========================================
+ Hits        16395    18570    +2175     
- Misses       1479     1519      +40     
Flag Coverage Δ
cpp 92.43% <ø> (+0.71%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
common 86.25% <ø> (-3.28%) ⬇️
datacell 93.39% <ø> (+0.21%) ⬆️
index 92.02% <ø> (+1.42%) ⬆️
simd 100.00% <ø> (ø)

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update dce6325...b446cea. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Collaborator

@wxyucs wxyucs left a comment

Choose a reason for hiding this comment

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

lgtm

@pull-request-size pull-request-size bot added size/M and removed size/S labels Nov 27, 2025
@jac0626 jac0626 force-pushed the minimal-fix-versioning branch 2 times, most recently from 594dac7 to b446cea Compare November 27, 2025 11:28
@pull-request-size pull-request-size bot added size/S and removed size/M labels Nov 27, 2025
Copy link
Collaborator

@LHT129 LHT129 left a comment

Choose a reason for hiding this comment

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

LGTM

@LHT129 LHT129 merged commit 822f04c into antgroup:main Dec 9, 2025
41 of 50 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

python build wheel unable to generate right version

3 participants