Fix BIP-39 wordlist not found when installed via pip/AUR

Move bip39-words.txt into package data directory and use
importlib.resources for reliable path resolution. The wordlist
was previously only included in sdist but not in wheel builds.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
adlee-was-taken
2026-01-24 01:12:45 -05:00
parent 398a359778
commit 9f0e0afeb6
4 changed files with 2079 additions and 5 deletions

View File

@@ -114,6 +114,13 @@ include = [
[tool.hatch.build.targets.wheel] [tool.hatch.build.targets.wheel]
packages = ["src/stegasoo", "frontends"] packages = ["src/stegasoo", "frontends"]
[tool.hatch.build.targets.wheel.sources]
"src" = ""
# Include data files in the wheel
[tool.hatch.build.targets.wheel.force-include]
"src/stegasoo/data/bip39-words.txt" = "stegasoo/data/bip39-words.txt"
[tool.pytest.ini_options] [tool.pytest.ini_options]
testpaths = ["tests"] testpaths = ["tests"]
python_files = ["test_*.py"] python_files = ["test_*.py"]

View File

@@ -25,6 +25,7 @@ BREAKING CHANGES in v3.2.0:
- Renamed day_phrase → passphrase throughout codebase - Renamed day_phrase → passphrase throughout codebase
""" """
import importlib.resources
from pathlib import Path from pathlib import Path
# ============================================================================ # ============================================================================
@@ -177,15 +178,32 @@ BATCH_OUTPUT_SUFFIX = "_encoded"
def get_data_dir() -> Path: def get_data_dir() -> Path:
"""Get the data directory path.""" """Get the data directory path.
# Check multiple locations
Checks locations in order:
1. Package data (installed via pip/wheel) using importlib.resources
2. Development layout (src/stegasoo -> project root/data)
3. Docker container (/app/data)
4. Current working directory fallbacks
"""
# Try package data first (works when installed via pip)
try:
pkg_data = importlib.resources.files("stegasoo.data")
# Check if the package data directory exists and has our files
if (pkg_data / "bip39-words.txt").is_file():
# Return as Path - importlib.resources.files returns a Traversable
return Path(str(pkg_data))
except (ModuleNotFoundError, TypeError):
pass
# Fallback to file-based locations
# From src/stegasoo/constants.py: # From src/stegasoo/constants.py:
# .parent = src/stegasoo/ # .parent = src/stegasoo/
# .parent.parent = src/ # .parent.parent = src/
# .parent.parent.parent = project root (where data/ lives) # .parent.parent.parent = project root (where data/ lives)
candidates = [ candidates = [
Path(__file__).parent / "data", # Installed package (stegasoo/data/)
Path(__file__).parent.parent.parent / "data", # Development: src/stegasoo -> project root Path(__file__).parent.parent.parent / "data", # Development: src/stegasoo -> project root
Path(__file__).parent / "data", # Installed package
Path("/app/data"), # Docker Path("/app/data"), # Docker
Path.cwd() / "data", # Current directory Path.cwd() / "data", # Current directory
Path.cwd().parent / "data", # One level up from cwd Path.cwd().parent / "data", # One level up from cwd
@@ -196,8 +214,8 @@ def get_data_dir() -> Path:
if path.exists(): if path.exists():
return path return path
# Default to first candidate # Default to package data path for clearer error messages
return candidates[0] return Path(__file__).parent / "data"
def get_bip39_words() -> list[str]: def get_bip39_words() -> list[str]:

View File

@@ -0,0 +1 @@
# Package data directory for stegasoo

File diff suppressed because it is too large Load Diff