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}")