Skip to content

Conversation

@kompre
Copy link
Owner

@kompre kompre commented Dec 19, 2025

Summary

This release brings significant performance improvements to the CLI and fixes critical issues with Jupyter integration and CI/CD workflows.

Major Features

Performance Improvements

  • 44x faster CLI startup via lazy imports optimization (~45ms vs ~2000ms)
  • Heavy dependencies (sympy, pint, pipe_command) now lazy-loaded only when accessed
  • 34x CLI startup optimization for simple commands like keecas --version
  • All import patterns supported: import keecas, from keecas import u, from keecas import *

CLI Improvements

  • CLI entry point moved into keecas package for proper module resolution
  • Simplified __main__.py to defer to CLI and avoid code duplication

Bug Fixes

  • Fixed Jupyter kernel hang by removing stdout/stderr pipes that caused blocking
  • Fixed pull_request_target workflow for proper release automation
  • Added pull_request_target support with proper PR branch checkout

CI/CD Improvements

  • Fixed release workflow to use pull_request_target trigger
  • Improved GitHub Actions workflow for automated releases
  • Better branch checkout handling in CI

Breaking Changes

None - this release maintains full backward compatibility.

Testing

  • All tests passing
  • Verified CLI startup performance with time keecas --version
  • Tested Jupyter integration without kernel hangs
  • Verified lazy import behavior across all import patterns

🤖 Generated with Claude Code

claude and others added 26 commits December 17, 2025 23:09
Problem:
- Simple commands like `keecas --version` took 5.8 seconds
- CLI entry point loaded heavy dependencies (SymPy, Pint) unnecessarily
- Every CLI invocation imported keecas package which triggered __init__.py

Solution:
- Created lightweight wrapper `keecas_cli.py` outside keecas package
- Fast paths for common commands that don't need heavy dependencies:
  * --version/-V: Direct metadata access (5.8s -> 0.17s, ~34x faster)
  * --help/-h: Quick help without argparse (2.5s -> 0.14s, ~18x faster)
  * No args: Fast error message (2.5s -> 0.14s)
- Commands needing full functionality delegate to keecas.cli

Performance improvements:
- `keecas --version`: 5.834s -> 0.172s (~34x faster)
- `keecas --help`: 2.529s -> 0.142s (~18x faster)
- Other commands (config, edit) still work, load keecas when needed

Changes:
- Add src/keecas_cli.py: Lightweight CLI entry point with lazy imports
- Update pyproject.toml: Change entry point from keecas.cli:main to keecas_cli:main
…-08ew6

perf: optimize CLI startup time by 34x for simple commands
The subprocess.Popen() call was using PIPE for stdout/stderr but never
consuming the output. This causes the process to hang when the OS pipe
buffers fill up after extended Jupyter usage.

Solution: Let Jupyter output go directly to the terminal (stdout=None,
stderr=None) which prevents buffer deadlock and allows users to see
Jupyter logs.

Fixes #71

Co-authored-by: kompre <kompre@users.noreply.github.com>
Co-authored-by: kompre <kompre@users.noreply.github.com>
fix: prevent Jupyter kernel hang by removing stdout/stderr pipes
chore: bump version to 1.0.5b1 for test release
…ution

The lightweight CLI entry point (keecas_cli.py) was located outside the
keecas package at src/keecas_cli.py, which prevented it from being included
in the built package. This caused "ModuleNotFoundError: No module named 'keecas'"
when running CLI commands after installation.

Changes:
- Moved src/keecas_cli.py -> src/keecas/__main__.py (inside package)
- Updated pyproject.toml entry point: keecas_cli:main -> keecas.__main__:main
- Enables both 'keecas' command and 'python -m keecas' execution
- Preserves lightweight fast-path for --version and --help

Tested:
- keecas --version (fast, no heavy imports)
- keecas --help (fast, no heavy imports)
- keecas config path (full CLI with dependencies)
- python -m keecas --version (module execution)

Fixes module resolution issue from PR #70.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Restructure __init__.py to use __getattr__ for lazy loading of heavy
dependencies (sympy, pint, pipe_command). This dramatically reduces package
import time and makes CLI commands nearly instant.

Performance Improvements:
- import keecas: 0 sympy/pint imports (vs ALL before)
- keecas --version: 45ms (vs ~2000ms before) = 44x faster
- keecas config path: 88ms (vs ~2000ms+ before) = 23x faster

Implementation Details:
- ALL exports except __version__ are now lazy-loaded via __getattr__()
- Heavy dependencies (sympy, pint, pipe_command) only load when accessed
- Fixed config module collision (keecas.config package vs config object)
- Added hasattr check to distinguish config types properly
- Backward compatibility maintained - all import patterns work

Technical Challenges Solved:
1. Submodules (col_wrappers, formatters, display) import sympy at module level
   - Solution: Made ALL keecas exports lazy to prevent eager loading
2. Import "from .config.manager" adds config module to namespace
   - Solution: Check hasattr(globals()["config"], "display") for correct type
3. Variable scope issues in conditional imports
   - Solution: Use globals()["config"] instead of local config variable

Testing:
- All 221 tests pass
- Zero sympy/pint imports on basic "import keecas"
- CLI performance improved by 44x
- Notebooks and star imports work correctly

Documentation:
- Updated CLAUDE.md with lazy import guidelines
- Updated task proposal with implementation results

Files Modified:
- src/keecas/__init__.py: Complete restructure (217 lines)
- CLAUDE.md: Added performance/lazy import section
- _todo/proposal/cli-performance-lazy-imports.md: Added results

