From 715f2a79be46bc316d23e77ee2fa17ca90a03158 Mon Sep 17 00:00:00 2001 From: Xubin Ren Date: Wed, 8 Apr 2026 15:45:24 +0000 Subject: [PATCH] fix(version): fall back to pyproject in source checkouts Keep importlib.metadata as the primary source for installed packages, but avoid PackageNotFoundError when nanobot is imported directly from a source tree. Made-with: Cursor --- nanobot/__init__.py | 24 ++++++++++++++++++-- tests/test_package_version.py | 41 +++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 tests/test_package_version.py diff --git a/nanobot/__init__.py b/nanobot/__init__.py index 93be6664c..0bce848df 100644 --- a/nanobot/__init__.py +++ b/nanobot/__init__.py @@ -2,9 +2,29 @@ nanobot - A lightweight AI agent framework """ -from importlib.metadata import version as _pkg_version +from importlib.metadata import PackageNotFoundError, version as _pkg_version +from pathlib import Path +import tomllib -__version__ = _pkg_version("nanobot-ai") + +def _read_pyproject_version() -> str | None: + """Read the source-tree version when package metadata is unavailable.""" + pyproject = Path(__file__).resolve().parent.parent / "pyproject.toml" + if not pyproject.exists(): + return None + data = tomllib.loads(pyproject.read_text(encoding="utf-8")) + return data.get("project", {}).get("version") + + +def _resolve_version() -> str: + try: + return _pkg_version("nanobot-ai") + except PackageNotFoundError: + # Source checkouts often import nanobot without installed dist-info. + return _read_pyproject_version() or "0.1.5" + + +__version__ = _resolve_version() __logo__ = "🐈" from nanobot.nanobot import Nanobot, RunResult diff --git a/tests/test_package_version.py b/tests/test_package_version.py new file mode 100644 index 000000000..4780757d6 --- /dev/null +++ b/tests/test_package_version.py @@ -0,0 +1,41 @@ +from __future__ import annotations + +import subprocess +import sys +import textwrap +from pathlib import Path + +import tomllib + + +def test_source_checkout_import_uses_pyproject_version_without_metadata() -> None: + repo_root = Path(__file__).resolve().parents[1] + expected = tomllib.loads((repo_root / "pyproject.toml").read_text(encoding="utf-8"))["project"][ + "version" + ] + script = textwrap.dedent( + f""" + import sys + import types + + sys.path.insert(0, {str(repo_root)!r}) + fake = types.ModuleType("nanobot.nanobot") + fake.Nanobot = object + fake.RunResult = object + sys.modules["nanobot.nanobot"] = fake + + import nanobot + + print(nanobot.__version__) + """ + ) + + proc = subprocess.run( + [sys.executable, "-S", "-c", script], + capture_output=True, + text=True, + check=False, + ) + + assert proc.returncode == 0, proc.stderr + assert proc.stdout.strip() == expected