main: Better Reporting of the GUI Tool Version Numbers - #136
Conversation
|
Hi @joshanne can you solve the version v0.0.0 issue when launching the tool directly from source? others looks OK to me |
4d5e709 to
bbacee0
Compare
|
@Huibean if possible, would you like to give it another look over? I've updated the above images to show the developer build working the same way. it simplifies the release process atm, no manual editing of files... there is still one edge case, but its very unlikely to hit now. It allows developers to run the tool from their directory and get the current commit information at runtime. If @tridge or the release maintainer is okay to slightly modify the release process, the release process then becomes...
In effect, the steps for loading the version here are then:
|
bbacee0 to
69793c2
Compare
Because the version is only incremented prior to a release, we have a number of commits between releases that all identify as the last release. This means, all of our most recent changes that have improved gui_tool look like it's an old version, and managing users installs is hard. 'But it works on v1.2.28' - when it's actually a dev build the user is running...
Precedence for version information: * git describe * setuptools_scm generated file * .git_archival.txt * default value
69793c2 to
e3f36a7
Compare
There was a problem hiding this comment.
Pull request overview
This PR improves how DroneCAN GUI Tool reports its version for development builds by adopting setuptools_scm-based version generation and surfacing additional metadata (e.g., post-release commit count / dirty state) in both CLI --version output and the About dialog.
Changes:
- Switch packaging to
setuptools_scmand emit a generated version file at build time. - Update the CLI
--versionoutput and About window to display dev/build metadata. - Add Git archive substitution support via
.gitattributesand a.git_archival.txttemplate for non-git source distributions.
Reviewed changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| setup.py | Switches package versioning to setuptools_scm with write_to output. |
| pyproject.toml | Adds setuptools_scm[toml] to build-system requirements. |
| dronecan_gui_tool/widgets/about_window.py | Updates About dialog to show version + dev metadata. |
| dronecan_gui_tool/version.py | Adds runtime/build-time version resolution (git / generated file / archival). |
| dronecan_gui_tool/main.py | Updates --version output to include dev metadata and dirty warning. |
| .gitignore | Ignores the generated version file and venv directory. |
| .gitattributes | Enables export-subst for .git_archival.txt. |
| .git_archival.txt | Provides archive-substitution placeholders for version/commit metadata. |
Suppressed comments (1)
dronecan_gui_tool/version.py:106
- Avoid printing to stdout/stderr at module import time. Importing
dronecan_gui_tool.versionduring normal startup will emit this message and can interfere with--versionoutput formatting or GUI launches. Prefer leaving the version as the default tuple (or logging/warnings at the call site where version is displayed).
print("Warning: Git is not available and .git_archival.txt not found")
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| use_scm_version={ | ||
| "write_to": "dronecan_gui_tool/_version_generated.py", | ||
| "version_scheme": "post-release" | ||
| }, |
3f9291e to
68200a4
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 8 changed files in this pull request and generated no new comments.
Suppressed comments (4)
dronecan_gui_tool/main.py:54
- Dirty-build detection here only looks for the setuptools_scm-style ".dYYYYMMDD" marker, but version.py also appends the literal metadata part "dirty" for dirty source trees. As a result,
--versionmay omit the dirty warning for source runs.
metadata_parts = [x for x in __version_tuple__ if isinstance(x, str)]
is_clean_release = len(metadata_parts) == 0
is_dirty = any(".d" in part for part in metadata_parts)
version_info = '.'.join(map(str, __version__))
dronecan_gui_tool/version.py:108
- This
print()runs at import time when git metadata isn't available, which can pollute stdout/stderr for any consumer importing the package (including packaging/build tools). Prefer logging (or silence) over printing from a library module import path.
else:
print("Warning: Git is not available and .git_archival.txt not found")
dronecan_gui_tool/version.py:27
- version.py runs
git describeunconditionally at import time. In installed wheels (no .git directory) this still spawns a git subprocess (and then falls back), adding avoidable startup overhead and an external tool dependency. Consider skipping the git call unless this is actually a git checkout.
This issue also appears on line 107 of the same file.
# 1. Try running git describe first (live git repository state)
try:
git_describe = subprocess.check_output(
["git", "describe", "--tags", "--long", "--dirty"],
stderr=subprocess.DEVNULL,
text=True,
cwd=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
).strip()
setup.py:50
setuptools-scmis only needed to build the package/version metadata; it isn't imported or required at runtime. Keeping it ininstall_requiresforces an unnecessary runtime dependency for end users.
install_requires=[
'setuptools>=18.5',
'setuptools-scm>=6.2',
'dronecan>=1.0.25',
'pyserial>=3.0',
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 8 changed files in this pull request and generated no new comments.
Suppressed comments (3)
dronecan_gui_tool/main.py:54
- Dirty working tree detection won't trigger with the parsed setuptools_scm metadata.
version.pysplits the version string into parts liked20260724, but this check looks for the substring.d, which won't be present in any individual part (so the warning is skipped even for dirty builds).
metadata_parts = [x for x in __version_tuple__ if isinstance(x, str)]
is_clean_release = len(metadata_parts) == 0
is_dirty = any(".d" in part for part in metadata_parts)
version_info = '.'.join(map(str, __version__))
dronecan_gui_tool/widgets/about_window.py:24
- The dirty build marker from setuptools_scm typically becomes a metadata part like
dYYYYMMDDafter splitting the version string. Checking for.dinside each part won't match, so the About dialog may omit the "Dirty" indicator even for dirty builds.
numeric_parts = [x for x in __version_tuple__ if isinstance(x, int)]
metadata_parts = [x for x in __version_tuple__ if isinstance(x, str)]
is_clean_release = len(metadata_parts) == 0
is_dirty = any((part == "dirty") or (".d" in part) for part in metadata_parts)
version_info = '.'.join(map(str, numeric_parts))
dronecan_gui_tool/version.py:36
setuptools_scm'swrite_tofile typically defines__version__(a string), not__version_tuple__. Importing__version_tuple__from_version_generated.pywill fail for built artifacts, causing the version to fall back to the manual tuple (and emitting a warning), which defeats the purpose ofuse_scm_version.
# 2. Try to import the generated version information (built wheels/MSIs)
try:
from ._version_generated import __version_tuple__ # noqa: F401
except ImportError:
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 8 changed files in this pull request and generated no new comments.
Suppressed comments (4)
dronecan_gui_tool/version.py:46
setuptools_scm'swrite_tooutput defaults to a module containing__version__(string). This code attempts to import__version_tuple__from._version_generated, so it will raiseImportErrorand always fall back to the manual version, defeating the purpose of writing the generated file.
# 2. Try to import the generated version information (built wheels/MSIs)
try:
from ._version_generated import __version_tuple__ # noqa: F401
except ImportError:
# 3. Fall back to the manually updated version
print("Warning: setuptools_scm is not available or failed with: ", e,
" and _version_generated.py not found. "
"Falling back to manual version.")
dronecan_gui_tool/version.py:50
- This module prints warnings to stdout during import (e.g., in shallow clones it intentionally raises an exception and then prints). That can corrupt
--versionoutput and other CLI output; prefer emitting warnings on stderr (or logging) and avoid warning for expected shallow-clone fallback.
if os.path.exists(os.path.join(_root_dir, '.git', 'shallow')):
raise Exception("Shallow clone detected, falling back to manual version")
_version_str = get_version(root=_root_dir, version_scheme='post-release')
# Parse the version string into a tuple
_parts = []
for _part in re.split(r'[-.+]', _version_str):
if _part:
try:
_parts.append(int(_part))
except ValueError:
_parts.append(_part)
__version_tuple__ = tuple(_parts)
except Exception as e:
if not _is_source:
# 2. Try to import the generated version information (built wheels/MSIs)
try:
from ._version_generated import __version_tuple__ # noqa: F401
except ImportError:
# 3. Fall back to the manually updated version
print("Warning: setuptools_scm is not available or failed with: ", e,
" and _version_generated.py not found. "
"Falling back to manual version.")
else:
print("Warning: setuptools_scm is not available or failed with: ", e,
" and running from source. "
"Falling back to manual version.")
dronecan_gui_tool/main.py:54
__version_tuple__is produced by splitting the setuptools_scm version string on[-.+], so dirty builds become a part like"d20260724"(no leading dot). Checking for the substring".d"will never match, so the dirty-working-tree warning won't be shown.
metadata_parts = [x for x in __version_tuple__ if isinstance(x, str)]
is_clean_release = len(metadata_parts) == 0
is_dirty = any(".d" in part for part in metadata_parts)
version_info = '.'.join(map(str, __version__))
dronecan_gui_tool/widgets/about_window.py:24
__version_tuple__comes from splitting the setuptools_scm version string on[-.+], so dirty builds are represented as a string part like"d20260724". The current check looks for".d"(and the literal"dirty"), which won't match"dYYYYMMDD", so the About dialog can miss marking dev builds as dirty.
numeric_parts = [x for x in __version_tuple__ if isinstance(x, int)]
metadata_parts = [x for x in __version_tuple__ if isinstance(x, str)]
is_clean_release = len(metadata_parts) == 0
is_dirty = any((part == "dirty") or (".d" in part) for part in metadata_parts)
version_info = '.'.join(map(str, numeric_parts))
This is hopefully a change for the better.
I have team members running various versions of the main branch since the last release. I cannot tell exactly which version they are running because the application only tells me what
version.pycontains, which is typically updated just before the next tag and release is about to occur.This PR makes use of
setuptools_scmto improve the reporting of the version number.The current build/release process entails:
version.pyThis means, for all users installing from
masterafter the last release, their build "looks" like the most recent release, but does not indicate that it is development patches on top of the last release.This PR aims to improve some of that reporting.
Currently outstanding:
All of this assumes the user has installed dronecan_gui_tool with one of the following methods:
After which, one of the following outcomes occur...
Similarly, the version can be seen in the application.
Release Build:

Clean Work Tree, Development Build

Dirty Work Tree, Development Build

When locally running the build, you will now get the following:
I'm in the process of updating
README.md- If this is accepted, the new Release Workflow should be updated to something like: