{"library":"pyhanko","title":"PyHanko","description":"PyHanko is a Python library designed for stamping and digitally signing PDF files, offering extensive functionality for handling digital signatures, including support for various PAdES profiles and cryptographic operations. It is actively maintained with frequent minor releases, currently at version 0.34.1, and aims to cover the digital signing features of the PDF standard comprehensively.","language":"python","status":"active","last_verified":"Wed May 20","install":{"commands":["pip install 'pyHanko[pkcs11,image-support,opentype,qr]' pyhanko-cli","pip install pyhanko"],"cli":{"name":"pyhanko","version":"pyHanko, version 0.35.1 (CLI 0.4.0)"}},"imports":["from pyhanko.pdf_utils.incremental_writer import IncrementalPdfFileWriter","from pyhanko.sign.signers import SimpleSigner","from pyhanko.sign.signers import PdfSignatureMetadata","from pyhanko.sign.signers import PdfSigner","from pyhanko.sign.signers import sign_pdf","from pyhanko.sign.timestamps import HTTPTimeStamper","import pyhanko_certvalidator"],"auth":{"required":false,"env_vars":[]},"quickstart":{"code":"import io\nimport os\n\nfrom pyhanko.pdf_utils.incremental_writer import IncrementalPdfFileWriter\nfrom pyhanko.sign import signers\n\ndef sign_document_example(input_path, output_path, key_path, cert_path, ca_chain_path=None, key_passphrase=None):\n    # Create dummy key and cert files for runnable example\n    with open('dummy_key.pem', 'w') as f: f.write('-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----') # Placeholder\n    with open('dummy_cert.pem', 'w') as f: f.write('-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----') # Placeholder\n    if ca_chain_path: # Create dummy CA chain if path provided\n        with open('dummy_ca_chain.pem', 'w') as f: f.write('-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----') # Placeholder\n\n    # In a real scenario, replace 'dummy_key.pem' and 'dummy_cert.pem'\n    # with paths to your actual signer key and certificate.\n    # key_passphrase should be bytes, e.g., b'your_password'\n\n    # Load the signer key and certificate\n    cms_signer = signers.SimpleSigner.load(\n        key_path or 'dummy_key.pem',\n        cert_path or 'dummy_cert.pem',\n        ca_chain_files=(ca_chain_path or 'dummy_ca_chain.pem',) if ca_chain_path else None,\n        key_passphrase=key_passphrase\n    )\n\n    with open(input_path, 'rb') as doc_input:\n        w = IncrementalPdfFileWriter(doc_input)\n        out = signers.sign_pdf(\n            w,\n            signers.PdfSignatureMetadata(field_name='Signature1'), # Use an existing field or 'Signature1' will be created\n            signer=cms_signer,\n        )\n\n        with open(output_path, 'wb') as doc_output:\n            doc_output.write(out.read())\n\n    print(f\"Document signed: {output_path}\")\n\n# Example usage (requires a dummy PDF and actual key/cert files in a real scenario)\n# You can create a dummy PDF file like 'input.pdf' for testing.\n# Replace 'your_key.pem', 'your_cert.pem', 'your_ca_chain.pem' with actual paths.\n# To run this example, ensure you have a 'input.pdf' file.\n# And replace the '...'(s) with actual PEM contents from your test certificates if you want to run it end to end.\n# try:\n#     # Create a minimal dummy PDF for testing if it doesn't exist\n#     if not os.path.exists('input.pdf'):\n#         from PyPDF2 import PdfWriter\n#         writer = PdfWriter()\n#         writer.add_blank_page(width=72, height=72)\n#         with open('input.pdf', 'wb') as f: writer.write(f)\n#\n#     sign_document_example(\n#         input_path='input.pdf',\n#         output_path='signed_output.pdf',\n#         key_path=os.environ.get('PYHANKO_SIGNER_KEY_PATH', 'dummy_key.pem'),\n#         cert_path=os.environ.get('PYHANKO_SIGNER_CERT_PATH', 'dummy_cert.pem'),\n#         ca_chain_path=os.environ.get('PYHANKO_CA_CHAIN_PATH', 'dummy_ca_chain.pem'),\n#         key_passphrase=os.environ.get('PYHANKO_KEY_PASSPHRASE', '').encode('utf-8')\n#     )\n# finally:\n#     # Clean up dummy files\n#     for f in ['dummy_key.pem', 'dummy_cert.pem', 'dummy_ca_chain.pem']:\n#         if os.path.exists(f): os.remove(f)\n","lang":"python","description":"This quickstart demonstrates how to digitally sign a PDF document using `pyhanko` with a simple signer. It covers loading the signing key and certificate, applying a signature to a PDF, and saving the output. For a real application, you would replace the dummy key/cert paths with your actual cryptographic materials.","tag":null,"tag_description":null,"last_tested":"2026-04-25","results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]},"compatibility":{"tag":null,"tag_description":null,"last_tested":"2026-05-20","installed_version":"0.32.0","pypi_latest":"0.35.1","is_stale":true,"summary":{"python_range":"3.10–3.9","success_rate":100,"avg_install_s":5.6,"avg_import_s":1.45,"wheel_type":"wheel"},"results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"pkcs11,image-support,opentype,qr","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":1.21,"mem_mb":18,"disk_size":"116.3M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"pkcs11,image-support,opentype,qr","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":1.18,"mem_mb":17.8,"disk_size":"115.0M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"pyhanko","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":1.21,"mem_mb":18,"disk_size":"59.4M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"pyhanko","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":1.2,"mem_mb":17.7,"disk_size":"58.3M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"pkcs11,image-support,opentype,qr","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":7.4,"import_time_s":0.85,"mem_mb":19.3,"disk_size":"119M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"pkcs11,image-support,opentype,qr","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.81,"mem_mb":17.7,"disk_size":"117M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"pyhanko","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":4.5,"import_time_s":0.92,"mem_mb":19.3,"disk_size":"60M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"pyhanko","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.82,"mem_mb":17.7,"disk_size":"59M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"pkcs11,image-support,opentype,qr","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":1.67,"mem_mb":21.1,"disk_size":"123.8M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"pkcs11,image-support,opentype,qr","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":1.87,"mem_mb":20.8,"disk_size":"122.5M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"pyhanko","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":1.75,"mem_mb":21.1,"disk_size":"63.2M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"pyhanko","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":1.88,"mem_mb":20.8,"disk_size":"62.1M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"pkcs11,image-support,opentype,qr","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":6.5,"import_time_s":1.51,"mem_mb":21.1,"disk_size":"127M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"pkcs11,image-support,opentype,qr","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":1.51,"mem_mb":20.8,"disk_size":"125M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"pyhanko","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":4.2,"import_time_s":1.5,"mem_mb":21.1,"disk_size":"64M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"pyhanko","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":1.48,"mem_mb":20.8,"disk_size":"63M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"pkcs11,image-support,opentype,qr","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":1.74,"mem_mb":20.5,"disk_size":"114.6M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"pkcs11,image-support,opentype,qr","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":1.86,"mem_mb":20.2,"disk_size":"113.3M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"pyhanko","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":1.7,"mem_mb":20.5,"disk_size":"54.8M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"pyhanko","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":1.87,"mem_mb":20.2,"disk_size":"53.7M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"pkcs11,image-support,opentype,qr","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":6,"import_time_s":1.76,"mem_mb":20.5,"disk_size":"117M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"pkcs11,image-support,opentype,qr","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":1.82,"mem_mb":20.2,"disk_size":"116M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"pyhanko","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":3.6,"import_time_s":1.72,"mem_mb":20.5,"disk_size":"56M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"pyhanko","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":1.95,"mem_mb":20.2,"disk_size":"55M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"pkcs11,image-support,opentype,qr","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":1.66,"mem_mb":21.5,"disk_size":"114.3M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"pkcs11,image-support,opentype,qr","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":1.69,"mem_mb":21.2,"disk_size":"112.9M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"pyhanko","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":1.64,"mem_mb":21.5,"disk_size":"54.5M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"pyhanko","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":1.65,"mem_mb":21.2,"disk_size":"53.3M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"pkcs11,image-support,opentype,qr","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":6,"import_time_s":1.64,"mem_mb":21.5,"disk_size":"117M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"pkcs11,image-support,opentype,qr","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":1.74,"mem_mb":21.2,"disk_size":"115M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"pyhanko","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":3.8,"import_time_s":1.65,"mem_mb":21.5,"disk_size":"56M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"pyhanko","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":1.84,"mem_mb":21.2,"disk_size":"54M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"pkcs11,image-support,opentype,qr","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":1.14,"mem_mb":17.9,"disk_size":"113.4M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"pkcs11,image-support,opentype,qr","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":1.15,"mem_mb":17.7,"disk_size":"112.3M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"pyhanko","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":1.13,"mem_mb":17.9,"disk_size":"59.4M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"pyhanko","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":1.15,"mem_mb":17.7,"disk_size":"58.3M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"pkcs11,image-support,opentype,qr","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":8.9,"import_time_s":1.09,"mem_mb":17.9,"disk_size":"116M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"pkcs11,image-support,opentype,qr","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.99,"mem_mb":17.7,"disk_size":"115M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"pyhanko","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":5.5,"import_time_s":1.08,"mem_mb":17.9,"disk_size":"60M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"pyhanko","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":1.02,"mem_mb":17.7,"disk_size":"59M"}]}}