Skip to main content

A Python static analysis tool that detects heavy initialization inside AWS Lambda handlers that should be moved to module scope for faster warm starts.

Project description

pythaw

PyPI version Python versions License CI

日本語ドキュメント

A Python static analysis tool that detects heavy initialization inside AWS Lambda handlers that should be moved to module scope for faster warm starts.

Recursively follows function calls—including across imported files—to catch indirect violations.

Requirements

Python 3.10 - 3.14 — matching the actively supported AWS Lambda Python runtimes.

Install

# pip
pip install pythaw

# uv
uv add pythaw

Quick Start

# handler.py

def lambda_handler(event, context):
    # BAD: Creating a boto3 client inside the handler
    #      runs initialization on every invocation,
    #      losing the benefit of warm starts.
    client = boto3.client("s3")
    return client.get_object(Bucket="my-bucket", Key=event["key"])
$ pythaw check handler.py
infra/aws.py:7:15: PW001 boto3.client() should be called at module scope
  → handler.py:5:11 process()
    → service.py:5:13 S3Provider.get_client()

Found 1 violation in 1 file.

Move the client to module scope so Lambda container reuse skips the initialization:

# handler.py (fixed)

client = boto3.client("s3")

def lambda_handler(event, context):
    return client.get_object(Bucket="my-bucket", Key=event["key"])
$ pythaw check handler.py
All checks passed!

Usage

pythaw check <path>                    # Check a file or directory
pythaw check . --format json           # JSON output
pythaw check . --format github         # GitHub Actions annotation format
pythaw check . --format sarif          # SARIF format (Code Scanning integration)
pythaw check . --select PW001,PW002    # Enable only specific rules
pythaw check . --ignore PW003          # Disable specific rules
pythaw check . --exit-zero             # Always exit with code 0
pythaw check . --statistics            # Show per-rule violation counts
pythaw rules                           # List built-in rules
pythaw rule PW001                      # Show rule details

Exit Codes

Code Meaning
0 No violations found
1 Violations found
2 Tool error (invalid config, etc.)

Rules

ID Detects
PW001 boto3.client()
PW002 boto3.resource()
PW003 boto3.Session()
PW004 pymysql.connect()
PW005 psycopg2.connect()
PW006 redis.Redis()
PW007 redis.StrictRedis()
PW008 httpx.Client()
PW009 requests.Session()

Call Graph Traversal

pythaw recursively follows local function calls and imported modules from the handler, detecting indirect violations across files.

Supported patterns

Pattern Example
Same-file function call helper()
Module-qualified function call infra.get_client()
Class method call AwsProvider.get_client()
Class instantiation (__init__) S3Client()
Cross-file import tracking from infra import get_client

Note: Instance method calls via variables (e.g. obj = Cls(); obj.method()) are not tracked — this would require data-flow analysis beyond the current scope.

infra/aws.py:4:15: PW001 boto3.client() should be called at module scope
  → handler.py:2:10 get_client()

Found 1 violation in 1 file.

Suppression

Inline suppression

Append # nopw: <code> to a line to suppress that violation. Multiple codes can be comma-separated.

client = boto3.client("s3")  # nopw: PW001

This also works on wrapper function calls — violations found recursively through the call are suppressed:

client = make_client()  # nopw: PW001

File-level suppression

Add # pythaw: nocheck in the leading comment block to skip the entire file.

# pythaw: nocheck
import boto3

def handler(event, context):
    boto3.client("s3")  # not checked

Configuration

Configure via the [tool.pythaw] section in pyproject.toml.

[tool.pythaw]
# Function name patterns recognized as handlers (fnmatch syntax)
handler_patterns = ["handler", "lambda_handler", "*_handler"]

# Patterns to exclude from scanning
exclude = [".venv", "tests"]

# Disable specific rules per file pattern
[tool.pythaw.per-file-ignores]
"tests/*" = ["PW001", "PW002"]
"scripts/*" = ["PW001"]

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pythaw-0.3.0.tar.gz (16.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pythaw-0.3.0-py3-none-any.whl (27.4 kB view details)

Uploaded Python 3

File details

Details for the file pythaw-0.3.0.tar.gz.

File metadata

  • Download URL: pythaw-0.3.0.tar.gz
  • Upload date:
  • Size: 16.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for pythaw-0.3.0.tar.gz
Algorithm Hash digest
SHA256 ed9b2d2bcf42b61750624f9fd666e38128206d78c718b4fc5d02d26643e2887b
MD5 597d87ad9b80fa9d73ea7bf7a3954ac8
BLAKE2b-256 c3a35db2c267ba52753761090d0c34f578a8a0fa087630436f50fda86c37c772

See more details on using hashes here.

File details

Details for the file pythaw-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: pythaw-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 27.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for pythaw-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 eb1cfc780e7bf4eb8e4607042a3d8e33c13bf54b23d77987c67a1d3e14f04840
MD5 6d14512717658d4f31259d95b4fa9ec5
BLAKE2b-256 5999288ca6d4133646db50e2214f273c65fbb1d0775fd0ea93ba40b9432f926a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page