# pyan-unused-functions
A Python static analysis tool to find unused functions in your codebase using AST (Abstract Syntax Tree) parsing. Perfect for CLI usage and CI/CD pipelines with GitHub Actions.
## Features
- 🔍 **Accurate Detection**: Uses Python's built-in AST module for reliable parsing
- 🚀 **Fast Analysis**: Efficiently scans entire codebases
- 📊 **Detailed Reports**: Shows all defined functions and their usage
- 🎯 **Smart Filtering**: Automatically skips private functions (starting with `_`)
- 🔄 **Class-Aware**: Handles both module-level functions and class methods
- ⚡ **Async Support**: Recognizes async functions and methods
- 🤖 **CI/CD Ready**: Easy integration with GitHub Actions and other CI systems
- 🛠️ **Lightweight**: Minimal dependencies (requires pyan3 for enhanced analysis)
## Installation
Install from PyPI:
```bash
pip install pyan-unused-functions
```
This will automatically install the required dependency: `pyan3==1.1.1`
Or install from source:
```bash
git clone https://github.com/yourusername/pyan-unused-functions.git
cd pyan-unused-functions
pip install -e .
```
## Usage
> 💡 **Quick Start**: Check the [`examples/`](examples/) directory for ready-to-use GitHub Actions workflows and Git hooks!
### Command Line
Analyze a directory:
```bash
pyan-unused-functions /path/to/your/code
```
Analyze current directory:
```bash
pyan-unused-functions .
```
### As a Python Module
```python
from pathlib import Path
from pyan_unused_functions import analyze_codebase, find_unused_functions
# Analyze a codebase
root_path = Path("./my_project")
defined_functions, called_functions = analyze_codebase(root_path)
# Find unused functions
unused = find_unused_functions(defined_functions, called_functions)
print(f"Found {len(unused)} unused functions:")
for func in sorted(unused):
print(f" {func}")
```
## Example Output
```
Analyzing Python code in: ./my_project
Analyzing 45 Python files...
=== Analysis Results ===
Total functions defined: 127
Total function calls found: 98
Potentially unused functions: 12
=== Potentially Unused Functions ===
module_a.helper_function
module_b.old_implementation
utils.deprecated_method
...
Note: This analysis may have false positives for:
- Functions called dynamically (getattr, exec, etc.)
- Functions used in decorators or metaclasses
- Functions called from other modules not analyzed
- Entry points, CLI commands, or framework callbacks
```
## How It Works
1. **Discovery**: Recursively finds all Python files in the specified directory
2. **Parsing**: Uses AST to parse each file and extract function definitions and calls
3. **Analysis**: Compares defined functions against called functions
4. **Reporting**: Identifies functions that are defined but never called
## Limitations
This tool provides **static analysis** and may report false positives in the following cases:
- **Dynamic calls**: Functions invoked via `getattr()`, `exec()`, `eval()`, etc.
- **Decorator usage**: Functions used as decorators or in metaclasses
- **External calls**: Functions called from modules outside the analyzed directory
- **Framework callbacks**: Entry points, CLI commands, or framework-specific callbacks
- **String-based invocation**: Functions referenced by name strings
Always review the results and verify before removing any function!
## GitHub Actions Integration
### Basic Workflow
Create `.github/workflows/check-unused-functions.yml`:
```yaml
name: Check Unused Functions
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install pyan-unused-functions
run: pip install pyan-unused-functions
- name: Check for unused functions
run: pyan-unused-functions .
```
### Advanced Workflow with Failure on Unused Functions
```yaml
name: Code Quality Check
on: [push, pull_request]
jobs:
check-unused-functions:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install pyan-unused-functions
run: pip install pyan-unused-functions
- name: Analyze codebase
id: analyze
run: |
OUTPUT=$(pyan-unused-functions . 2>&1)
echo "$OUTPUT"
echo "$OUTPUT" | grep -q "Potentially unused functions: 0" || exit 1
continue-on-error: false
- name: Comment on PR (if unused functions found)
if: failure() && github.event_name == 'pull_request'
uses: actions/github-script@v6
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '⚠️ Unused functions detected! Please review the workflow logs.'
})
```
### Multi-Project Workflow
```yaml
name: Check Multiple Projects
on: [push]
jobs:
analyze:
runs-on: ubuntu-latest
strategy:
matrix:
directory: ['./backend', './frontend-utils', './scripts']
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install pyan-unused-functions
run: pip install pyan-unused-functions
- name: Check ${{ matrix.directory }}
run: pyan-unused-functions ${{ matrix.directory }}
```
> 📖 **More Examples**: See [`examples/`](examples/) for more GitHub Actions workflows including:
> - Strict mode (fail on unused functions)
> - Scheduled weekly checks with issue creation
> - Multi-project/monorepo setups
> - Pre-commit Git hooks
## Configuration
The tool automatically skips common directories:
- `.venv`, `venv` (virtual environments)
- `__pycache__` (Python cache)
- `.git` (version control)
- `node_modules` (JavaScript dependencies)
- `.pytest_cache` (pytest cache)
## CI/CD Best Practices
### Recommended Usage
- **Pre-commit hooks**: Run as a pre-commit check
- **Pull request checks**: Automatically analyze PRs
- **Scheduled scans**: Weekly cron jobs to catch accumulating unused code
- **Release gates**: Ensure no unused functions before releases
### Exit Codes
The tool returns:
- `0` - Success (analysis completed)
- `1` - Error (invalid path, no files found, etc.)
Note: The tool doesn't fail on finding unused functions by default. Wrap with custom logic to enforce policies.
## Development
### Setup Development Environment
```bash
git clone https://github.com/yourusername/pyan-unused-functions.git
cd pyan-unused-functions
pip install -e .
```
### Build Package
```bash
python -m build
```
### Local Testing
```bash
# Test on your own codebase
pyan-unused-functions ./your-project
# Test on current directory
pyan-unused-functions .
```
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
## Documentation
- **[CLI Usage Guide](CLI_GUIDE.md)** - Complete command-line reference
- **[Examples Directory](examples/)** - Ready-to-use GitHub Actions workflows and Git hooks
- **[Publishing Guide](PUBLISHING.md)** - How to publish to PyPI
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Changelog
### Version 0.1.0 (Initial Release)
- Basic unused function detection
- AST-based parsing
- Command-line interface
- Class method support
- Async function support
## Author
mhs - mohammedhs404@gmail.com
## Acknowledgments
- Built with Python's `ast` module
- Inspired by the need for better code quality tools
Raw data
{
"_id": null,
"home_page": "https://github.com/yourusername/pyan-unused-functions",
"name": "pyan-unused-functions",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": null,
"keywords": "static-analysis, code-quality, unused-code, linter, ast, dead-code, code-cleanup, ci-cd, github-actions, cli-tool, python-analysis, code-maintenance",
"author": "Your Name",
"author_email": "mhs <mohammedhs404@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/6d/ba/fbc5498150790e602a5415db558c5cdd83b8b4b932021181d58108c79303/pyan_unused_functions-0.1.2.tar.gz",
"platform": null,
"description": "# pyan-unused-functions\r\n\r\nA Python static analysis tool to find unused functions in your codebase using AST (Abstract Syntax Tree) parsing. Perfect for CLI usage and CI/CD pipelines with GitHub Actions.\r\n\r\n## Features\r\n\r\n- \ud83d\udd0d **Accurate Detection**: Uses Python's built-in AST module for reliable parsing\r\n- \ud83d\ude80 **Fast Analysis**: Efficiently scans entire codebases\r\n- \ud83d\udcca **Detailed Reports**: Shows all defined functions and their usage\r\n- \ud83c\udfaf **Smart Filtering**: Automatically skips private functions (starting with `_`)\r\n- \ud83d\udd04 **Class-Aware**: Handles both module-level functions and class methods\r\n- \u26a1 **Async Support**: Recognizes async functions and methods\r\n- \ud83e\udd16 **CI/CD Ready**: Easy integration with GitHub Actions and other CI systems\r\n- \ud83d\udee0\ufe0f **Lightweight**: Minimal dependencies (requires pyan3 for enhanced analysis)\r\n\r\n## Installation\r\n\r\nInstall from PyPI:\r\n\r\n```bash\r\npip install pyan-unused-functions\r\n```\r\n\r\nThis will automatically install the required dependency: `pyan3==1.1.1`\r\n\r\nOr install from source:\r\n\r\n```bash\r\ngit clone https://github.com/yourusername/pyan-unused-functions.git\r\ncd pyan-unused-functions\r\npip install -e .\r\n```\r\n\r\n## Usage\r\n\r\n> \ud83d\udca1 **Quick Start**: Check the [`examples/`](examples/) directory for ready-to-use GitHub Actions workflows and Git hooks!\r\n\r\n### Command Line\r\n\r\nAnalyze a directory:\r\n\r\n```bash\r\npyan-unused-functions /path/to/your/code\r\n```\r\n\r\nAnalyze current directory:\r\n\r\n```bash\r\npyan-unused-functions .\r\n```\r\n\r\n### As a Python Module\r\n\r\n```python\r\nfrom pathlib import Path\r\nfrom pyan_unused_functions import analyze_codebase, find_unused_functions\r\n\r\n# Analyze a codebase\r\nroot_path = Path(\"./my_project\")\r\ndefined_functions, called_functions = analyze_codebase(root_path)\r\n\r\n# Find unused functions\r\nunused = find_unused_functions(defined_functions, called_functions)\r\n\r\nprint(f\"Found {len(unused)} unused functions:\")\r\nfor func in sorted(unused):\r\n print(f\" {func}\")\r\n```\r\n\r\n## Example Output\r\n\r\n```\r\nAnalyzing Python code in: ./my_project\r\nAnalyzing 45 Python files...\r\n\r\n=== Analysis Results ===\r\nTotal functions defined: 127\r\nTotal function calls found: 98\r\nPotentially unused functions: 12\r\n\r\n=== Potentially Unused Functions ===\r\n module_a.helper_function\r\n module_b.old_implementation\r\n utils.deprecated_method\r\n ...\r\n\r\nNote: This analysis may have false positives for:\r\n - Functions called dynamically (getattr, exec, etc.)\r\n - Functions used in decorators or metaclasses\r\n - Functions called from other modules not analyzed\r\n - Entry points, CLI commands, or framework callbacks\r\n```\r\n\r\n## How It Works\r\n\r\n1. **Discovery**: Recursively finds all Python files in the specified directory\r\n2. **Parsing**: Uses AST to parse each file and extract function definitions and calls\r\n3. **Analysis**: Compares defined functions against called functions\r\n4. **Reporting**: Identifies functions that are defined but never called\r\n\r\n## Limitations\r\n\r\nThis tool provides **static analysis** and may report false positives in the following cases:\r\n\r\n- **Dynamic calls**: Functions invoked via `getattr()`, `exec()`, `eval()`, etc.\r\n- **Decorator usage**: Functions used as decorators or in metaclasses\r\n- **External calls**: Functions called from modules outside the analyzed directory\r\n- **Framework callbacks**: Entry points, CLI commands, or framework-specific callbacks\r\n- **String-based invocation**: Functions referenced by name strings\r\n\r\nAlways review the results and verify before removing any function!\r\n\r\n## GitHub Actions Integration\r\n\r\n### Basic Workflow\r\n\r\nCreate `.github/workflows/check-unused-functions.yml`:\r\n\r\n```yaml\r\nname: Check Unused Functions\r\n\r\non:\r\n push:\r\n branches: [ main, develop ]\r\n pull_request:\r\n branches: [ main ]\r\n\r\njobs:\r\n analyze:\r\n runs-on: ubuntu-latest\r\n steps:\r\n - uses: actions/checkout@v3\r\n \r\n - name: Set up Python\r\n uses: actions/setup-python@v4\r\n with:\r\n python-version: '3.11'\r\n \r\n - name: Install pyan-unused-functions\r\n run: pip install pyan-unused-functions\r\n \r\n - name: Check for unused functions\r\n run: pyan-unused-functions .\r\n```\r\n\r\n### Advanced Workflow with Failure on Unused Functions\r\n\r\n```yaml\r\nname: Code Quality Check\r\n\r\non: [push, pull_request]\r\n\r\njobs:\r\n check-unused-functions:\r\n runs-on: ubuntu-latest\r\n steps:\r\n - uses: actions/checkout@v3\r\n \r\n - name: Set up Python\r\n uses: actions/setup-python@v4\r\n with:\r\n python-version: '3.11'\r\n \r\n - name: Install pyan-unused-functions\r\n run: pip install pyan-unused-functions\r\n \r\n - name: Analyze codebase\r\n id: analyze\r\n run: |\r\n OUTPUT=$(pyan-unused-functions . 2>&1)\r\n echo \"$OUTPUT\"\r\n echo \"$OUTPUT\" | grep -q \"Potentially unused functions: 0\" || exit 1\r\n continue-on-error: false\r\n \r\n - name: Comment on PR (if unused functions found)\r\n if: failure() && github.event_name == 'pull_request'\r\n uses: actions/github-script@v6\r\n with:\r\n script: |\r\n github.rest.issues.createComment({\r\n issue_number: context.issue.number,\r\n owner: context.repo.owner,\r\n repo: context.repo.repo,\r\n body: '\u26a0\ufe0f Unused functions detected! Please review the workflow logs.'\r\n })\r\n```\r\n\r\n### Multi-Project Workflow\r\n\r\n```yaml\r\nname: Check Multiple Projects\r\n\r\non: [push]\r\n\r\njobs:\r\n analyze:\r\n runs-on: ubuntu-latest\r\n strategy:\r\n matrix:\r\n directory: ['./backend', './frontend-utils', './scripts']\r\n steps:\r\n - uses: actions/checkout@v3\r\n \r\n - name: Set up Python\r\n uses: actions/setup-python@v4\r\n with:\r\n python-version: '3.11'\r\n \r\n - name: Install pyan-unused-functions\r\n run: pip install pyan-unused-functions\r\n \r\n - name: Check ${{ matrix.directory }}\r\n run: pyan-unused-functions ${{ matrix.directory }}\r\n```\r\n\r\n> \ud83d\udcd6 **More Examples**: See [`examples/`](examples/) for more GitHub Actions workflows including:\r\n> - Strict mode (fail on unused functions)\r\n> - Scheduled weekly checks with issue creation\r\n> - Multi-project/monorepo setups\r\n> - Pre-commit Git hooks\r\n\r\n## Configuration\r\n\r\nThe tool automatically skips common directories:\r\n- `.venv`, `venv` (virtual environments)\r\n- `__pycache__` (Python cache)\r\n- `.git` (version control)\r\n- `node_modules` (JavaScript dependencies)\r\n- `.pytest_cache` (pytest cache)\r\n\r\n## CI/CD Best Practices\r\n\r\n### Recommended Usage\r\n\r\n- **Pre-commit hooks**: Run as a pre-commit check\r\n- **Pull request checks**: Automatically analyze PRs\r\n- **Scheduled scans**: Weekly cron jobs to catch accumulating unused code\r\n- **Release gates**: Ensure no unused functions before releases\r\n\r\n### Exit Codes\r\n\r\nThe tool returns:\r\n- `0` - Success (analysis completed)\r\n- `1` - Error (invalid path, no files found, etc.)\r\n\r\nNote: The tool doesn't fail on finding unused functions by default. Wrap with custom logic to enforce policies.\r\n\r\n## Development\r\n\r\n### Setup Development Environment\r\n\r\n```bash\r\ngit clone https://github.com/yourusername/pyan-unused-functions.git\r\ncd pyan-unused-functions\r\npip install -e .\r\n```\r\n\r\n### Build Package\r\n\r\n```bash\r\npython -m build\r\n```\r\n\r\n### Local Testing\r\n\r\n```bash\r\n# Test on your own codebase\r\npyan-unused-functions ./your-project\r\n\r\n# Test on current directory\r\npyan-unused-functions .\r\n```\r\n\r\n## Contributing\r\n\r\nContributions are welcome! Please feel free to submit a Pull Request.\r\n\r\n1. Fork the repository\r\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\r\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\r\n4. Push to the branch (`git push origin feature/amazing-feature`)\r\n5. Open a Pull Request\r\n\r\n## Documentation\r\n\r\n- **[CLI Usage Guide](CLI_GUIDE.md)** - Complete command-line reference\r\n- **[Examples Directory](examples/)** - Ready-to-use GitHub Actions workflows and Git hooks\r\n- **[Publishing Guide](PUBLISHING.md)** - How to publish to PyPI\r\n\r\n## License\r\n\r\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\r\n\r\n## Changelog\r\n\r\n### Version 0.1.0 (Initial Release)\r\n\r\n- Basic unused function detection\r\n- AST-based parsing\r\n- Command-line interface\r\n- Class method support\r\n- Async function support\r\n\r\n## Author\r\n\r\nmhs - mohammedhs404@gmail.com\r\n\r\n## Acknowledgments\r\n\r\n- Built with Python's `ast` module\r\n- Inspired by the need for better code quality tools\r\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Find unused functions in Python codebases - perfect for CLI usage and CI/CD pipelines",
"version": "0.1.2",
"project_urls": {
"Bug Tracker": "https://github.com/MohammedHS404/pyan-unused-functions/issues",
"Homepage": "https://github.com/MohammedHS404/pyan-unused-functions"
},
"split_keywords": [
"static-analysis",
" code-quality",
" unused-code",
" linter",
" ast",
" dead-code",
" code-cleanup",
" ci-cd",
" github-actions",
" cli-tool",
" python-analysis",
" code-maintenance"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "eb34fbc6eb73a7165c41a6a51e82a30d2d3c0d1c6bb97a6e954d488374cc0a56",
"md5": "4a71caf854b2f1d258ef61e1fe0a6c22",
"sha256": "0dddcd1e33a989683a7f4b82ceb2a512d85c497fdbeaced62931ae8a175d4552"
},
"downloads": -1,
"filename": "pyan_unused_functions-0.1.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "4a71caf854b2f1d258ef61e1fe0a6c22",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 10093,
"upload_time": "2025-10-25T03:25:00",
"upload_time_iso_8601": "2025-10-25T03:25:00.110447Z",
"url": "https://files.pythonhosted.org/packages/eb/34/fbc6eb73a7165c41a6a51e82a30d2d3c0d1c6bb97a6e954d488374cc0a56/pyan_unused_functions-0.1.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "6dbafbc5498150790e602a5415db558c5cdd83b8b4b932021181d58108c79303",
"md5": "65ef72b2c35ce58fcd8a879c8c422c53",
"sha256": "c5b6ee7ad3150c6b5aa308d5e14fba31085694e107a5a7eb04360bf62dff793c"
},
"downloads": -1,
"filename": "pyan_unused_functions-0.1.2.tar.gz",
"has_sig": false,
"md5_digest": "65ef72b2c35ce58fcd8a879c8c422c53",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 9327,
"upload_time": "2025-10-25T03:25:01",
"upload_time_iso_8601": "2025-10-25T03:25:01.462636Z",
"url": "https://files.pythonhosted.org/packages/6d/ba/fbc5498150790e602a5415db558c5cdd83b8b4b932021181d58108c79303/pyan_unused_functions-0.1.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-25 03:25:01",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "yourusername",
"github_project": "pyan-unused-functions",
"github_not_found": true,
"lcname": "pyan-unused-functions"
}