Skip to content

Replace pkg_resources with importlib.metadata for version detection - #44

Merged
zacchiro merged 2 commits into
beancount:masterfrom
zacchiro:fix/replace-pkg-resources
Apr 21, 2026
Merged

zacchiro merged 2 commits into
beancount:masterfrom
zacchiro:fix/replace-pkg-resources

Conversation

@zacchiro

Copy link
Copy Markdown
Collaborator

No description provided.

Generate man pages from scdoc sources during setup.py execution instead of
requiring them to be pre-built. The data_files entry is moved from setup.cfg to
setup.py where it's computed dynamically:

- If scdoc is available, man pages are generated from .scd sources
- If scdoc is unavailable, man pages are simply omitted
- If man pages already exist (pre-built), they are used as-is

This fixes the 'can't copy docs/beancount2ledger.1: doesn't exist'
error when installing from git.

Fixes: beancount#42
pkg_resources (from setuptools) is not always available in modern Python
environments, causing 'ModuleNotFoundError: No module named pkg_resources'.
importlib.metadata is in the standard library since Python 3.8.
Copilot AI review requested due to automatic review settings April 20, 2026 08:28

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR updates version detection to avoid pkg_resources and adjusts packaging of man pages so they’re only included when present (optionally generating them from scdoc sources).

Changes:

  • Switch __version__ resolution from pkg_resources to importlib.metadata.
  • Move man-page data_files configuration out of setup.cfg into setup.py.
  • Add optional man-page generation via scdoc during setup.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
setup.py Adds optional scdoc-based man-page generation and dynamically supplies data_files to setuptools.setup().
setup.cfg Removes static [options.data_files] man-page entries (now handled in setup.py).
beancount2ledger/__init__.py Replaces pkg_resources-based version detection with importlib.metadata.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread setup.py
Comment on lines +11 to +38
def generate_man_pages():
"""Generate man pages from scdoc sources if scdoc is available."""
man_pages = {
"docs/beancount2ledger.1": "docs/beancount2ledger.1.scd",
"docs/beancount2ledger.5": "docs/beancount2ledger.5.scd",
}
for output, source in man_pages.items():
if os.path.exists(output):
continue
if not os.path.exists(source):
continue
try:
with open(source, "r") as src, open(output, "w") as dst:
subprocess.run(["scdoc"], stdin=src, stdout=dst, check=True)
except (FileNotFoundError, subprocess.CalledProcessError):
# scdoc not available or failed; skip man page generation
if os.path.exists(output):
os.remove(output)

def get_data_files():
"""Return data_files list with only man pages that exist."""
generate_man_pages()
data_files = []
if os.path.exists("docs/beancount2ledger.1"):
data_files.append(("share/man/man1", ["docs/beancount2ledger.1"]))
if os.path.exists("docs/beancount2ledger.5"):
data_files.append(("share/man/man5", ["docs/beancount2ledger.5"]))
return data_files

Copilot AI Apr 20, 2026

Copy link

Choose a reason for hiding this comment

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

This PR introduces man-page generation/packaging logic in setup.py (running scdoc and dynamically setting data_files), which doesn’t align with the PR title about version detection. If the intent is only to swap pkg_resources for importlib.metadata, consider moving the man-page changes into a separate PR or updating the PR title/description to reflect the packaging behavior change.

Copilot uses AI. Check for mistakes.
Comment thread setup.py
Comment on lines +30 to +37
def get_data_files():
"""Return data_files list with only man pages that exist."""
generate_man_pages()
data_files = []
if os.path.exists("docs/beancount2ledger.1"):
data_files.append(("share/man/man1", ["docs/beancount2ledger.1"]))
if os.path.exists("docs/beancount2ledger.5"):
data_files.append(("share/man/man5", ["docs/beancount2ledger.5"]))

Copilot AI Apr 20, 2026

Copy link

Choose a reason for hiding this comment

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

With docs/beancount2ledger.1 / .5 not present in the repo (only the .scd sources exist), builds performed without scdoc on PATH will now silently ship without installed man pages (since data_files becomes empty). If man pages are expected to be installed for end users, consider generating and committing the .1/.5 outputs as part of the release process (or failing the build when sources exist but generation is unavailable).

Copilot uses AI. Check for mistakes.
Comment on lines +14 to +22
from importlib.metadata import version, PackageNotFoundError

from .common import map_data
from .ledger import LedgerPrinter
from .hledger import HLedgerPrinter

try:
__version__ = get_distribution(__name__).version
except DistributionNotFound:
__version__ = version(__name__)
except PackageNotFoundError:

Copilot AI Apr 20, 2026

Copy link

Choose a reason for hiding this comment

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

importlib.metadata is only available in the stdlib on Python 3.8+. This package declares python_requires = >=3.6 (setup.cfg:39), so importing version, PackageNotFoundError from importlib.metadata will raise ModuleNotFoundError on 3.6/3.7 at import time. Use a conditional import fallback to importlib_metadata for older Pythons (and add an environment-marked dependency for <3.8), or bump python_requires to >=3.8 if dropping older versions is intended.

Copilot uses AI. Check for mistakes.
@zacchiro
zacchiro merged commit 3d32db2 into beancount:master Apr 21, 2026
4 of 13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants