{"library":"python-gnupg","title":"python-gnupg","description":"The `python-gnupg` library provides a Python wrapper for the GNU Privacy Guard (GnuPG or GPG), enabling Python programs to encrypt, decrypt, sign data, verify signatures, and manage GPG keys. It is actively maintained by Vinay Sajip with frequent bug-fix and enhancement releases. The current version is 0.5.6.","status":"active","version":"0.5.6","language":"en","source_language":"en","source_url":"https://github.com/vsajip/python-gnupg","tags":["cryptography","gpg","gnupg","security","encryption","decryption","key management"],"install":[{"cmd":"pip install python-gnupg","lang":"bash","label":"Install with pip"}],"dependencies":[{"reason":"This Python library is a wrapper for the GnuPG command-line tool, which must be installed and accessible on the system PATH.","package":"GnuPG (gpg executable)"}],"imports":[{"note":"The primary class to interact with GnuPG functionality is `GPG`. You typically instantiate it without arguments, or specify `gnupghome`.","symbol":"GPG","correct":"import gnupg\ngpg = gnupg.GPG()"}],"quickstart":{"code":"import gnupg\nimport os\nimport tempfile\nimport shutil\nimport subprocess\n\ndef check_gpg_installed():\n    try:\n        subprocess.run(['gpg', '--version'], check=True, capture_output=True)\n        return True\n    except (subprocess.CalledProcessError, FileNotFoundError):\n        return False\n\nif not check_gpg_installed():\n    print(\"GnuPG (gpg) executable not found. Please install GnuPG first.\")\n    exit(1)\n\n# Create a temporary directory for GnuPG home to avoid interfering with user's keyring\ntry:\n    temp_gnupghome = tempfile.mkdtemp()\n    print(f\"Using temporary GnuPG home: {temp_gnupghome}\")\n\n    gpg = gnupg.GPG(gnupghome=temp_gnupghome)\n    # For GnuPG >= 2.1, passphrases might require 'allow-loopback-pinentry' in gpg-agent.conf\n    # For a quickstart, we generate a key without protection for simplicity if supported by GnuPG version.\n    # However, 'passphrase' is generally required for security.\n    \n    # Generate a key\n    # Note: Real key generation might require sufficient entropy on your system\n    input_data = gpg.gen_key_input(\n        key_type='RSA',\n        key_length=2048,\n        name_real='Test User',\n        name_email='test@example.com',\n        passphrase='mysecretpassword',\n        no_protection=False # Keep True for keys without passphrase, False for password-protected\n    )\n    key = gpg.gen_key(input_data)\n\n    if not key.ok:\n        print(f\"Key generation failed: {key.status} - {key.stderr}\")\n        if \"no_protection\" in key.stderr and \"passphrase\" in key.stderr and gpg.version[0] >= 2:\n            print(\"Hint: For GnuPG >= 2.1, generating keys with an empty passphrase (no_protection=True) or without `allow-loopback-pinentry` might fail. Try providing a passphrase.\")\n        exit(1)\n\n    print(f\"Generated key: {key.fingerprint}\")\n\n    # List keys to confirm\n    public_keys = gpg.list_keys()\n    print(\"Public keys:\")\n    for k in public_keys:\n        print(f\"  {k['keyid']} - {k['uids']}\")\n\n    # Encrypt a message\n    unencrypted_string = \"This is a secret message.\"\n    encrypted_data = gpg.encrypt(\n        unencrypted_string,\n        recipients=[key.fingerprint],\n        always_trust=True  # Use --trust-model always in newer gpg, but always_trust is for this library.\n    )\n\n    if not encrypted_data.ok:\n        print(f\"Encryption failed: {encrypted_data.status} - {encrypted_data.stderr}\")\n        exit(1)\n\n    print(f\"Encrypted message: {encrypted_data.data.decode('utf-8')[:50]}...\")\n\n    # Decrypt the message\n    decrypted_data = gpg.decrypt(\n        encrypted_data.data,\n        passphrase='mysecretpassword'\n    )\n\n    if not decrypted_data.ok:\n        print(f\"Decryption failed: {decrypted_data.status} - {decrypted_data.stderr}\")\n        exit(1)\n\n    print(f\"Decrypted message: {decrypted_data.data.decode('utf-8')}\")\n    assert decrypted_data.data.decode('utf-8') == unencrypted_string\n    print(\"Encryption and decryption successful!\")\n\nfinally:\n    # Clean up the temporary directory\n    if 'temp_gnupghome' in locals() and os.path.exists(temp_gnupghome):\n        print(f\"Cleaning up temporary GnuPG home: {temp_gnupghome}\")\n        shutil.rmtree(temp_gnupghome)\n","lang":"python","description":"This quickstart demonstrates how to initialize `python-gnupg`, generate a new GPG key, encrypt a string using that key, and then decrypt it. It uses a temporary `gnupghome` to avoid affecting your existing GnuPG setup and includes a check for the `gpg` executable. Remember that key generation requires sufficient system entropy, and passphrase handling can be complex with GnuPG versions >= 2.1."},"warnings":[{"fix":"Install GnuPG (e.g., `sudo apt install gnupg` on Debian/Ubuntu, `brew install gnupg` on macOS) or specify the `gpgbinary` path when initializing `gnupg.GPG(gpgbinary='/path/to/gpg')`.","message":"The `gpg` executable must be installed on the system and accessible via the system's PATH. If not found, `python-gnupg` operations will fail with `FileNotFoundError` or similar.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure the user running the Python script has appropriate read/write permissions for the specified `gnupghome` directory. Consider creating a dedicated `gnupghome` for your application with `tempfile.mkdtemp()` for isolated operations, and always clean it up. You can also try setting `ignore_homedir_permissions=True` as a last resort, but use with caution.","message":"GnuPG uses a 'home directory' (`gnupghome`) for keyrings and trust databases. If you don't specify `gnupghome` when initializing `gnupg.GPG`, it will use the GnuPG default (typically `~/.gnupg`). Permissions issues on this directory are common, especially in server environments, leading to `secret key not available` or other access errors.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Continue using `always_trust=True` if you need to bypass trust checks, but understand that the underlying GnuPG command has changed to `--trust-model always`.","message":"The `always_trust=True` parameter in `encrypt` and `verify` methods (which maps to GnuPG's `--always-trust`) was effectively deprecated by GnuPG itself. For GnuPG versions >= 0.5.1, `python-gnupg` now internally uses `--trust-model always` when `always_trust=True` is passed. While the parameter still works, be aware of the underlying change.","severity":"deprecated","affected_versions":"0.5.1 and later"},{"fix":"Add `allow-loopback-pinentry` to `gpg-agent.conf` in your `gnupghome` directory. If the file doesn't exist, create it. Some GnuPG 2.1.x versions may still exhibit issues.","message":"For GnuPG versions >= 2.1, passing passphrases directly via streams (e.g., to `decrypt`) might not work by default. GnuPG 2.1+ often requires `allow-loopback-pinentry` to be added to `gpg-agent.conf` in the GnuPG home directory for programmatic passphrase input. Without this, operations requiring a passphrase may hang or fail.","severity":"gotcha","affected_versions":"GnuPG >= 2.1 (affects `python-gnupg` when interacting with these GnuPG versions)"},{"fix":"After every `gpg` operation, examine the `result.ok` boolean and `result.stderr` string to determine success or failure and get diagnostic messages from GnuPG.","message":"Always check the `ok` attribute and `stderr` of the result object returned by `gnupg` methods (e.g., `gpg.encrypt().ok`, `gpg.decrypt().stderr`). Operations might not raise Python exceptions on GnuPG failures, but instead report errors in the result object's attributes.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Explicitly set the `encoding` parameter when initializing `gnupg.GPG(encoding='utf-8')` if you are working with UTF-8 data, or another appropriate encoding matching your environment and GnuPG setup.","message":"Encoding issues can arise, especially when working with non-ASCII data. `python-gnupg` defaults to `latin-1` for communication with the `gpg` executable. If your data or GnuPG's output uses a different encoding, you might encounter `UnicodeDecodeError` or corrupted output.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-05T00:00:00.000Z","next_check":"2026-07-04T00:00:00.000Z"}