From 644b2b8fa0835fddeb4afd9f73434d4692dc8063 Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Thu, 11 Dec 2025 11:04:12 +0100 Subject: [PATCH] Align Nix Python environment and add lazy CLI import - Switch flake package and dev shell to Python 3.11 to match pyproject - Ensure the python-with-deps environment is preferred on PATH in nix develop - Introduce a lightweight pkgmgr __init__ with lazy loading of pkgmgr.cli - Avoid pulling in CLI/config dependencies on plain `import pkgmgr`, fixing unit test imports and PyYAML availability in the Nix test containers https://chatgpt.com/share/693a9723-27ac-800f-a6c2-c1bcc91b7dff --- flake.nix | 16 +++++++++++----- src/pkgmgr/__init__.py | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/flake.nix b/flake.nix index a94bfc3..6d5ff7e 100644 --- a/flake.nix +++ b/flake.nix @@ -25,11 +25,13 @@ ########################################################################## packages = forAllSystems (system: let - pkgs = nixpkgs.legacyPackages.${system}; + pkgs = nixpkgs.legacyPackages.${system}; - # Single source of truth: "python3" from this nixpkgs revision - python = pkgs.python3; - pyPkgs = python.pkgs; + # Single source of truth for pkgmgr: Python 3.11 + # - Matches pyproject.toml: requires-python = ">=3.11" + # - Uses python311Packages so that PyYAML etc. are available + python = pkgs.python311; + pyPkgs = pkgs.python311Packages; in rec { pkgmgr = pyPkgs.buildPythonApplication { @@ -74,7 +76,8 @@ if pkgs ? ansible-core then pkgs.ansible-core else pkgs.ansible; - python = pkgs.python3; + # Use the same Python version as the package (3.11) + python = pkgs.python311; pythonWithDeps = python.withPackages (ps: [ ps.pip @@ -90,6 +93,9 @@ ]; shellHook = '' + # Ensure our Python with dependencies is preferred on PATH + export PATH=${pythonWithDeps}/bin:$PATH + # Ensure src/ layout is importable: # pkgmgr lives in ./src/pkgmgr export PYTHONPATH="$PWD/src:${PYTHONPATH:-}" diff --git a/src/pkgmgr/__init__.py b/src/pkgmgr/__init__.py index e69de29..2798285 100644 --- a/src/pkgmgr/__init__.py +++ b/src/pkgmgr/__init__.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Top-level pkgmgr package. + +We deliberately avoid importing heavy submodules (like the CLI) +on import to keep unit tests fast and to not require optional +dependencies (like PyYAML) unless they are actually used. + +Accessing ``pkgmgr.cli`` will load the CLI module lazily via +``__getattr__``. This keeps patterns like + + from pkgmgr import cli + +working as expected in tests and entry points. +""" + +from __future__ import annotations + +from importlib import import_module +from typing import Any + +__all__ = ["cli"] + + +def __getattr__(name: str) -> Any: + """ + Lazily expose ``pkgmgr.cli`` as attribute on the top-level package. + + This keeps ``import pkgmgr`` lightweight while still allowing + ``from pkgmgr import cli`` in tests and entry points. + """ + if name == "cli": + return import_module("pkgmgr.cli") + raise AttributeError(f"module 'pkgmgr' has no attribute {name!r}")