{"id":6803,"library":"pykeepass","title":"PyKeePass","description":"PyKeePass is a Python library that enables interaction with KeePass databases, supporting both KDBX3 and KDBX4 formats. It allows users to read, create, update, and save entries and groups within a KeePass file. The library is actively maintained with frequent releases, typically every few months.","status":"active","version":"4.1.1.post1","language":"en","source_language":"en","source_url":"https://github.com/libkeepass/pykeepass","tags":["keepass","password manager","security","kdbx","database"],"install":[{"cmd":"pip install pykeepass","lang":"bash","label":"Install PyKeePass"}],"dependencies":[{"reason":"Cryptography operations for KeePass database encryption/decryption.","package":"pycryptodome","optional":false},{"reason":"XML parsing and manipulation of the KeePass database structure.","package":"lxml","optional":false}],"imports":[{"symbol":"PyKeePass","correct":"from pykeepass import PyKeePass"}],"quickstart":{"code":"import os\nfrom pykeepass import PyKeePass, create_database\n\nDB_PATH = 'my_database.kdbx'\nMASTER_PASSWORD = os.environ.get('KEEPASS_MASTER_PASSWORD', 'supersecurepassword')\n\n# Create a new KeePass database\nif not os.path.exists(DB_PATH):\n    print(f\"Creating new database at {DB_PATH}\")\n    kp = create_database(filename=DB_PATH, password=MASTER_PASSWORD)\n    # Add a root group if it doesn't exist (create_database usually handles this)\n    # kp.add_group(kp.root_group, 'General')\n    kp.save()\n\n# Open an existing KeePass database\nprint(f\"Opening database: {DB_PATH}\")\nkp = PyKeePass(DB_PATH, password=MASTER_PASSWORD)\n\n# Add a new entry if it doesn't exist\nif not kp.find_entries(title='Example Entry', first=True):\n    print(\"Adding new entry: 'Example Entry'\")\n    # The path argument should be a list of strings for group hierarchy (v4.0.0+)\n    entry = kp.add_entry(kp.root_group, 'Example Entry', 'testuser', 'entry_password_123', notes='This is a test entry.')\n    print(f\"Added entry: {entry.title} ({entry.username})\")\nelse:\n    print(\"Entry 'Example Entry' already exists.\")\n\n# Find an entry and retrieve its password\nentry = kp.find_entries(title='Example Entry', first=True) # Use first=True for a single entry\nif entry:\n    print(f\"Found entry '{entry.title}'. Username: {entry.username}, Password: {entry.password}\")\n    # Update an entry\n    entry.notes = 'Updated notes for the test entry.'\n    entry.tags = ['web', 'test']\n    print(f\"Entry notes updated: {entry.notes}\")\n    print(f\"Entry tags updated: {entry.tags}\")\nelse:\n    print(\"Entry 'Example Entry' not found.\")\n\n# Save changes to the database\nkp.save()\nprint(\"Database saved successfully.\")\n\n# Clean up (optional)\n# os.remove(DB_PATH)\n# print(f\"Cleaned up: Removed {DB_PATH}\")\n","lang":"python","description":"This quickstart demonstrates how to create a new KeePass database, open an existing one, add a new entry, find an entry by its title, retrieve its credentials, update its properties, and save the changes. Ensure you set the `KEEPASS_MASTER_PASSWORD` environment variable or replace the placeholder password."},"warnings":[{"fix":"Update string path arguments to be lists of path components. For example, `kp.find_groups(path='social')` becomes `kp.find_groups(path=['social'])`.","message":"Starting with version 4.0.0, path arguments for methods like `find_groups`, `find_entries`, `add_group`, and `add_entry` changed from a single string (e.g., 'Group/Subgroup') to a list of strings representing the hierarchical components (e.g., ['Group', 'Subgroup']).","severity":"breaking","affected_versions":">=4.0.0"},{"fix":"When expecting a single result, use the `first=True` argument (e.g., `kp.find_entries(title='MyEntry', first=True)`) or explicitly access the first element of the returned list (e.g., `kp.find_entries(title='MyEntry')[0]`).","message":"Methods like `find_entries()` and `find_groups()` return a *list* of matching objects by default, even if only one item matches. Directly accessing attributes (e.g., `entry.password`) on the result without specifying `first=True` or indexing the list (`[0]`) will result in an `AttributeError`.","severity":"gotcha","affected_versions":"All"},{"fix":"Review logic that checks the `Entry.tags` property for `None` and update it to correctly handle an empty list as an indication of no tags.","message":"As of version 4.1.0, the `Entry.tags` property now returns an empty list `[]` when an entry has no tags defined, instead of `None`. Code that checks for `if entry.tags is None:` might need adjustment to `if not entry.tags:` or `if len(entry.tags) == 0:`.","severity":"behavioral","affected_versions":">=4.1.0"}],"env_vars":null,"last_verified":"2026-04-15T00:00:00.000Z","next_check":"2026-07-14T00:00:00.000Z","problems":[]}