Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
.idea
*.DS_Store

# setuptools_scm generated version file (may appear in any subpackage)
tabcmd/**/_version.py
tabcmd/_version.py

# python build files
build/
dist/
Expand Down
8 changes: 8 additions & 0 deletions dodo.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,14 @@ def write_for_pyinstaller():
version=numeric_version,
)

# Write tabcmd/_version.py so PyInstaller bundles the correct version string.
# setuptools_scm only writes this file during pip install/build; doit version
# may run in CI without a prior install step.
version_file = os.path.join("tabcmd", "_version.py")
with open(version_file, "w", encoding="utf-8") as f:
f.write("# generated by doit version -- do not edit\n")
f.write("version = {!r}\n".format(version))

return {
"actions": [write_for_pyinstaller],
"verbosity": 2,
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ requires = ["build", "setuptools", "setuptools_scm"]
build-backend = "setuptools.build_meta"
[tool.setuptools_scm]
local_scheme = "no-local-version" # require pypi supported versions always
write_to = "tabcmd/_version.py"
[tool.setuptools]
packages = ["tabcmd"]
[tool.setuptools.package-data]
Expand Down
7 changes: 6 additions & 1 deletion tabcmd/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,9 @@
try:
version = get_version("tabcmd")
except PackageNotFoundError:
version = "2.0.0"
# importlib.metadata is unavailable in PyInstaller bundles; fall back to the
# _version.py file that setuptools_scm writes at build time.
try:
from tabcmd._version import version
except ImportError:
version = "0.0"
33 changes: 33 additions & 0 deletions tests/commands/test_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import ast
import re
import unittest
from pathlib import Path

ROOT = Path(__file__).parent.parent.parent


class VersionConsistencyTests(unittest.TestCase):
def test_version_py_fallback_matches_pyproject_write_to(self):
"""The fallback import in version.py must match the write_to path in pyproject.toml."""
pyproject = (ROOT / "pyproject.toml").read_text(encoding="utf-8")
match = re.search(r'write_to\s*=\s*"([^"]+)"', pyproject)
self.assertIsNotNone(match, "write_to not found in [tool.setuptools_scm] in pyproject.toml")
assert match is not None

write_to_path = match.group(1) # e.g. "tabcmd/_version.py"
expected_module = write_to_path.replace("/", ".").removesuffix(".py") # e.g. "tabcmd._version"

version_py = (ROOT / "tabcmd" / "version.py").read_text(encoding="utf-8")
tree = ast.parse(version_py)

fallback_modules = []
for node in ast.walk(tree):
if isinstance(node, ast.ImportFrom) and node.module:
fallback_modules.append(node.module)

self.assertIn(
expected_module,
fallback_modules,
"version.py does not import from '{}' (the write_to path in pyproject.toml). "
"If write_to was changed, update the fallback import in tabcmd/version.py.".format(expected_module),
)
Loading