Fixes CLI performance issue where even --version took 2+ seconds.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Task successfully implemented with 44x performance improvement.
- import keecas: 45ms (vs 2000ms)
- All 221 tests passing
- Ready for test release

Moved to: _todo/completed/2025-12-18/
…tion

- Remove duplicate get_version() function
- Remove custom show_quick_help() function
- Defer all functionality to cli.main()
- Leverage lazy imports already implemented in cli.py
- Reduce file from 66 lines to 12 lines

Co-authored-by: kompre <kompre@users.noreply.github.com>
Co-authored-by: kompre <kompre@users.noreply.github.com>
refactor: simplify __main__.py to avoid code duplication
- Add pull_request_target trigger for PR opens/syncs with @claude mentions
- Upgrade permissions to contents:write and pull-requests:write
- Add PR details extraction step for comment-based events
- Fix checkout to use PR head SHA instead of base branch
- Support fork PRs with repository parameter
- Increase fetch-depth to 0 for full history access

This ensures Claude Code Action runs on the correct PR branch context,
enabling it to make changes and push commits to PRs.
- Change trigger from pull_request to pull_request_target
- Ensures workflow runs in base repo context after merge
- Fixes issue where release was building from pre-merge state
- Maintains proper access to secrets for PyPI publishing

With pull_request trigger, the workflow runs in PR context before merge
completes. Using pull_request_target ensures we build and release the
actual merged code on the base branch.
The pull_request_target fix was needed for release.yml, not claude.yml.
Claude workflow permissions are intentionally limited for security.
fix: add pull_request_target support and proper PR branch checkout
@kompre kompre added release Production release to PyPI (stable versions) code-review Requires code review before merge labels Dec 19, 2025
@claude
Copy link

claude bot commented Dec 19, 2025

Code Review: Release v1.1.0

Summary

This PR introduces significant performance improvements through lazy imports and fixes critical Jupyter integration issues. The changes are well-implemented with strong adherence to the project's conventions documented in CLAUDE.md.

Positive Aspects

1. Excellent Performance Optimization

  • 44x faster CLI startup (~45ms vs ~2000ms) is a massive improvement
  • Lazy loading via getattr() is the Pythonic approach for this use case
  • Smart caching strategy prevents re-importing on subsequent access
  • All import patterns properly supported: import keecas, from keecas import u, from keecas import *

2. Critical Bug Fix

  • Jupyter kernel hang fix by removing stdout/stderr pipes is correct
  • Using stdout=None, stderr=None allows direct terminal output, preventing buffer deadlock
  • This was a blocking issue for users, excellent catch

3. Good Documentation

  • CLAUDE.md updated with clear lazy import guidelines
  • Performance constraints documented for future maintainers
  • Comprehensive task completion notes in _todo/completed/

4. Proper Workflow

  • Release workflow fix (pull_request_target) ensures proper PR branch checkout
  • Follows project conventions (dev to main flow)

Issues and Concerns

1. Missing Test Coverage for Lazy Loading (High Priority)

The lazy loading mechanism is a critical change but lacks dedicated tests. Missing test scenarios include verifying no sympy/pint imports on basic import keecas, testing that version is accessible without heavy imports, verifying lazy attributes are cached after first access, and testing all import patterns.

Recommend creating tests/test_lazy_imports.py with comprehensive tests for the lazy loading mechanism.

2. Config Collision Handling Complexity (Medium Priority)

The config collision check in init.py is repeated 5 times (DRY violation). Consider extracting to a helper function _ensure_config() to reduce duplication and improve maintainability.

3. CLI Entry Point Change (Low Priority - Clarification Needed)

The change from keecas.cli:main to keecas.main:main adds an extra indirection layer. Can you clarify what specific issue this fixes? Both approaches should work correctly.

4. Release Workflow Security (Medium Priority)

The pull_request_target trigger is safe here because it only runs on merge to protected main branch. However, recommend adding a comment in the workflow explaining the security model to prevent future misuse.

Minor Issues

  • The all list has inconsistent inline comments
  • Version bump 1.0.4 to 1.1.0 is correct per SemVer (backward compatible)
  • Consider adding performance regression tests in CI to verify startup time stays under 100ms

Overall Assessment

Rating: APPROVE with required changes (after addressing issues 1-2)

This is a high-quality PR that solves real performance and usability problems. The lazy loading implementation is sound, and the Jupyter fix addresses a critical bug. The main gaps are test coverage for the lazy loading mechanism and code quality for config collision handling.

Once these are addressed, this is ready to merge. Excellent work on the performance optimization!

- Add comprehensive lazy loading tests (17 tests)
  - Test import performance and heavy dependency isolation
  - Test caching, dependency resolution, and import patterns
  - All tests pass, verify no sympy/pint on basic import

- Refactor config collision handling to reduce DRY violation
  - Extract repeated pattern into _ensure_config_loaded() helper
  - Replace 5 occurrences with single function call
  - Reduces code from 223 to 209 lines, improves maintainability

- Add comprehensive security documentation to release workflow
  - Explain why pull_request_target is safe for releases
  - Document security model for future maintainers
  - Clarify that only merged code is published

All 238 tests pass. CLI startup time verified at ~51ms (< 100ms threshold).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@kompre kompre merged commit 3675f33 into main Dec 19, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

code-review Requires code review before merge release Production release to PyPI (stable versions)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants