Skip to content

Commit

Permalink
Defense in depth
Browse files Browse the repository at this point in the history
It seems we must rely on heuristics, so let's go all the way.

Needs more testing.
  • Loading branch information
twm committed Jul 28, 2024
1 parent d659ea0 commit 4fcdf4b
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 11 deletions.
33 changes: 25 additions & 8 deletions src/incremental/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,14 +374,13 @@ def _findPath(path, package): # type: (str, str) -> str
)


def _existing_version(path): # type: (str) -> Version
def _existing_version(version_path): # type: (str) -> Version
"""
Load the current version from {path}/_version.py.
Load the current version from a ``_version.py`` file.
"""
version_info = {} # type: Dict[str, Version]

versionpath = os.path.join(path, "_version.py")
with open(versionpath, "r") as f:
with open(version_path, "r") as f:
exec(f.read(), version_info)

return version_info["__version__"]
Expand Down Expand Up @@ -414,7 +413,19 @@ def _get_setuptools_version(dist): # type: (_Distribution) -> None
if not config or not config.opt_in:
return

dist.metadata.version = _existing_version(config.path).public()
try:
version = _existing_version(config.version_path)
except Exception:
return

# It's possible we're in the working directory of a *different* package!
# We do a case-insensitive comparison because the CLI tool historically
# required you to type the package name and not all maintainers
# capitalize the same.
if config.package.lower() != version.package.lower():
return

dist.metadata.version = version.public()


def _get_distutils_version(dist, keyword, value): # type: (_Distribution, object, object) -> None
Expand All @@ -435,8 +446,9 @@ def _get_distutils_version(dist, keyword, value): # type: (_Distribution, objec

for item in sp_command.find_all_modules():
if item[1] == "_version":
package_path = os.path.dirname(item[2])
dist.metadata.version = _existing_version(package_path).public()
version_path = os.path.join(
os.path.dirname(item[2]), "_version.py")
dist.metadata.version = _existing_version(version_path).public()
return

raise Exception("No _version.py found.") # pragma: no cover
Expand Down Expand Up @@ -475,8 +487,13 @@ class _IncrementalConfig:
path: str
"""Path to the package root"""

@property
def version_path(self): # type: () => str
"""Path of the ``_version.py`` file. May not exist."""
return os.path.join(self.path, "_version.py")


def _load_pyproject_toml(toml_path): # type: (str) -> Optional[_IncrementalConfig]
def _load_pyproject_toml(toml_path): # type: (str) -> _IncrementalConfig
"""
Load Incremental configuration from a ``pyproject.toml``
Expand Down
2 changes: 1 addition & 1 deletion src/incremental/newsfragments/106.bugfix
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Incremental could mis-identify that a project had opted in to version management.

If a ``pyproject.toml`` in the current directory contained a ``[project]`` table with a ``name`` key, but did not contain the opt-in ``[tool.incremental]`` table, Incremental would still treat the file as if the opt-in were present and attempt to validate the configuration. This could happen in contexts outside of packaging, such as when creating a virtualenv. When operating as a setuptools plugin Incremental now always requires the ``[tool.incremental]`` opt-in. Additionally, it suppresses any exceptions that occur while attempting to read ``pyproject.toml`` until it finds a valid ``[tool.incremental]`` table.
If a ``pyproject.toml`` in the current directory contained a ``[project]`` table with a ``name`` key, but did not contain the opt-in ``[tool.incremental]`` table, Incremental would still treat the file as if the opt-in were present and attempt to validate the configuration. This could happen in contexts outside of packaging, such as when creating a virtualenv. When operating as a setuptools plugin Incremental now always ignores invalid configuration, such as configuration that doesn't match the content of the working directory.
4 changes: 2 additions & 2 deletions src/incremental/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,11 @@ def _run(
):
raise ValueError("Only give --create")

versionpath = os.path.join(path, "_version.py")
if newversion:
from pkg_resources import parse_version

existing = _existing_version(path)
existing = _existing_version(versionpath)
st_version = parse_version(newversion)._version # type: ignore[attr-defined]

release = list(st_version.release)
Expand Down Expand Up @@ -212,7 +213,6 @@ def _run(
with open(filepath, "wb") as f:
f.write(content)

versionpath = os.path.join(path, "_version.py")
_print("Updating %s" % (versionpath,))
with open(versionpath, "wb") as f:
f.write(
Expand Down

0 comments on commit 4fcdf4b

Please sign in to comment.