Package: pykeepass
This library allows you to write entries to a KeePass database.Come chat at#pykeepasson Freenode or#pykeepass:matrix.orgon Matrix.Installationsudo apt install python3-lxml
pip install pykeepassExamplefrompykeepassimportPyKeePass# load database>>>kp=PyKeePass('db.kdbx',password='somePassw0rd')# find any group by its name>>>group=kp.find_groups(name='social',first=True)# get the entries in a group>>>group.entries[Entry:"social/facebook (myusername)",Entry:"social/twitter (myusername)"]# find any entry by its title>>>entry=kp.find_entries(title='facebook',first=True)# retrieve the associated password>>>entry.password's3cure_p455w0rd'# update an entry>>>entry.notes='primary facebook account'# create a new group>>>group=kp.add_group(kp.root_group,'email')# create a new entry>>>kp.add_entry(group,'gmail','myusername','myPassw0rdXX')Entry:"email/gmail (myusername)"# save database>>>kp.save()Finding Entriesfind_entries(title=None, username=None, password=None, url=None, notes=None, otp=None, path=None, uuid=None, tags=None, string=None, group=None, recursive=True, regex=False, flags=None, history=False, first=False)Returns entries which match all provided parameters, wheretitle,username,password,url,notes,otp,autotype_windowandautotype_sequenceare strings,pathis a list,stringis a dict,autotype_enabledis a boolean,uuidis auuid.UUIDandtagsis a list of strings.  This function has optionalregexboolean andflagsstring arguments, which means to interpret search strings asXSLT styleregular expressions withflags.Thepathlist is a full path to an entry (ex.['foobar_group', 'foobar_entry']).  This impliesfirst=True.  All other arguments are ignored when this is given.  This is useful for handling user input.Thestringdict allows for searching custom string fields.  ex.{'custom_field1': 'custom value', 'custom_field2': 'custom value'}Thegroupargument determines whatGroupto search under, and therecursiveboolean controls whether to search recursively.Thehistory(defaultFalse) boolean controls whether history entries should be included in the search results.Thefirst(defaultFalse) boolean controls whether to return the first matched item, or a list of matched items.iffirst=False, the function returns a list ofEntrys or[]if there are no matchesiffirst=True, the function returns the firstEntrymatch, orNoneif there are no matchesentriesa flattened list of all entries in the database>>>kp.entries[Entry:"foo_entry (myusername)",Entry:"foobar_entry (myusername)",Entry:"social/gmail (myusername)",Entry:"social/facebook (myusername)"]>>>kp.find_entries(title='gmail',first=True)Entry:"social/gmail (myusername)">>>kp.find_entries(title='foo.*',regex=True)[Entry:"foo_entry (myusername)",Entry:"foobar_entry (myusername)"]>>>entry=kp.find_entries(title='foo.*',url='.*facebook.*',regex=True,first=True)>>>entry.url'facebook.com'>>>entry.title'foo_entry'>>>entry.title='hello'>>>group=kp.find_group(name='social',first=True)>>>kp.find_entries(title='facebook',group=group,recursive=False,first=True)Entry:"social/facebook (myusername)">>>entry.otpotpauth://totp/test:lkj?secret=TEST%3D%3D%3D%3D&period=30&digits=6&issuer=testFinding Groupsfind_groups(name=None, path=None, uuid=None, notes=None, group=None, recursive=True, regex=False, flags=None, first=False)wherenameandnotesare strings,pathis a list,uuidis auuid.UUID. This function has optionalregexboolean andflagsstring arguments, which means to interpret search strings asXSLT styleregular expressions withflags.Thepathlist is a full path to a group (ex.['foobar_group', 'sub_group']).  This impliesfirst=True.  All other arguments are ignored when this is given.  This is useful for handling user input.Thegroupargument determines whatGroupto search under, and therecursiveboolean controls whether to search recursively.Thefirst(defaultFalse) boolean controls whether to return the first matched item, or a list of matched items.iffirst=False, the function returns a list ofGroups or[]if there are no matchesiffirst=True, the function returns the firstGroupmatch, orNoneif there are no matchesroot_grouptheRootgroup to the databasegroupsa flattened list of all groups in the database>>>kp.groups[Group:"foo",Group"foobar",Group:"social",Group:"social/foo_subgroup"]>>>kp.find_groups(name='foo',first=True)Group:"foo">>>kp.find_groups(name='foo.*',regex=True)[Group:"foo",Group"foobar"]>>>kp.find_groups(path=['social'],regex=True)[Group:"social",Group:"social/foo_subgroup"]>>>kp.find_groups(name='social',first=True).subgroups[Group:"social/foo_subgroup"]>>>kp.root_groupGroup:"/"Entry Functions and Propertiesadd_entry(destination_group, title, username, password, url=None, notes=None, tags=None, expiry_time=None, icon=None, force_creation=False)delete_entry(entry)trash_entry(entry)move a group to the recycle bin.  The recycle bin is created if it does not exit.entrymust be an empty Entry.move_entry(entry, destination_group)atimeaccess timectimecreation timemtimemodification timewheredestination_groupis aGroupinstance.entryis anEntryinstance.title,username,password,url,notes,tags,iconare strings.expiry_timeis adatetimeinstance.Ifexpiry_timeis a naive datetime object (i.e.expiry_time.tzinfois not set), the timezone is retrieved fromdateutil.tz.gettz().# add a new entry to the Root group>>>kp.add_entry(kp.root_group,'testing','foo_user','passw0rd')Entry:"testing (foo_user)"# add a new entry to the social group>>>group=kp.find_groups(name='social',first=True)>>>entry=kp.add_entry(group,'testing','foo_user','passw0rd')Entry:"testing (foo_user)"# save the database>>>kp.save()# delete an entry>>>kp.delete_entry(entry)# move an entry>>>kp.move_entry(entry,kp.root_group)# save the database>>>kp.save()# change creation time>>>fromdatetimeimportdatetime,timezone>>>entry.ctime=datetime(2023,1,1,tzinfo=timezone.utc)# update modification or access time>>>entry.touch(modify=True)Group Functions and Propertiesadd_group(destination_group, group_name, icon=None, notes=None)delete_group(group)trash_group(group)move a group to the recycle bin.  The recycle bin is created if it does not exit.groupmust be an empty Group.empty_group(group)delete all entries and subgroups of a group.groupis an instance ofGroup.move_group(group, destination_group)atimeaccess timectimecreation timemtimemodification timedestination_groupandgroupare instances ofGroup.group_nameis a string# add a new group to the Root group>>>group=kp.add_group(kp.root_group,'social')# add a new group to the social group>>>group2=kp.add_group(group,'gmail')Group:"social/gmail"# save the database>>>kp.save()# delete a group>>>kp.delete_group(group)# move a group>>>kp.move_group(group2,kp.root_group)# save the database>>>kp.save()# change creation time>>>fromdatetimeimportdatetime,timezone>>>group.ctime=datetime(2023,1,1,tzinfo=timezone.utc)# update modification or access time>>>group.touch(modify=True)AttachmentsIn this section,binaryrefers to the bytes of the attached data (stored at the root level of the database), whileattachmentis a reference to a binary (stored in an entry).  A binary can be referenced by none, one or many attachments.add_binary(data, compressed=True, protected=True)wheredatais bytes.  Adds a blob of data to the database. The attachment reference must still be added to an entry (see below).compressedonly applies to KDBX3 andprotectedonly applies to KDBX4 (no effect if used on wrong database version).  Returns id of attachment.delete_binary(id)whereidis an int.  Removes binary data from the database and deletes any attachments that reference it.  Since attachments reference binaries by their positional index, attachments that reference binaries with id >idwill automatically be decremented.find_attachments(id=None, filename=None, element=None, recursive=True, regex=False, flags=None, history=False, first=False)whereidis an int,filenameis a string, and element is anEntryorGroupto search under.iffirst=False, the function returns a list ofAttachments or[]if there are no matchesiffirst=True, the function returns the firstAttachmentmatch, orNoneif there are no matchesbinarieslist of bytestrings containing binary data.  List index corresponds to attachment idattachmentslist containing allAttachments in the database.Entry.add_attachment(id, filename)whereidis an int andfilenameis a string.  Creates a reference using the given filename to a database binary.  The existence of a binary with the given id is not checked.  ReturnsAttachment.Entry.delete_attachment(attachment)whereattachmentis anAttachment.  Deletes a reference to a database binary.Entry.attachmentslist ofAttachments for this Entry.Attachment.idid of data that this attachment points toAttachment.filenamestring representing this attachmentAttachment.datathe data that this attachment points to.  RaisesBinaryErrorif data does not exist.Attachment.entrythe entry that this attachment is attached to>>>e=kp.add_entry(kp.root_group,title='foo',username='',password='')# add attachment data to the db>>>binary_id=kp.add_binary(b'Hello world')>>>kp.binaries[b'Hello world']# add attachment reference to entry>>>a=e.add_attachment(binary_id,'hello.txt')>>>aAttachment:'hello.txt'->0# access attachments>>>aAttachment:'hello.txt'->0>>>a.id0>>>a.filename'hello.txt'>>>a.datab'Hello world'>>>e.attachments[Attachment:'hello.txt'->0]# list all attachments in the database>>>kp.attachments[Attachment:'hello.txt'->0]# search attachments>>>kp.find_attachments(filename='hello.txt')[Attachment:'hello.txt** -> 0]# delete attachment reference>>>e.delete_attachment(a)# or, delete both attachment reference and binary>>>kp.delete_binary(binary_id**Credential Expirycredchange_datedatetime object with date of last credentials changecredchange_requiredboolean whether database credentials have expired and are required to changecredchange_recommendedboolean whether database credentials have expired and are recommended to changecredchange_required_daysdays aftercredchange_datethat credential update is requiredcredchange_recommended_daysdays aftercredchange_datethat credential update is recommendedMiscellaneousread(filename=None, password=None, keyfile=None, transformed_key=None, decrypt=False)wherefilename,password, andkeyfileare strings (filenameandkeyfilemay also be file-like objects).filenameis the path to the database,passwordis the master password string, andkeyfileis the path to the database keyfile.  At least one ofpasswordandkeyfileis required.  Alternatively, the derived key can be supplied directly throughtransformed_key.decrypttells whether the file should be decrypted or not.Can raiseCredentialsError,HeaderChecksumError, orPayloadChecksumError.reload()reload database from disk using previous credentialssave(filename=None)wherefilenameis the path of the file to save to (filenamemay also be file-like object).  Iffilenameis not given, the path given inreadwill be used.passwordstring containing database password.  Can also be set.  UseNonefor no password.filenamestring containing path to database.  Can also be setkeyfilestring containing path to the database keyfile.  Can also be set.  UseNonefor no keyfile.versiontuple containing database version.  e.g.(3, 1)is a KDBX version 3.1 database.encryption_algorithmstring containing algorithm used to encrypt database.  Possible values areaes256,chacha20, andtwofish.create_database(filename, password=None, keyfile=None, transformed_key=None)create a new database atfilenamewith supplied credentials.  ReturnsPyKeePassobjecttreedatabase lxml treexmlget database XML data as stringdump_xml(filename)pretty print database XML to fileTOTPEntry.otpTOTP URI which can be passed to an OTP library to generate codes# find an entry which has otp attribute>>>e=kp.find_entries(otp='.*',regex=True,first=True)>>>importpyotp>>>pyotp.parse_uri(e.otp).now()799270Tests and DebuggingRun tests withpython tests/tests.pyorpython tests/tests.py SomeSpecificTestEnable debugging when doing tests in console:>>> from pykeepass.pykeepass import debug_setup
>>> debug_setup()
>>> kp.entries[0]
DEBUG:pykeepass.pykeepass:xpath query: //Entry
DEBUG:pykeepass.pykeepass:xpath query: (ancestor::Group)[last()]
DEBUG:pykeepass.pykeepass:xpath query: (ancestor::Group)[last()]
DEBUG:pykeepass.pykeepass:xpath query: String/Key[text()="Title"]/../Value
DEBUG:pykeepass.pykeepass:xpath query: String/Key[text()="UserName"]/../Value
Entry: "root_entry (foobar_user)"