google/grumpy
Grumpy is a Python to Go source code transcompiler and runtime.
Stale — last commit 4y ago
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
last commit was 4y ago; Scorecard "Branch-Protection" is 0/10
- ⚠Stale — last commit 4y ago
- ⚠Scorecard: marked unmaintained (0/10)
- ⚠Scorecard: default branch unprotected (0/10)
- ✓7 active contributors
- ✓Distributed ownership (top contributor 45% of recent commits)
- ✓Apache-2.0 licensed
- ✓CI configured
- ✓Tests present
What would improve this?
- →Deploy as-is Mixed → Healthy if: 1 commit in the last 180 days
Computed from maintenance signals — commit recency, contributor breadth, bus factor, license, CI, tests, cross-checked against OpenSSF Scorecard
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Safe to depend on" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/google/grumpy)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card
This card auto-renders when someone shares https://repopilot.app/r/google/grumpy on X, Slack, or LinkedIn.
Ask AI about google/grumpy
Grounded in the actual source code. Pick a starter question or write your own.
Onboarding doc
Onboarding: google/grumpy
Generated by RepoPilot · 2026-06-27 · Source
🎯Verdict
WAIT — Stale — last commit 4y ago
- 7 active contributors
- Distributed ownership (top contributor 45% of recent commits)
- Apache-2.0 licensed
- CI configured
- Tests present
- ⚠ Stale — last commit 4y ago
- ⚠ Scorecard: marked unmaintained (0/10)
- ⚠ Scorecard: default branch unprotected (0/10)
<sub>Computed from maintenance signals — commit recency, contributor breadth, bus factor, license, CI, tests, cross-checked against OpenSSF Scorecard</sub>
⚡TL;DR
Grumpy is a Python-to-Go source code transcompiler that converts Python 2.7 source code into Go source code, which then compiles to native binaries. Rather than using a VM and bytecode interpretation like CPython, Grumpy generates direct Go code that calls the Grumpy runtime library (analogous to the Python C API), enabling static compilation and native performance without the overhead of a dynamic runtime. Monolithic structure: compiler/ contains the transcompilation pipeline (expr.py for expressions, stmt.py for statements, block.py for control flow, expr_visitor.py for AST traversal); lib/ holds runtime implementations of Python builtins and stdlib modules in Python (which themselves get transpiled); benchmarks/ contains performance test cases; the Makefile orchestrates build and test targets.
👥Who it's for
Python developers who want to distribute performance-critical applications as standalone native binaries without shipping a Python interpreter, and Go developers who want to reuse existing Python codebases or gradually migrate Python logic to Go. Maintainers of Python 2.7 codebases seeking an alternative to EOL CPython for deployment.
🌱Maturity & risk
Actively developed but incomplete: the project has CI via Travis CI (.travis.yml present), test coverage across compiler modules (expr_visitor_test.py, stmt_test.py, util_test.py, itertools_test.py, etc.), and a clear roadmap of missing features documented in the README. However, critical features like old-style classes, exec/eval, and C extensions are explicitly non-goals, and many stdlib modules remain unimplemented. Verdict: experimental/usable for specific workloads, not production-ready for arbitrary Python 2.7 code.
Heavy reliance on Python 2.7 (officially EOL since 2020) with no Python 3 support planned—new code targeting this is inherently legacy-bound. The transcompiler is feature-incomplete (no dynamic code execution, no old-style classes), meaning a subset of valid Python 2.7 will silently fail or compile incorrectly. Single-maintainer risk (Google-backed but narrow ownership evident from AUTHORS.md), and the inability to support C extensions cuts off a large ecosystem dependency.
Active areas of work
Unable to determine from file list alone—no git log, commit history, or recent PR data visible. The presence of comprehensive tests (block_test.py, expr_visitor_test.py, imputil_test.py, os_test.py, etc.) and a well-structured compiler pipeline suggest active maintenance, but .travis.yml indicates CI integration rather than frequency of updates.
🚀Get running
Clone and build: git clone https://github.com/google/grumpy.git && cd grumpy && make (inferred from Makefile presence and Go-heavy codebase). Then examine compiler/__init__.py as the entry point and try transpiling a simple .py file using the compiled grumpy binary.
Daily commands:
make (from Makefile) to build the compiler, then grumpy <script.py> to transpile. For tests: make test runs the test suite across compiler/ and lib/.
🗺️Map of the codebase
compiler/expr.py— Core expression compiler that transpiles Python AST nodes to Go code; fundamental to understanding how Python constructs become Gocompiler/stmt.py— Statement compiler handling control flow, assignments, and function definitions; essential for grasping statement-level transpilationruntime/core.go— Core Go runtime providing base object model and fundamental operations that all transpiled Python code depends oncompiler/block.py— Block management and code generation orchestration; coordinates how Python scopes translate to Go function callsruntime/dict.go— Go implementation of Python dict type; demonstrates the pattern for implementing Python built-in types in Golib/__builtin__.py— Python standard library builtins that get compiled to Go; shows which Python features are available in Grumpycompiler/imputil.py— Import system and module loading logic; critical for understanding how multi-module Grumpy programs are structured
🧩Components & responsibilities
- compiler/expr.py (ExprCompiler) — Visits expression
🛠️How to make changes
Add support for a new Python built-in function
- Implement the function logic in Python (using Go builtins where needed) (
lib/__builtin__.py) - Add Go runtime implementation if the function requires special handling (
runtime/core.go) - Update the compiler's expression visitor to recognize and emit the function call (
compiler/expr.py) - Add unit tests for the new built-in in the appropriate test file (
lib/__builtin__.py)
Implement a new Python built-in type (e.g., tuple improvements)
- Create the Go type definition with required methods (Hash, Eq, Str, etc.) (
runtime/object.go) - Implement indexing, slicing, and iteration via Seq interface (
runtime/seq.go) - Add type operations (conversion, type checking) in builtin_types.go (
runtime/builtin_types.go) - Update compiler expression visitor to handle constructor calls and literals (
compiler/expr.py) - Write comprehensive tests (
runtime/object_test.go)
Port a new Python standard library module
- Create the module file in lib/ mirroring the Python 2.7 API (
lib/newmodule.py) - Register the module with the import system (
compiler/imputil.py) - Implement native Go functions for performance-critical parts (
runtime/native.go) - Add tests verifying compatibility with CPython 2.7 (
lib/newmodule_test.py)
Fix a compiler code generation issue
- Add a failing test case demonstrating the issue (
compiler/expr_test.py or compiler/stmt_test.py) - Identify which visitor method handles the problematic Python construct (
compiler/expr.py or compiler/stmt.py) - Update the Go code generation logic in the appropriate file (
compiler/expr.py or compiler/stmt.py) - Verify the generated Go code compiles and runs correctly (
compiler/block.py)
🔧Why these technologies
- Python AST + Go Code Generation — Allows static compilation to native code while preserving Python semantics; no VM overhead
- Go Runtime Library — Provides efficient, garbage-collected implementation of Python object model; leverages Go's concurrency and performance
- Visitor Pattern for Compilation — Clean separation of AST traversal from code generation; enables incremental extension for new Python constructs
⚖️Trade-offs already made
-
Compile to Go source instead of directly to machine code
- Why: Leverages Go's mature compiler toolchain and ecosystem; simplifies cross-compilation and debugging
- Consequence: Slower compilation cycle than direct codegen; requires Go toolchain dependency
-
Python 2.7 only, not Python 3
- Why: Narrower target reduces implementation scope and complexity
- Consequence: Cannot run modern Python code; no unicode by default; legacy syntax (print statement, etc.)
-
No support for eval/exec/compile
- Why: Requires runtime compilation which contradicts static compilation model
- Consequence: Dynamic code execution patterns unavailable; metaprogramming severely limited
-
Module system based on static imports
- Why: Enables compile-time dependency resolution and dead code elimination
- Consequence: No dynamic imports; modules must be known at compile time
🚫Non-goals (don't propose these)
- Dynamic code execution (eval, exec, compile)
- Full compatibility with CPython C API and extension modules
- Python 3 support
- Interactive REPL
- Bytecode generation or interpretation
🪤Traps & gotchas
Python 2.7-only (no Python 3 support—many modern libraries won't work). Dynamic features (exec, eval, compile) are explicitly unsupported and will fail silently or produce incorrect code. Old-style classes not supported—only new-style classes work. C extensions cannot be imported, cutting off numpy, scipy, and most native modules. No virtual environment support evident—assumes global install or careful PATH management. The compiler requires the Go toolchain installed (not just Python) to produce runnable binaries.
🏗️Architecture
💡Concepts to learn
- Source-to-source compilation (transpilation) — Grumpy is a transcompiler, not a compiler—it converts Python AST to Go source code rather than bytecode, then relies on Go's compiler for native code. Understanding the multi-stage pipeline (Python AST → Grumpy IR → Go source → Go binary) is critical to debugging and extending it.
- Abstract Syntax Tree (AST) traversal via Visitor pattern — The expr_visitor.py and expr.py files implement the Visitor pattern to walk Python's ast.Module and convert nodes to Go code. Extending Grumpy requires understanding how Python's ast module represents code and how visitors transform it.
- Runtime library / language binding layer — Grumpy's runtime (Go code in lib/ that gets imported into generated code) is analogous to the Python C API but for Go. It provides the type system, method dispatch, and builtin implementations that transpiled code relies on. Changes to the runtime affect all generated code.
- Basic blocks and control flow graphs (CFG) — compiler/block.py implements a basic block IR used to represent loops, branches, and exception handling before lowering to Go. Understanding blocks is essential for implementing new control flow features (try/except, finally, etc.).
- Static linking and module resolution — Grumpy statically links all Python modules into a single Go binary (via compiler/imputil.py). Unlike CPython's dynamic import at runtime, Grumpy must resolve all imports at compile time, which limits dynamic features but enables optimization.
- Python 2.7 semantics (EOL language spec) — Grumpy targets Python 2.7 specifically (officially EOL since 2020). Understanding Python 2 vs 3 differences (print statement vs function, unicode handling, integer division, etc.) is critical to writing correct transcompiler logic.
- Go goroutines and concurrency primitives — Transpiled Python code runs on Go's runtime with goroutines and channels available. Features like thread.py and generator support depend on mapping Python's threading/iteration model to Go's concurrency model.
🔗Related repos
jython/jython— Python-to-Java transcompiler with similar goal (Python on non-CPython runtime) but produces JVM bytecode instead of native code; shows alternative approach to Python portabilitypypy/pypy— Alternative Python implementation with JIT compilation and translation toolchain; addresses similar performance goals but with a complete VM rather than static compilationgolang/go— The target language and runtime for Grumpy-generated code; understanding Go semantics, goroutines, and the standard library is essential for working on the runtime librarycython/cython— Python-to-C transcompiler for performance; similar goal (compiled Python) but targets C and maintains Python semantics more closely, vs Grumpy's static Go approachgoogle/pytype— Google's Python type inference tool; could complement Grumpy by providing static type hints for safer transpilation
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive runtime tests for builtin_types.go
The file runtime/builtin_types.go exists but runtime/builtin_types_test.go appears minimal or incomplete. Given that Grumpy implements Python builtins as Go types (bool, int, float, string, etc.), this is a critical surface area. A new contributor could systematically add test cases covering edge cases for type conversions, comparisons, and operations that Python developers expect, which would improve reliability of the transcompiled output.
- [ ] Review runtime/builtin_types.go to identify all exported functions and type methods
- [ ] Add test cases in runtime/builtin_types_test.go for type constructors (e.g., creating Bool, Int, Float from various inputs)
- [ ] Add test cases for type coercion and comparison operators between different builtin types
- [ ] Add test cases for edge cases like overflow, underflow, and special values (NaN, Inf)
Add missing stdlib library wrappers (lib/subprocess.py and lib/json.py)
The lib/ directory contains Python stdlib wrappers for modules like os, sys, math, itertools, and random. However, common Python modules like subprocess, json, and re are missing. These are heavily used in real-world Python code. A new contributor could implement stubs or partial wrappers for these modules to expand Grumpy's stdlib coverage and improve transcompilation success rate for typical Python scripts.
- [ ] Create lib/json.py with at least loads() and dumps() functions wrapping Go's encoding/json
- [ ] Create lib/subprocess.py with basic Popen and call() functions
- [ ] Add corresponding unit tests in lib/json_test.py and lib/subprocess_test.py following the pattern of existing tests like lib/os_test.py
- [ ] Document any limitations in lib/README.md for these new modules
Implement compiler tests for class and inheritance constructs
The compiler/ directory has expr_visitor_test.py, stmt_test.py, and block_test.py, but there's no dedicated test file for class definitions and inheritance—core Python OOP features. Looking at the file structure, class compilation likely touches stmt.py and expr.py. A new contributor could add compiler/class_test.py to comprehensively test class definition, method compilation, inheritance chains, and super() calls, which would catch transcompilation bugs early.
- [ ] Review compiler/stmt.py and compiler/expr.py to understand class AST node handling
- [ ] Create compiler/class_test.py with test cases for simple class definitions
- [ ] Add test cases for class inheritance, method overriding, and init compilation
- [ ] Add test cases for super() calls and multiple inheritance scenarios
- [ ] Run tests against expected generated Go code to ensure correctness
🌿Good first issues
- Add missing string methods: The lib/builtin.py has partial str class implementation; audit and add missing methods like str.partition(), str.rpartition(), str.zfill() with corresponding test cases in *_test.py
- Implement missing operators in expr.py: The README lists 'a handful of operators' not yet supported; identify which (bitwise, comparison, etc.) and add AST node handlers with expr_test.py coverage
- Expand os/ module coverage: lib/os/init.py and lib/os/path.py are stubbed; implement more POSIX functions (getcwd, listdir, stat wrappers) matching CPython behavior, following the test pattern in os_test.py
⭐Top contributors
Click to expand
Top contributors
- @trotterdylan — 45 commits
- @m4ns0ur — 24 commits
- [@Dylan Trotter](https://github.com/Dylan Trotter) — 18 commits
- @corona10 — 10 commits
- @alanjds — 1 commits
📝Recent commits
Click to expand
Recent commits
3ec8795— runtime: Fix complain about linting and Go 1.9 compiler error. (#384) (corona10)2c8ff4b— Fix string literal imports w/ periods (#377) (trotterdylan)50cbc8b— Remove some dead import code (trotterdylan)205bbd3— Generate native package wrappers (trotterdylan)9d80504— Support importing string literal mod names (trotterdylan)6bdfc4b— Add dummy_thread module (#372) (m4ns0ur)7f4857e— Add Queue module (trotterdylan)85d6bc1— Fix dir() for modules and types (trotterdylan)9b8d487— Make break statements trigger finally blocks (trotterdylan)e19dab7— Make stdlib tests depend on traceback lib (trotterdylan)
🔒Security observations
Grumpy's security posture is generally good for a compiler/runtime project. The main risks are: (1) Intentional limitations on dynamic code execution that may not be properly enforced, (2) Potential path traversal or privilege escalation risks in OS/syscall modules that require deeper testing, and (3) Missing visibility into CI/CD and dependency management practices. The project appears well-structured and maintained (Google-backed), but runtime security controls for file operations and system calls should be explicitly validated. No obvious hardcoded secrets, SQL injection, or XSS vectors were identified in the provided file structure.
- Medium · Dynamic Code Execution Limitations Not Enforced —
README.md, runtime/core.go. The README explicitly states that Grumpy does not supportexec,eval, andcompiledynamic features. However, there is no evidence in the provided file structure that these are explicitly blocked or sandboxed at the runtime level. If a transcompiled Python program somehow attempts to use these features, the behavior is undefined and could lead to unexpected runtime errors or security issues. Fix: Implement explicit runtime checks to raise appropriate exceptions when unsupported dynamic code execution features are attempted. Document this limitation prominently in error messages. - Low · Test Coverage for Security-Sensitive Modules —
lib/_syscall.py, lib/os/. Security-sensitive modules such aslib/_syscall.py,lib/os/__init__.py, andlib/os/path.pyare present, but there is limited visibility into the security testing of file operations, system calls, and path traversal prevention. The_syscall.pymodule suggests direct system call wrapping which could be a vector for privilege escalation or unauthorized system access. Fix: Implement comprehensive security test cases for all OS and syscall modules. Add path traversal prevention tests in os/path operations. Ensure proper input validation for all system calls. - Low · Missing Security Configuration in CI/CD —
.travis.yml. The.travis.ymlfile exists but content is not provided. Travis CI configurations may contain exposed environment variables, insecure build steps, or missing security scanning steps. Fix: Review and harden the CI/CD configuration. Ensure: (1) No credentials are hardcoded, (2) Security scanning tools are integrated, (3) Dependency vulnerability scanning is enabled, (4) Build artifacts are properly signed. - Low · Incomplete Dependency Information —
Project root. No package dependency files (requirements.txt, setup.py, go.mod, etc.) were provided in the analysis. This prevents assessment of transitive dependency vulnerabilities and version pinning issues. Fix: Provide and analyze all dependency files. Use tools likesafetyfor Python dependencies andnancyfor Go dependencies to identify known vulnerabilities. Pin all dependencies to specific versions.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/google/grumpy shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live google/grumpy
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/google/grumpy.
What it runs against: a local clone of google/grumpy — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in google/grumpy | Confirms the artifact applies here, not a fork |
| 2 | License is still Apache-2.0 | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 1607 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of google/grumpy. If you don't
# have one yet, run these first:
#
# git clone https://github.com/google/grumpy.git
# cd grumpy
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of google/grumpy and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "google/grumpy(\\.git)?\\b" \\
&& ok "origin remote is google/grumpy" \\
|| miss "origin remote is not google/grumpy (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
&& ok "license is Apache-2.0" \\
|| miss "license drift — was Apache-2.0 at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "compiler/expr.py" \\
&& ok "compiler/expr.py" \\
|| miss "missing critical file: compiler/expr.py"
test -f "compiler/stmt.py" \\
&& ok "compiler/stmt.py" \\
|| miss "missing critical file: compiler/stmt.py"
test -f "runtime/core.go" \\
&& ok "runtime/core.go" \\
|| miss "missing critical file: runtime/core.go"
test -f "compiler/block.py" \\
&& ok "compiler/block.py" \\
|| miss "missing critical file: compiler/block.py"
test -f "runtime/dict.go" \\
&& ok "runtime/dict.go" \\
|| miss "missing critical file: runtime/dict.go"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 1607 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~1577d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/google/grumpy"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.
Similar Go repos
Other mixed-signal Go repos by stars.
More from google
See all →Embed this chat in your README →
Drop this iframe anywhere — the widget runs against the same live analysis cache as the main app.
<iframe src="https://repopilot.app/embed/google/grumpy" width="100%" height="500" style="border:1px solid #d0d7de; border-radius:8px;" allow="microphone" loading="lazy" ></iframe>